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

[AArch64] Adjust cache location for PC relative branches #7838

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

jim-saxman
Copy link
Contributor

@jim-saxman jim-saxman commented May 12, 2017

AArch64 supports up to +/-128MB PC relative branches with 26-bit
immediates in the B and BL instructions, so make Hot, Prof, Main,
and Cold caches 128MB (total).

No new failures in the 'all' unit test suite, nor in the oss-
performance benchmarking suite. When combined with relocation, it
produces nice gains in oss.

AArch64 supports up to +/-128MB PC relative branches with 26-bit
immediates in the B and BL instructions, so make Hot, Prof, Main,
and Cold caches 128MB (total).

No new failures in the 'all' unit test suite, nor in the oss-
perfomrance benchmarking suite. When combined with relocation, it
produces nice gains in oss.
@jim-saxman
Copy link
Contributor Author

@mxw please review.
@swalk-cavium This patch goes well with relocation, #7661. Care to test it?

@swalk-cavium
Copy link
Contributor

@jim-saxman - Is this branch complete? Or do I have to do the cherry-picking business on top of #7661.

@mxw mxw self-assigned this May 12, 2017
@jim-saxman
Copy link
Contributor Author

@swalk-cavium It has no dependencies against #7661 so it will apply cleanly either way. However you won't see any gains if you don't also have #7661 in your tree.

@swalk-cavium
Copy link
Contributor

@jim-saxman - does this remove the restriction on retranslateAll()?

@jim-saxman
Copy link
Contributor Author

@swalk-cavium No, AFAIK retranslateAll() is still broken on ARM.

@mxw
Copy link
Contributor

mxw commented May 12, 2017

We definitely can't just quit if the code size is too big—some applications might need all that code.

@@ -97,7 +98,14 @@ CodeCache::CodeCache()
exit(1);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mxw I tried to copy to functionality from here. Do you recommend printing the warning and not calling exit(1), or just removing this entire block?

Copy link
Contributor

Choose a reason for hiding this comment

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

That code quits if the code size is too small.

More generally, I don't think we should be altering these defaults on ARM, since your choice of platform isn't going to alter the reality of your codebase's size. We should be looking for ways to optimize in spite of the direct jump size restrictions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I can accept that.

I've found that instead of shrinking the sizes of the various caches to fit within 128MB, I can change the memory mapping to place ACold before AProf. This allows direct jumps from AHot to reach ACold, and keeps the significant gains for OSS-mediawiki (in conjunction with #7661). Would an ARM specific change to the cache's layout be acceptable?

Copy link
Contributor

@mxw mxw May 24, 2017

Choose a reason for hiding this comment

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

Whoa, sorry @jim-saxman; I must have missed the notification (or maybe it got dropped) for this comment.

That seems fine to me, although if the user configures HHVM to have larger code sizes than the defaults (which I suspect we may do internally), then you'll still run into the performance degradation with far jumps. There might be reasons not do to it that I'm not aware of, but if there are, someone will raise them once we see the PR.

cc-ing @dave-estes, @cmuellner, @swalk-cavium also—On the subject of avoiding long jumps: I think the most important thing is for hot and main to be within near jump distance of one another. Jumps to cold and frozen are supposed to be rare, so the cost penalty should be relatively insignificant in practice—though, of course, the far jump is a much bigger instruction sequence, which does still have a passive impact on icache behavior.

One idea we bounced around internally when discussing this issue on ARM was to dynamically allocate blocks of far jump trampolines which were always within a near jump of hot and main. Then, in the code we emit, we can just always emit a near jump, and then proxy through the trampoline if necessary. The static relocator could probably handle this, and it would obviate the dependency on dynamic relocation (though smashable jumps would still require dynamic relocation to shorten them, I'd expect). (Are calls PC-relative and limited in immediate size, also? Even if main itself grew too big, we could partition main into chunks with trampoline areas in between, and the same solution would work if we called across chunks in main.)

This is an area with substantial potential for perf improvement, so I'm interested in hearing other thoughts or ideas on the subject you all might have.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mxw - Hi Max, et.al, In my previous life we called those trampolines branch islands. The linker would create a little table between object files for the case you describe above. Is there an easy way to instrument this an capture some data? It sure seems like most of the jumps are nearby, but that could be an artifact of just looking at small-ish tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mxw Calls can be PC-relative with the BL instruction in which case the range is also +/-128MB, or through a Register using the BLR instructions.

We also have a few branch instructions with smaller immediates:

  • CBZ/CBNZ <Xt>, <label> Compare and branch if register Xt is zero/non-zero to label. They have a +/- 1MB range.

  • TBZ/TBNZ <Xt>, #<imm>, <label> Test bit numbered by imm in register Xt with and branch to label. They have a +/- 32KB range.

@@ -97,7 +98,14 @@ CodeCache::CodeCache()
exit(1);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

That code also exit()'s if code size is > 2GiB due to PC-relatives. Perhaps I marked the wrong exit(1)???

Anyway, I've also found that moving aHot around works well, but I'm afraid to do that since I don't know if __hot_start and __hot_end will be enabled, which could gain from having backward(to lower addresses) PC-relative branches from aHot into the __hot_start--__hot_end native functions.

@swalk-cavium
Copy link
Contributor

@jim-saxman - I think I merged #7661 and this change correctly and ran a MOP
with 6 option sets. No new regressions were detected. I ran it on a Ubuntu 16.04
machine.

@jim-saxman
Copy link
Contributor Author

@swalk-cavium Thanks!

AArch64 supports up to +/-128MB PC relative branches with 26-bit
immediates in the B and BL instructions, so move aHot closer to
the aCold cache.

No new failures in the 'all' unit test suite, nor in the oss-
perfomrance benchmarking suite. When combined with relocation, it
produces nice gains in oss.
@hhvm-bot
Copy link
Contributor

@jim-saxman updated the pull request - view changes

@jim-saxman jim-saxman changed the title [AArch64] Adjust cache sizes for PC relative branches [AArch64] Adjust cache localtion for PC relative branches May 24, 2017
@jim-saxman jim-saxman changed the title [AArch64] Adjust cache localtion for PC relative branches [AArch64] Adjust cache location for PC relative branches May 24, 2017
@jim-saxman
Copy link
Contributor Author

HI @mxw I've updated this PR by moving the Hot cache to between Main and Cold.

However, Dave and I still have a concern. Why are we running code from Cold often enough that this really makes such a difference? Specifically, is something being incorrectly placed in Cold with the hint "Unlikely" ?

I used #7703 from @swalk-cavium to dump the caches during the OSS/Mediawiki benchmark, and under 3% of the total cycles are spent in Cold). I then filtered by the addresses of the cold cache using the -a and -A flags, and the top hitter in Cold is part of is the Hooks::run php function (from the /tmp/hhvm-nginxxUDocX/mediawiki-1.28.0/includes/Hooks.php file line 131). I think, but I'm not sure, that the foreach on line 132 is in Hot, as is the return true on line 207, however the foreach's body from lines 133 to 205 is placed into Cold. This is true on ARM and x64. Why? I was expecting to find an exception handler or something else "unlikely", but finding the body of a foreach loop confuses me. Any light you can shine would be greatly appreciated!

@hhvm-bot
Copy link
Contributor

@mxw has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@jim-saxman
Copy link
Contributor Author

@mxw, Hi. What's the status on this patch? Would you like it changed in some fashion? I just re-benchmarked it last night and it still provides solid gains across OSS, especially Mediawiki and Drupal7.

@jim-saxman
Copy link
Contributor Author

Hi @mxw Do I have a chance of getting this PR accepted? Are there any changes you'd like me to make?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants