pawnbox has quit [Remote host closed the connection]
pawnbox has joined #jruby
pawnbox has quit [Ping timeout: 276 seconds]
skade has joined #jruby
bbrowning has quit [Quit: Leaving]
e_dub has quit [Quit: ZZZzzz…]
<headius>
chrisseaton: hey I'm confused about your deopt and safe points...you have something "special"?
zacts has quit [Quit: WeeChat 1.4]
<headius>
I'm looking at doing a better job of detecting Fixnum/Float overrides, which will mean more safepoints
<chrisseaton>
we re-use normal VM safe points to deopt
<headius>
well, more switchpoints
<chrisseaton>
Switch points do as well I think
<headius>
right...so does hotspot + indy
<headius>
but what's the special part?
<chrisseaton>
Not sure what you mean - are you aware that it doesn't matter how many switch points you have in a method, you don't get any more safe points? The safe points are only ever in the same places, whether you have a switch point near there or not
<headius>
yes, I'm aware
<headius>
safe points can also get added if you put guards in the middle of side-effect-free code though
skade has quit [Quit: Computer has gone to sleep.]
<headius>
in a place where none would have existed before
<chrisseaton>
are you sure? that's not how I believe they work, but I'm not an expert in that area
<chrisseaton>
because the thread causing the pause in safe points can just wait until all threads reach them, so within reason it doesn't matter how long it takes
<headius>
but if there's a boolean condition you've optimized, for example
<headius>
straight-line code, I'm not sure where the VM would put safe points in it if it were not optimized
<chrisseaton>
right, but that doesn't matter
<headius>
why not?
<headius>
you'll have code go down the wrong branch because it hasn't reached the next safepoint to invalidate yet
<chrisseaton>
Because the thread triggering the safe point waits until all threads stop
<headius>
and they stop at safepoints
skade has joined #jruby
<headius>
which would be after the optimized guard in question if there weren't a safepoint there
<chrisseaton>
But you stop all threads *before* you cause the side effect that invalidated what they assumed
<chrisseaton>
Stop everyone, tell them things have changed, not the other way around
<chrisseaton>
Sorry, stop everyone and tell them things are going to change, not change it and then stop everyone
<chrisseaton>
I remember being confused about this
<headius>
right ok, that matches my understanding better
<headius>
but if you have a = b + c; if SOME_OPTIMIZED GUARD; blah; else foo; end
<headius>
if that were jitted simply without optimizing that guard it would not have a safepoint there
<headius>
if you optimize with a guard, it would have to
prasun_ has left #jruby [#jruby]
<chrisseaton>
no, but how could you tell the difference
<headius>
so what you're saying is that it wiill proceed with the wrong value until it hits a safepoint, and then allow the right value to be published
prasun has quit [Remote host closed the connection]
<chrisseaton>
no - if someone wants to change SOME_OPTIMISED_GUARD, and you're asking what happens if it happens where you first semicolon is?
<headius>
yes
<headius>
if it doesn't insert a safepoint there it won't stop and wait for the guard to deopt at the id
<headius>
the if
<chrisseaton>
right, so it doesn't stop and wait - the person who wants to invalidate the guard has to wait until a safe point is reached
<headius>
you'd be able to tell the difference because temporally you have requested the guard be invalidated at time A, and code executing after time A won't see it for a bit
<chrisseaton>
the guard doesn't get invalidated until everyone's in a safepoint
<chrisseaton>
so nothing's happened until everyone's in a safepoint
<chrisseaton>
but our processor architectures don't have any kind of ordering guarantees like that anyway - there's no such thing as 'time A', only side effects being ordered
<chrisseaton>
and as I say, the side effect doesn't happen until everyone's in a safepoint
<headius>
there absolutely is such a thing as 'time A' if we're assuming volatile guards
e_dub has joined #jruby
<chrisseaton>
thread A only sees that the guard is invalidated when it is in a safepoint
<chrisseaton>
therefore, thread B doesn't invalidate the guard until thread A is in a safepoint
<chrisseaton>
nothing changes until A is safely paused
<chrisseaton>
thread B has to wait, but until A and B are ready, the $DEBUG = true or whatever hasn't happened yet - the program is pausing until it can make that change
<headius>
hmm
<enebo>
this makes sense to me across threads
<headius>
right...so it isn't considered published until all threads get to a safepoint
<chrisseaton>
thread A keeps running happily assuming the guard is valid, because it is, until thread A pauses and accepts the invalidation
<chrisseaton>
yes
<chrisseaton>
and within a thread it's different - the thread itself can immediately pause and invalidate if it's triggering it on itself
<enebo>
but in b + c if that invalidates the guard then what?
<enebo>
I suspect I am missing something really ismple there :)
<chrisseaton>
if thread A invalidates itself that's easy isn't it - it just throws away its own code
<chrisseaton>
'I'm going to change $DEBUG to true, oh wait I assumed it was false, so I'll jump back to the interpreter and carry on there with full checks'
<enebo>
but if as charlie says it is optimized and has no safdepoint how would it?
<headius>
so invalidating a guard forces a safepoint then
<chrisseaton>
yes
<headius>
even for current thread
<chrisseaton>
because the code for $DEBUG = ... causes it to pause - it emits code to say to do that
<chrisseaton>
it does even for the current thread, because it's a VM global operation
<headius>
so then if you do $DEBUG = true in code, it *will* force a safepoint
<chrisseaton>
it forces everyone to pause inside their safe points (the terminology overlaps, safe point as the check, safe point as the state etc)
<headius>
sure
<chrisseaton>
so using the safe point is not cheap
<chrisseaton>
so if you keep changing $DEBUG many many times we'll stop making any assumptions
<headius>
right, we do the same
<enebo>
chrisseaton: do you use this for more than globals?
<headius>
safepoint around the guarded value with some bailout if it changes too much
<chrisseaton>
enebo: yeah this is fundamentally how we cache method calls
<headius>
or at least...we used to...not sure if that part of our indy code made it to 9k
<enebo>
chrisseaton: ok I was wondering about that :)
<thedarkone2>
headius: there 2 cases, either the currently running thread is invalidating something, then it is a conditional jmp into deopt routine
<headius>
so it sounds like it's the same behavior regardless of hotspot or truffle
<chrisseaton>
we use it for all sorts of other stuff as well - it's very powerful and easy to use - you can just disable whole parts of the language semantics until they're actually needed, like overflow etc
<headius>
yeah, switchpoint
<enebo>
chrisseaton: the b+c calling code which defines a method is a common pattern for invdaliting a callsite
<chrisseaton>
yes our assumptions are exactly the same as your switch points - I think our paper says that
<thedarkone2>
if a different thread is invalidating something it requests hotspot to safepoint all threads, and the proceeds to invalidate
<headius>
ok
<enebo>
well maybe not common
<headius>
then I'm not confused anymore
<headius>
I thought you were doing something different
<headius>
thedarkone2: right, that makes sense now...I was not clear on the temporal details
<chrisseaton>
there seems to be very little literature about safe points - the GC handbook says almost nothing - there was a paper at ISMM a couple of years ago about one tiny aspect - I think our ICOOLPS paper may be the best written description of them at the moment
<GitHub106>
jruby/master 95208a8 Charles Oliver Nutter: Add sort_by! spec for single-element array....
tcrawley is now known as tcrawley-away
drbobbeaty has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
<thedarkone2>
headius: admittedly, working with switchpoints, you have it much worse than Truffle's assumptions, because in Truffle you can do/rely on arbitrarily complex abstractions (DRY-up your code) without having to worry about inlining budgets etc., addionally you are able to litter "assert this is a const" everywhere… so you're worry about the cost of supposedly free switchpoints is imho warranted (don't know if hostpost's newish incrementa
<thedarkone2>
inlining helps with that)
<headius>
incremental inlining helps a great deal
<headius>
but we can also run on graal of course
<headius>
I don't see what inlining budgets have to do with switchpoint though
<headius>
and it's not quite fair to say truffle escapes inlining budgets when it just inlines everything :-)
<thedarkone2>
if the method in question has 50 switchpoints in itself?
<headius>
so what?
<headius>
each one will boil down to appropriate safepoint nearby
<thedarkone2>
of course, but switchpoint checks are method calls
<headius>
no they're not
<headius>
they inline to a safepoint
<thedarkone2>
I meant to inliner
<headius>
well ok, they would be a single invokedynamic
<headius>
in our simplest case invokedynamic instr with no arguments and a constant pool reference, so a couple bytes
camlow32_ has quit [Remote host closed the connection]
<headius>
so then yes, incremental inlining definitely helps
<headius>
and running on graal helps
<thedarkone2>
is Graal also incrementally inlining though? :)
<headius>
Graal doesn't have inlining budgets
<headius>
I believe it only goes against the complexity of the optimized nodes after inlining etc
<headius>
incremental inlining is supposed to do that but you still have to have enough room left to inline before you optimize
<headius>
so it can do it but coarser chunks
<headius>
I am not an expert here though :-)
<thedarkone2>
what I meant with hotspot, consider that you have a method that has 50 ruby method calls in it, so it weights at X bytecodes, but if each of those method calls has associated switchpoint checks (lets say 5 per method), then they carry additional bytecode weight, right?
<headius>
additional switchpoint checks?
<headius>
oh well there's one detail missing here: most of java.lang.invoke has JVM-internal annotations like @ForceInline
<headius>
so they get a free pass
<headius>
several methods are intrinsics
<headius>
so most of the pipeline of method handles attached to an indy call site will forcibly inline
<headius>
that includes switchpoint
<thedarkone2>
ok, @ForceInline probably solves that
camlow325 has joined #jruby
<headius>
I wish we could use it :-)
enebo has quit [Quit: enebo]
<thedarkone2>
you're a filthy user, you wouldn't know what to do with it!
<thedarkone2>
yeah I bet having access to @Stable and @ForceInline would go a long way for JRuby :)
<headius>
planning to get around it by just emitting more code
<headius>
re-JIT hot methods that take blocks so they can inline each block, etc
<headius>
we can do anything, it's just more cumbersome
lanceball is now known as lance|afk
<chrisseaton>
you're not using ExactMath yet are you? I always thought that would be a low hanging fruit for you
camlow325 has quit [Remote host closed the connection]
skade has quit [Read error: Connection reset by peer]