Skip to content

Conversation

@rkennke
Copy link
Contributor

@rkennke rkennke commented Feb 27, 2019

As discussed here:
https://mail.openjdk.java.net/pipermail/graal-dev/2019-February/005634.html
I would like to generalize the GC barrier information that we carry around in nodes. Instead of the rather GC specific PRECISE vs IMPRECISE information, I'd prefer to record whether or not the access is to array element or a field, and whether or not the access is to primitive field or object field. We also need to know if it's the special access to a Reference.referent field.

I tried to determine the primitive vs. object field information in the backend from the JavaKind of the node (or in case of writes, its value), but it turns out this not always consistent with the information carried in BarrierType. I suspect that object writes can sometimes be generated that don't require a barrier?

Notice that the implementation covers the need for current barriers. This means it's equivalent to what was there before. It's not yet generating the correct information for loads, yet (except for the referent field access), because no GC currently needs it. I will get to this later, when adding support for Shenandoah and/or ZGC, which will require this sort of information. I'd rather not do this blindly. ;-)

Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be named BarrierUtils?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that is a good point! I will change it.

Copy link
Contributor

Choose a reason for hiding this comment

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

This could be a static method on enum BarrierPrecision, but it could just as easily be with the BarrierType code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Putting it in the enum sounds good. I'd rather not put it in the BarrierType class, because this is exposed everywhere.
I also have an idea how to reliably determine object vs. primitive. Stay tuned.

@rkennke
Copy link
Contributor Author

rkennke commented Feb 28, 2019

I just pushed a change that is closer to the original design, but renames and adds BarrierType values: IMPRECISE becomes FIELD, PRECISE becomes ARRAY, UNKNOWN means we don't know (and GCs treat it as array/precise) and REFERENT denotes a Reference.referent access. Initializing stores and useDeferredInitBarriers are now handled in the GC backends, rather than in the compiler. This still doesn't provide the implementation for load barriers, but it can easily be used for that. I'll do that in a followup PR.

@Peter-B-Kessler
Copy link
Contributor

Peter-B-Kessler commented Feb 28, 2019

@rkennke Not to confuse your life, but SubstrateVM has an annotation @Hybrid that allocates an array in an instance that also has fields. See https://github.com/oracle/graal/blob/master/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/annotate/Hybrid.java.

The @Hybrid annotation is used on DynamicHub (the thing pointed to from every object header) for the vtable for the class. (Also a bit set for type comparisons.) DynamicHub instances are read-only, so the current collector does not need write-barriers to access them. (And the current collector does not move them.)

I don't know if that changes the names you want to give to FIELD and ARRAY. Hybrids are enough of a special case that you might want to ignore them. If they don't need barriers, then they should not affect the names given to barrier types.

@rkennke
Copy link
Contributor Author

rkennke commented Feb 28, 2019

@Peter-B-Kessler oook, good to know, thanks! It sounds like I can safely ignore it for now (and not sure if the previous names have been any more useful either) :-)

I'm about to do some SubstrateVM/GC work soon anyway (mostly unrelated to this here), and then I guess I will get a better understanding of the situation there.

@Peter-B-Kessler
Copy link
Contributor

The thing to remember about the current SubstrateVM garbage collector is the (lack of) motivation for it. The idea of SubstrateVM was fast startup for small, short-running, services. In the best of all possible worlds, the application runs to completion without needing any collection. But we had to have some garbage collector, so a serial, stop-the-world, copying collector was "good enough". For now. If your application has gigabyte heaps, you don't need fast startup, and you are probably better off using HotSpot with your favorite (:-) collector.

The other constraint was running in environments where large blocks of contiguous memory are not available, which is why the current SubstrateVM heap comes in "chunks". That also means one does not have to specify a maximum heap size, and one can change the heap shape at runtime. Also, pinning objects is ... easier.

If you have questions about the current SubstrateVM collector and heap: ask away.

@rkennke
Copy link
Contributor Author

rkennke commented Mar 1, 2019

My application doesn't have GBs of heaps. I'm looking at 100-200MB. I guess it's too big/too long-running to not fit the original assumption, but not big enough to warrant full hotspot+GCs. Let's take that discussion to the mailing lists though... ;-)

This PR looks good to integrate (at least, CI-wise). Do the latest changes resolve your concerns?

@rkennke
Copy link
Contributor Author

rkennke commented Mar 1, 2019

@Peter-B-Kessler BTW, if you expect that an application dies before even hitting a single GC, you might want an even simpler GC: a single-space, sliding GC that triggers on memory exhaustion. This way you'd make best use of available memory, and not pay the runtime overhead of barriers. ;-)

@adinn
Copy link
Collaborator

adinn commented Mar 1, 2019

I suspect Peter (or, more importantly, Graal users) probably wants an insurance policy as well as low GC overhead.

@rkennke
Copy link
Contributor Author

rkennke commented Mar 1, 2019

The adoption of Epsilon for those sorts of uses is an indication that this is a more feasible proposal than it sounds like. And indeed, under closed world assumption, when you know how much you're going to allocate, and lifetime is short and limited anyway, this might indeed be your best bet.

@Peter-B-Kessler
Copy link
Contributor

Fortunately/Unfortunately, the GraalVM runtime compiler itself is written in Java, and allocates a lot of memory, and leaves behind a lot of garbage. So we chose a two-generation scavenger as a compromise. The epsilon garbage collector might be useful for when we can ahead-of-time compile the whole application. Eliminating barriers would be one advantage. If we could eliminate safepoint checks that would win, too. Lots of opportunities to win the "most improved VM" award. :-)

Choose a reason for hiding this comment

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

The correct new barrier type to use in this class (both changes) is ARRAY: In Substrate VM's single threaded mode, the thread local variables are stored in a normal Java array that resides in the image heap.

Copy link
Member

Choose a reason for hiding this comment

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

This should probably be an implementation detail of LoadVMThreadLocalNode instead of being a constructor parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so. VMThreadMTFeature.java passes NONE there. I'll change it to ARRAY for the VMThreadSTFeature.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to ARRAY in latest push.

Choose a reason for hiding this comment

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

The difference between the MT and ST feature is correct: in multi-threaded (MT) mode, the thread local variables are in the thread descriptor is in C memory, i.e., no barriers needed. In single-threaded (ST) mode, the thread local variables are in the Java heap in a regular array, i.e., array write barriers are needed.

Copy link
Member

Choose a reason for hiding this comment

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

So the barrier kind is really a property of VMThreadLocalInfo?

Choose a reason for hiding this comment

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

No, the barrier kind is a property of how the thread local storage is implemented. Which is all encapsulated in this class, so defining the barrier kind in this class is correct.

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good.

Choose a reason for hiding this comment

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

It's not ideal to have a barrier type that is only used by one specific VM, the HotSpot VM, in the VM-independent part of Graal. Maybe it is a bad idea in the first place to have barrier types as an enum here, and not just define an empty marker interface here and have the actual value definitions in VM-specific code.

Copy link
Member

Choose a reason for hiding this comment

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

I think a clear set in the core would better than multiple different definitions but I agree this naming is very HotSpot specific. Maybe this would be better called WEAK_FIELD to generalize it?

Choose a reason for hiding this comment

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

We could do a split: some definitions (definitely UNKNOWN, but maybe also FIELD and ARRAY) in the platform independent part, and others like REFERENT in HotSpot specific code.

Copy link
Member

@dougxc dougxc Mar 5, 2019

Choose a reason for hiding this comment

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

Why is REFERENT HotSpot specific since it's a field in a (non-HotSpot specific) JDK class?

Choose a reason for hiding this comment

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

I guess the field is defined in the Reference class because it simplified the HotSpot implementation (unfortunately the JDK and the VM are not as decoupled as they should be). But the field has the interesting comment /* Treated specially by GC */ ;-)
So your argument is that the bad JDK/VM separation means that Graal also does not need to separate it out into VM independent code. Which is a valid argument.

Copy link
Member

Choose a reason for hiding this comment

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

If SVM adds a G1 style collector it will need the exact same special handling. The read from referent needs special handling because it's reading from a weak field. Even if the field were hidden in some way the actual read would still need this work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently, only Shenandoah and G1, probably ZGC (not sure) need to know about it, they are all Hotspot-only. Current SVM GCs don't currently need to know about it, but it surely belongs into the GC interface anyway (even if ignored by specific implementations). I'm fine with renaming it to WEAK_FIELD, this should be generic enough?

Copy link
Member

Choose a reason for hiding this comment

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

I think so.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Latest push fixes this.

Copy link
Member

Choose a reason for hiding this comment

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

I think you need to rearrange these tests. type.isArray() must be tested before type.isAssignableFrom(objectArrayType) to find the ARRAY case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Latest push should fix it.

Copy link
Member

Choose a reason for hiding this comment

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

This needs a type != null guard.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should be fixed.

@tkrodriguez
Copy link
Member

tkrodriguez commented Mar 12, 2019

The travis gate failed because of a minor indenting problem. There's also a problem our internal gate found that didn't show up here. There are a bunch of failures when running with -Dgraal.VerifyPhases=true that look like this:

java.lang.AssertionError: Write barrier must be present 135|Write { barrierType=FIELD, stamp=void, location=INIT_LOCATION, nullCheck=false,  } / inputs=[133|OffsetAddress, 134|HotSpotCompression]
          	at org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase.validateWrite(WriteBarrierVerificationPhase.java:105)
          	at org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase.processWrites(WriteBarrierVerificationPhase.java:86)
          	at org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase.run(WriteBarrierVerificationPhase.java:74)
          	at org.graalvm.compiler.phases.Phase.run(Phase.java:49)
          	at org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:197)
          	at org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:139)
          	at org.graalvm.compiler.phases.PhaseSuite.run(PhaseSuite.java:212)

You can just do something like mx unittest -Dgraal.VerifyPhases=true to see this. It's probably something simple.

Copy link
Member

Choose a reason for hiding this comment

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

Wrong indent.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should be fixed.

@graalvmbot
Copy link
Collaborator

Hello Roman Kennke, thanks for contributing a PR to our project!

We use the Oracle Contributor Agreement to make the copyright of contributions clear. We don't have a record of you having signed this yet, based on your email address rkennke -(at)- linux -(dot)- fritz -(dot)- box. You can sign it at that link.

If you think you've already signed it, please comment below and we'll check.

@dougxc
Copy link
Member

dougxc commented Apr 9, 2019

Hi @rkennke can you please change the commits in this PR to use your RedHat email address since that it what is registered in the OCA database consulted by @graalvmbot .

@rkennke
Copy link
Contributor Author

rkennke commented Apr 9, 2019

Hi @rkennke can you please change the commits in this PR to use your RedHat email address since that it what is registered in the OCA database consulted by @graalvmbot .

Sorry, I don't know how to do that. git rebase doesn't seem to work on merge commits, which is the one with wrong email.
I could fold all the commits in this PR into one changeset, and open a new PR for that. Might be a good idea anyway, this became a bit messy.
Sorry, those are my first steps with git and github.
What do you think?

@dougxc
Copy link
Member

dougxc commented Apr 9, 2019

I don't know how to fix the author in merge commits either so I think squashing all the commits in the PR is probably the right way to go. However, please don't open a new PR - just force push your squashed commit to this PR (i.e., git pushf origin HEAD).

@rkennke
Copy link
Contributor Author

rkennke commented Apr 9, 2019

I don't know how to fix the author in merge commits either so I think squashing all the commits in the PR is probably the right way to go. However, please don't open a new PR - just force push your squashed commit to this PR (i.e., git pushf origin HEAD).

Are you sure? force-pushing to a branch with PR is discouraged by github:
https://help.github.com/en/articles/about-pull-requests

Also, I am not sure how to do that either. Interactively 'rebase' the branch, thereby deleting all the changesets, and then commit the squashed changeset? Seems easier to create a new branch+PR, link back to this here, and start with clean slate?

@dougxc
Copy link
Member

dougxc commented Apr 9, 2019

I've force pushed often to GitHub PRs with no negative consequences. As far as I know, the best reason to avoid force pushing is when you are actively collaborating with others on a PR (as in they are also pushing commits to the PR - not just reviewing it).

@thomaswue
Copy link
Member

As long as you don't force push master, everything is fine ;-).

The following should work for squashing (make a local backup of the changesets in case something gets messed up):
git rebase -i master
https://github.com/wprig/wprig/wiki/How-to-squash-commits

@rkennke
Copy link
Contributor Author

rkennke commented Apr 9, 2019

Worked like a charm! Thanks!

@rkennke rkennke force-pushed the gc-interface2 branch 2 times, most recently from 9c588cd to bbb272a Compare April 9, 2019 22:32
@rkennke
Copy link
Contributor Author

rkennke commented Apr 9, 2019

Ok, I think I messed it up. Rebased and re-committed the whole thing as single changeset. I hope that works now.

@rkennke
Copy link
Contributor Author

rkennke commented Apr 10, 2019

Hmm, it looks like I killed the travis checker somehow. How should I proceed? Sorry for messing things up so badly...

@thomaswue
Copy link
Member

That is fine. For this type of change, we will anyway have to run much more tests than just the Travis checker.

@rkennke
Copy link
Contributor Author

rkennke commented Apr 10, 2019

Ok, cool. Travis seems kaputt anyway, my other PR (#1117) travis job seems stuck since a while already... Let me know if you find anything that requires fixing. Thanks!

@tkrodriguez
Copy link
Member

I grabbed your latest bits and they pass our internal gates so it all looks good. We're waiting to push it until the GraalVM freeze is over at the end of the month.

@rkennke
Copy link
Contributor Author

rkennke commented Apr 10, 2019

Perfect, thanks!

@rkennke
Copy link
Contributor Author

rkennke commented May 22, 2019

It looks like this has already been integrated:

bbb272a

Closing the PR.

@rkennke rkennke closed this May 22, 2019
@rkennke rkennke deleted the gc-interface2 branch May 22, 2019 10:23
@tkrodriguez
Copy link
Member

Sorry, it usually detects the merge of you commit and automatically closes it. Not sure why it didn't detect it in this case.

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.

8 participants