Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor some visitor internals #4447

Merged
merged 7 commits into from
Feb 23, 2024
Merged

Refactor some visitor internals #4447

merged 7 commits into from
Feb 23, 2024

Conversation

asl
Copy link
Contributor

@asl asl commented Feb 22, 2024

This is a first step towards #4418

The particular set of changes includes:

  • Refactor Inspector's visiting tracking to be similar to ChangeTracker of Modifier / Transform. Albeit very similar, there are important differences here and there
  • Fixed subtle iterator invalidation bug in Inspector::apply_visitor. It was not exposed due to way std::unordered_map is implemented in libc++ / libstdc++. Long story short: iterator was kept across possible insertion. It will be invalidated in case of rehash
  • Ensured no internal guts of visiting process is exposed for the purposes of visitOnce / visitAgain. Previously we had a pointer to a field inside map's value stored in Visitor. So we risked a lot to obtain some dangling pointer to freed memory. It worked due to guarantees we had from std::unordered_map, but would stop to work with maps with less strong guarantees. And in general, it looks like an escaping pointer complicating code clarity.
  • Reduced size of Visitor::Context via rearranging fields to reduce alignment padding waste
  • Removed extraneous map lookups from hot code paths

As a result we are having ~5% speedup on P4CParserUnroll.switch_20160512 testcase:

Command Mean [s] Min [s] Max [s] Relative
gtestp4c-baseline --gtest_filter=P4CParserUnroll.switch_20160512 8.620 ± 0.113 8.413 8.749 1.05 ± 0.02
gtestp4c --gtest_filter=P4CParserUnroll.switch_20160512 8.200 ± 0.098 8.059 8.362 1.00

(benchmarking by hyperfine with 10 iterations and warm-up)

@asl asl added the core Topics concerning the core segments of the compiler (frontend, midend, parser) label Feb 22, 2024
@asl asl requested a review from grg February 22, 2024 03:32
@asl asl added the run-sanitizer Use this tag to run a Clang+Sanitzers CI run. label Feb 22, 2024
Copy link
Contributor

@grg grg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No major issues: just a couple of minor comments.

ir/visitor.cpp Outdated
@@ -311,25 +429,23 @@ const IR::Node *Modifier::apply_visitor(const IR::Node *n, const char *name) {
if (ctxt) ctxt->child_name = name;
if (n) {
PushContext local(ctxt, n);
if (visited->busy(n)) {
auto [busy, done] = visited->start(n, visitDagOnce);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the original code, start really was only used when starting processing on a node. Now it has the concept of "get status and start if not already started". Perhaps a name like update / update_status / start_or_status?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was mixed thing actually. There was "implicit" start in Inspector and slightly different thing in Modifier/ Transform. I thought about try_start. But if there are other options, then I'm all for it :)

ir/visitor.cpp Show resolved Hide resolved
@asl
Copy link
Contributor Author

asl commented Feb 22, 2024

@grg Renamed the function. Also it returns more clear status now, not just pair of bools

@asl asl requested a review from grg February 22, 2024 20:39
Copy link
Contributor

@grg grg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. And the new VisitStatus enum is clearer than the pair of bools.

@asl asl enabled auto-merge (squash) February 23, 2024 03:39
@asl asl merged commit 05e2e5d into p4lang:main Feb 23, 2024
16 checks passed
void visitAgain() const { *visitCurrentOnce = false; }
// FIXME: It would be better named visitCurrentOnce() / visitCurrenAgain()
virtual void visitOnce() const { BUG("do not know how to handle request"); }
virtual void visitAgain() const { BUG("do not know how to handle request"); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe delete these here -- make them only in Inspector/Modifier/Transform, and final s well (no need for virtual)

};
typedef std::unordered_map<const IR::Node *, info_t> visited_t;
std::shared_ptr<visited_t> visited;
std::shared_ptr<Tracker> visited;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of having this be an info_t instead of a trscker is tha an Inspector can't change nodes, so only needs to store 2 bits per node visited and not an additional pointer. If you change it to an hvec_map instead of an unordered_map, it would might be possible to make it even more compact.

Copy link
Contributor Author

@asl asl Feb 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See next PRs for further improvements here :) And its 'Tracker', not 'ChangeTracker'. We indeed store only two bools. Though due to alignment requirements it's a bit more depending on the platform.

Copy link
Contributor Author

@asl asl Feb 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And for now I cannot use it due to #4389 as it is not a drop-in replacement for unordered_map

@asl asl deleted the visitor-improve branch February 27, 2024 20:17
grg added a commit that referenced this pull request Apr 11, 2024
Set the done flag to flase when revisiting a node in
Tracker::try_start. Fixes a small regression introduced in #4447.
grg added a commit that referenced this pull request Apr 11, 2024
Set the done flag to false when revisiting a node in
Tracker::try_start. Fixes a small regression introduced in #4447.
grg added a commit that referenced this pull request Apr 11, 2024
Reset the done/visit_in_progress flag when revisiting a node in
Visitor::Tracker::try_start or Visitor::ChangeTracker::try_start.

For inspectors, fixes a small regression introduced in #4447. For
Modifiers/Transforms, fixes a bug that hadn't been previously
encountered. (Bug revealed by test program.)
github-merge-queue bot pushed a commit that referenced this pull request Apr 12, 2024
Reset the done/visit_in_progress flag when revisiting a node in
Visitor::Tracker::try_start or Visitor::ChangeTracker::try_start.

For inspectors, fixes a small regression introduced in #4447. For
Modifiers/Transforms, fixes a bug that hadn't been previously
encountered. (Bug revealed by test program.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Topics concerning the core segments of the compiler (frontend, midend, parser) run-sanitizer Use this tag to run a Clang+Sanitzers CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants