Welcome to the main channel on the development of MoarVM, a virtual machine for NQP and Rakudo (moarvm.org). This channel is being logged for historical purposes.
Set by lizmat on 24 May 2021.
00:13 MasterDuke91 joined
MasterDuke91 timo: you might find github.com/Raku/nqp/commit/0d4885d...e43b98d7d7 interesting 00:13
timo well, that disappeared 00:19
MasterDuke91 yep
timo: with your change, `raku --ll-exception -e 'use MONKEY; say EVAL "die";'` gives: 00:21
at gen/moar/CORE.c.setting:49703 (/home/dan/Source/perl6/install/share/perl6/runtime/CORE.c.setting.moarvm:throw)
from gen/moar/CORE.c.setting:1015 (/home/dan/Source/perl6/install/share/perl6/runtime/CORE.c.setting.moarvm:die)
from gen/moar/CORE.c.setting:1011 (/home/dan/Source/perl6/install/share/perl6/runtime/CORE.c.setting.moarvm:die)
without that change: 00:22
at SETTING::src/core.c/Exception.pm6:62 (/home/dan/Source/perl6/install/share/perl6/runtime/CORE.c.setting.moarvm:throw)
from SETTING::src/core.c/control.pm6:213 (/home/dan/Source/perl6/install/share/perl6/runtime/CORE.c.setting.moarvm:die)
from SETTING::src/core.c/control.pm6:209 (/home/dan/Source/perl6/install/share/perl6/runtime/CORE.c.setting.moarvm:die)
timo i need to revert that 00:24
we may want to see if we can optimize that. a lot, ideally 00:26
MasterDuke91 please do 00:27
timo so during parsing, we hit mostly the first entry in the list or the last 01:11
while going through the mast stage however we kind of just linearly go from the start to the end, where the list is 228 entries long 01:12
some kind of little cache could probably do a lot to help here
perhaps splitting the directives array into one array of line numbers and one with filenames 01:13
so we dont have a bunch of nested lists of int, str in the directives list 01:14
so the line numbers list can become a native int list as well
native str list is a little better than regular list with strings in it as well i think?
additionally / alternatively, there could be a binary search there 01:15
01:24 evalable6 left, linkable6 left 01:27 linkable6 joined 01:55 kjp left 01:56 kjp joined 03:25 evalable6 joined 04:00 MasterDuke91 left 04:05 reportable6 joined 04:25 Xliff left 05:33 committable6 left, statisfiable6 left, greppable6 left, sourceable6 left, releasable6 left, linkable6 left, evalable6 left, squashable6 left, bisectable6 left, shareable6 left, bloatable6 left, nativecallable6 left, unicodable6 left, benchable6 left, notable6 left, coverable6 left, quotable6 left, tellable6 left, reportable6 left, unicodable6 joined 05:34 evalable6 joined, nativecallable6 joined, coverable6 joined, tellable6 joined 05:35 greppable6 joined 05:36 committable6 joined, shareable6 joined 05:39 Altai-man left 06:03 reportable6 joined 06:34 sourceable6 joined, linkable6 joined 06:35 quotable6 joined 06:36 benchable6 joined, notable6 joined, bloatable6 joined, squashable6 joined 06:56 frost joined
Nicholas good *, #moarvm 07:12
07:36 bisectable6 joined, statisfiable6 joined 08:36 releasable6 joined
timo good 08:41
lizmat switched back to the new-disp branch 08:59
and did some test-t timing: master: 1.32 / 0.60 (test-t and test-t --race 09:00
new-disp: 2.11 / 0.81 09:01
startup: .12 (master) and .16 (new-disp) 09:02
just some data points... no pressure :-)
Nicholas I'm sure it's all brrt's fault for not JITting it all yet :-) 09:07
lizmat while doing some timing stuff, something struck me (again) that I feel warrants some thinking 09:08
when just measuring bare startup, every now and then I get an outlier that is *way* below average 09:09
just now, on master: 5 times .126 in a row, and then one with .095 09:10
and I can't help but think: maybe that outlier didn't have its spesh thread started for some reason 09:11
is that a weird idea?
or are there other easy ways to all of a sudden get a much faster startup ? 09:12
(well, and shutdown of course)
timo it would be quite strange for the spesh thread to not start 09:20
Nicholas lizmat: to paraphrase the Spacex reddit answer of "it's ice. it's always ice" (which isn't quite always true) we always seem to say "it's hash randomisation, and it's causing spesh to have a good day" (or bad day). As in
I'd suggest that, but I have no idea how to test that theory 09:21
timo but i'm also not entirely sure if we're perhaps waiting a noticeably long time for the process to shut down due to the spesh thread?
we can systematically test one bajillion hash randomization seeds, right?
Nicholas In parallel universes in constant time, sure. But it's probably faster to test about 100 runs (or whatever it is) with hash randomisation "normal", and then try 100 with it disabled (or fixed to one salt) and see if the latter doesn't have these outliers 09:22
lizmat if it *is* hash randomization, then from the bajillion possible seeds, maybe we could choose from a subset that is faster 30% faster :-)
how does one start up with it disabled again ? 09:23
timo oh i thought that was a compile time change 09:24
Nicholas er, I'm not sure if it's possible without changing a #define and recompiling MoarVM.
lizmat ah... ok
Nicholas and there were actually two things to disable 09:25
1) the random 64 bit value used to peturb the calls to SIPhash generating the 64 bit hash value for any string
2) the random number in each hash that gets "mixed" into that
09:33 lizmat_ joined 09:37 lizmat left, lizmat_ is now known as lizmat, lizmat left, lizmat joined
timo so, um, who knows how moar and nqp handle nonexistant dynamic variables, why do they get a list when they are @ sigiled and why do you get the same list back every time? 09:44
lizmat only knows of the Rakudo way :-( 09:45
jnthnwrthngtn I believe NQP also has some kind of fallback semantics 10:19
lizmat: The test-t one is very likely mostly down to the missing inlining still. 10:20
lizmat: I'm continuing work on that today; we'll see how far I get
Startup is a thornier issue.
lizmat ++jnthnwrthngtn :-) 10:21
jnthnwrthngtn We do save on deserializing method caches, but we probably make that up in deserializing meta-objects. 10:23
Although deserialization is by far dominated by the inefficient way NFAs are stored 10:24
lizmat what could be done to store them more efficiently?
timo we currently store them both as a bunch of arrays and an actual nfa object
the nfa object has essentially its own optimized serialization 10:25
and you can relatively easily make the one form from the other
jnthnwrthngtn Right, if we could recover the bunch of arrays from the NFA object that'd be a kinda solution but...
timo did the branch where i implemented that nqp op ever get merged, i wonder
jnthnwrthngtn ...when I glanced "how much effort is this" it seemed one'd have to restructure quite a bit of the code too
timo yeah, we need the bunch-of-arrays form so that we can modify the nfa from nqp code 10:26
jnthnwrthngtn Then I was like, sigh, we need to re-work the grammar engine more broadly, so this is annoying throwaway work
lizmat which brings me back to the idea I once had, of reimplementing the grammar engine in Rakudo :-)
timo surely we can't just make an nfa multi-dim-subscriptable?
jnthnwrthngtn timo: That's...interesting 10:27
timo probably troublesome for in-between forms while we're modifying stuff
jnthnwrthngtn lizmat: For prototyping a new design, or as the thing to use? 10:28
(It'd present some...bootstrapping problems...if the latter.)
lizmat potentially both ?
jnthnwrthngtn I mean, we'd want to use it for NQP too
For prototyping it makes sense at least. 10:29
timo clearly needs a raku to nqp compiler :)
jnthnwrthngtn I already have a terrible partial one of those :P
(That's what the AST implementation does.)
lizmat he.. indeed :-) 10:30
timo yup 10:33
nqp-js: sub a() { say(nqp::objectid(@*a)); }; sub m() { say(nqp::objectid(@*a)); }; sub x() { a(); m(); }; a(); a(); x(); m();m(); a(); m(); 10:35
camelia sudo: /home/camelia/nqp-js: command not found
timo nqp-jvm: sub a() { say(nqp::objectid(@*a)); }; sub m() { say(nqp::objectid(@*a)); }; sub x() { a(); m(); }; a(); a(); x(); m();m(); a(); m();
camelia sudo: /home/camelia/rakudo-j-inst/bin/nqp-j: command not found
timo nqp: sub a() { say(nqp::objectid(@*a)); }; sub m() { say(nqp::objectid(@*a)); }; sub x() { a(); m(); }; a(); a(); x(); m();m(); a(); m(); 10:36
camelia 21030072
timo jnthn, would you consider this a bug?
nothing declares this dyn var but still we somehow store it somewhere?
jnthnwrthngtn Can you say .HOW.name of the thing given to objectid too? 10:43
(My suspicion is that it's NQPMu)
timo nqp: sub a() { say(nqp::objectid(@*a)); say(@*a.HOW.name(@*a)) }; sub m() { say(nqp::objectid(@*a)); }; sub x() { a(); m(); }; a(); a(); x(); m();m(); a(); m(); 10:45
camelia 45652648
timo well there we have that
nqp: sub a() { say(nqp::objectid(@*a)); say(@*a.HOW.name(@*a)) }; sub m() { say(nqp::objectid(@*b)); }; sub x() { a(); m(); }; a(); a(); x(); m();m(); a(); m(); 10:46
camelia 42068920
jnthnwrthngtn Is it a concrete array or just the type object?
If the former, what on earth...
timo nqp: sub a() { say(nqp::objectid(@*a)); say(@*a.HOW.name(@*a)); say(nqp::isconcrete(@*a)) }; sub m() { say(nqp::objectid(@*b)); }; sub x() { a(); m(); }; a(); a(); x(); m();m(); a(); m();
camelia 40005000
timo concrete
my thought is the mechanism that gives us an array when the dyn var doesnt exist since we asked for a @ sigil is somehow wonky 10:47
jnthnwrthngtn Yeah, I'm just wondering where on earth it stores it 10:48
$ast := QAST::VarWithFallback.new( 10:49
:name(~@name.pop), :scope('contextual'),
And $global_fallback involves
lexical_package_lookup(['GLOBAL', ~$<sigil> ~ $<desigilname>], $/),
Yeah, that does indeed vivify it in GLOBAL 10:50
m: say(GLOBAL.WHO<@a>); @*a; say(GLOBAL.WHO<@a>); 10:51
camelia (Any)
Dynamic variable @*a not found
in block <unit> at <tmp> line 1
jnthnwrthngtn oh, NQP 10:52
nqp: say(GLOBAL.WHO<@a>); @*a; say(GLOBAL.WHO<@a>);
jnthnwrthngtn nqp: say(nqp::existskey(GLOBAL.WHO, '@a')); @*a; say(nqp::existskey(GLOBAL.WHO, '@a'));
camelia 0
jnthnwrthngtn nqp: say(nqp::existskey(GLOBAL.WHO, '@*a')); @*a; say(nqp::existskey(GLOBAL.WHO, '@*a'));
camelia 0
jnthnwrthngtn nqp: say(nqp::existskey(GLOBAL.WHO, '@*a')); say(nqp::objectid(@*a)); say(nqp::existskey(GLOBAL.WHO, '@*a')); 10:53
camelia 0
jnthnwrthngtn nqp: say(nqp::existskey(GLOBAL.WHO, '@a')); say(nqp::objectid(@*a)); say(nqp::existskey(GLOBAL.WHO, '@a'));
camelia 0
jnthnwrthngtn Huh.
No idea, but yeah, agree that it vivifying an array is wrong 10:54
lizmat afk for a few hours& 10:58
10:59 squashable6 left 11:05 lizmat left 11:08 TempIRCLogger left 11:09 lizmat joined 11:10 TempIRCLogger joined 11:26 brrt joined
Nicholas good *, brrt 11:50
timo bood *, grrt 11:54
12:00 squashable6 joined 12:03 reportable6 left 12:13 brrt left
timo now i can look where the right spot to hang the comp line directives is 12:19
its really at the compunit level i think?
and the same spot that gets that would also get the tiny cache to make lookups fastered 12:20
13:05 reportable6 joined
jnthnwrthngtn Getting somewhere with inlining calls with resumptions set up; it will find such a resumption and it works with the interp, but not with the JIT 13:16
It seems finding the current active deopt index doesn't work if we're in the frame on the stack top
timo does the resumption op need an annotation in the oplist that causes some varABle to get updated when its reached? 13:19
jnthnwrthngtn m: say 0x7f590e8eb82b - 0x7f590e8eb337 13:21
camelia 1268
jnthnwrthngtn No, it should really give the label immediately after the sp_dispatch that wants to resume, but doesn't 13:23
That first number is what it probably should find, the second is what is in *tc->jit_return_address 13:24
13:24 frost left 13:25 brrt joined
brrt good *, timo, Nicholas 13:25
jnthnwrthngtn oh yay, it's brrt :)
brrt also, I learnt recently that hacker news has a 'brnt' user, also from the Netherlands
ohai jnthnwrthgtn.... I fear something is broken about the JIT again 13:26
jnthnwrthngtn brrt: I'm having trouble getting MVM_jit_code_get_active_deopt_idx to give a valid result when it's about the currently executing frame 13:27
brrt: We're running an sp_dispatch at the time. I first though it was 'cus that wasn't marked :invokish, but I just tried that.
brrt ehm. 13:28
jnthnwrthngtn The piece I don't really understand: in the prologue we do:
| lea rax, [rsp-0x8];
| mov aword TC->jit_return_address, rax; 13:29
And null it out in the epilogue, but what is it that actually updates that location?
Is it the `call` instruction, 'cus it's the (ABI-level) location of the return address?
brrt yes
the 'call' instruction does this 13:30
that's... the beauty of it, really
this can go wrong if we use `push` and `pop` in the assembly
which I don't think we do?
jnthnwrthngtn doesn't look liek it 13:31
github.com/MoarVM/MoarVM/blob/new-.../emit.dasc is the JIT of sp_dispatch
In theory the label is right after it
brrt will have a look 13:33
jnthnwrthngtn Oh. Uhhh.
When we inline something...there isn't a DEOPT_ALL on it any more 13:34
I wonder if that in turn means no label.
brrt two steps back pls 13:35
what lines should I be looking at
jnthnwrthngtn hah, yes, I figured out a fix 13:38
brrt :-)
jnthnwrthngtn brrt: Today in after_ins we have:
brrt good.
jnthnwrthngtn } else if (ann->type == MVM_SPESH_ANN_DEOPT_ALL_INS) { 13:39
brrt yeah
jnthnwrthngtn If I change it to
} else if (ann->type == MVM_SPESH_ANN_DEOPT_ALL_INS ||
(ann->type == MVM_SPESH_ANN_DEOPT_INLINE && (ins->info->jittivity & MVM_JIT_INFO_INVOKISH))) {
Then it works for inlines also, although this feels mildly cheaty
I guess my next question is "how did we get away with this"... :) 13:41
Geth MoarVM/new-disp: dfde811154 | (Jonathan Worthington)++ | 3 files
Ensure we have JIT deopt info for inlined dispatch

  * Mark it invokish
  * When we see an inline deopt annotation on an invokish instruction,
   treat it like a deopt all
brrt ugh 13:59
I promise I probably knew one time
timo looking very forward to the next commit that i assume will be spesh linking and possibly inlining of things that use resumption 14:01
jnthnwrthngtn We already have spesh linking of that, it's inlining 14:04
I do locally have the first step to reinstating inlining working, but:
1. I know I need to do a bit more work with regard to deopt, but it's surprisingly tricky to write an example that triggers it
(And still does all the required inlines, and triggers it at the right time to make the situation that needs handling) 14:05
2. I see a couple of spectest regressions, although they don't involve resumption, so I think I'm allowing more inlining and exposing something else that wants fixing
I'd like to sort out 1 before I push it 14:06
timo phew. okay
jnthnwrthngtn The step after that for more inlining is to allow us to inline sp_resumption itself, which I think is really mostly work in the graph merge; the way I wrote the code in the resumption search should already handle multi-level inlines. 14:07
However, in the inline log I see a huge amount of "a deopt may happen before arguments are processed" 14:08
Which I think is our main blocker
And I think that's due to things like hllize sticking in guards in the dispatcher translation that are not require 14:09
BUT when I stop inserting those, the NQP build blows up
That will need sorting out before we can really have a chance of inlining as well as before 14:10
timo you gave me the hope of inlining better than before :D but that will come in time of course 14:14
jnthnwrthngtn Well, there will be things we can inline now that we couldn't before 14:16
Actually my test case is of a simple (but not onlystar) proto, where we inline the proto itself
Which was impossible before
Oh finally, I managed to cause a deopt that busts things
timo de-ooped 14:17
jnthnwrthngtn OK, now to recreate dispatch run call records... 14:19
Hmmm. I wonder if I really should do it that way... 14:22
The code would be vastly simpler with a special kind of call stack record for a deopt'd resume init arg set 14:24
Hm, or would it 14:25
Yup, it's possible to reconstruct a sufficiently convincing run dispatch record, but not pleasant. 14:35
Deopt is difficult enough to debug already.
Got it "working" for my example. Turns out somewhere deep in compiling CORE.setting it now segfaults though :/ 16:01
Thankfully, it was a silly thinko 16:13
Geth MoarVM/new-disp: 56067a06ad | (Jonathan Worthington)++ | 8 files
Allow inlining of dispatches with resume init args

This enables inlining optimizations in `sp_runbytecode` when there are
  `sp_resumption` instructions stacked up before it. (It does not yet
allow inlining of `sp_resumption` instructions themselves). The key pieces are:
... (11 more lines)
jnthnwrthngtn That was kinda tricky to work out how to do, but the implementation is relatively straightforward in the end 16:28
16:30 evalable6 left, linkable6 left 16:32 evalable6 joined
dogbert11 jnthnwrthngtn++ 16:38
17:15 brrt left
Geth MoarVM/new-disp: 31d53e35d5 | (Jonathan Worthington)++ | 3 files
Enable inlining of sp_resumption

By doing all of the required index fixup:
  * In the sp_resumption op itself
  * In the inline table
  * In the spesh resume init table
And merging the spesh resume init table itself.
lizmat jnthnwrthngtn: so should that make a performance difference for test-t? 17:23
or would you like me to find out? :-)
jnthnwrthngtn We have some newly busted stuff to hunt from this, alas, but that triage would be nice to share. 17:24
lizmat ok 17:25
jnthnwrthngtn lizmat: Maybe, but so much inlining is being forbidden by "potential deopt before args processing" that I suspect it'll block many of the benefits.
Some improvement in test-t is likely (it'd be interesting to see how much) 17:26
Running it with MVM_SPESH_INLINE_LOG=1 and looking for "a deopt may happen before arguments are processed" will give a feel for how much is being left undone because of that issue 17:27
Time to cook, rest, etc. bbl 17:29
lizmat It's remarkably quick: 17:33
$ time raku test-t.pl <hello.csv
Segmentation fault: 11
[Coke] Regarding post-deploy merge - I think the windows build issue is a blocker, but the nativecall concurrency issue is probably not (though I think we'll need to track that down over the next month.) I can see if I can duplicate ... was it masterduke? Nine? 's fix for the VLA. 17:34
(if no one else gets to it.)
Is there a list of issues to fix before the merge / list of expected things to hit before first release? 17:35
(afk) 17:36
18:03 reportable6 left
dogbert11 MoarVM oops: Failed to find deopt index when processing resume 18:04
18:05 patrickb joined
jnthnwrthngtn dogbert11: Yeah, spotted that one; it only happens with the JIT enabled 18:05
lizmat jnthnwrthngtn: so no test-t numbers 18:08
dogbert11 jnthnwrthngtn: aha
18:30 linkable6 joined
lizmat m: sub e() { 42 }; say e 18:49
camelia 2.718281828459045
lizmat hmmm
19:05 reportable6 joined 19:22 patrickb left
timo yeah cuz e is a term, right? 19:23
lizmat yup 19:24
but I thought locally defined things would have precedence?
or is that because the name of the sub is really &e 19:25
and "foo" is just syntactic sugar for "&foo()" ?
timo probably terms will always have precedence over subs without parens 19:45
19:51 cognominal left
lizmat I guess :-) 19:59
it's still a bit of a gotcha
m: sub now() { 42 }; dd now 20:00
camelia 42
lizmat he?
I though now was also a term ?
m: sub pi() { 42 }; dd pi 20:03
camelia 3.141592653589793e0
lizmat hmmm....
lizmat goes away for a bit for some epibration
nl.wikipedia.org/wiki/Epibreren # for the more Dutch inclined :-) 20:06
dogbert11 jnthnwrthngtn: not the best golf ever but try the code snippet below with MVM_SPESH_NODELAY=1 20:26
for ^10 { my $proc = Proc::Async.new($*EXECUTABLE, '-e', '$*OUT.write(Blob.new(65, 66))'); my $result = ''; $proc.stdout.tap({ $result ~= $_ }); await $proc.start; }
japhb lizmat: That is a truly excellent term. Right up there with 'defenestration' I think. 20:38
jnthnwrthngtn dogbert11: Thanks, will look at it tomorrow 21:24
22:52 linkable6 left, evalable6 left 22:54 RakuIRCLogger left 22:55 TempIRCLogger left, evalable6 joined 22:56 linkable6 joined, Geth left, lizmat left 23:00 lizmat joined, TempIRCLogger joined 23:01 Geth joined