11:17 librasteve_ joined 12:03 timo1 is now known as timo 14:06 librasteve_ left 15:18 librasteve_ joined 16:16 arunvickram joined
lizmat I appear to have lost my QAST chops 16:17
I have: 16:18
- QAST::Op(create)
- QAST::WVal(Int) Int
and need to change that to:
- QAST::Op(create)
- QAST::Op(decont)
- QAST::WVal(Int) Int
timo ? 16:19
16:21 arunvickram left
timo for a WVal we can check that it's not a container and skip the decont though right? 16:27
so you need something like $the-create-op[0] := QAST::Op.new(:op<decont>, $the-create-op[0]); or something? 16:32
lizmat well, I guess I could check for a WVal... but it wouldn't need to be 16:46
this is about changing Foo.CREATE into nqp::create(Foo) 16:47
rather than: nqp::callmethod(:name<CREATE>, Foo)
should make .CREATE about 2x as fast 16:48
timo well, decont on non-containers is pretty cheap post-spesh, it should completely disappear 16:49
lizmat m: Int.CREATE for ^10000000; say now - ENTER now
camelia 0.248240845 16:50
lizmat m: use nqp; nqp::create(Int) for ^10000000; say now - ENTER now
camelia 0.043995743
lizmat m: Int.CREATE for ^10000000; say now - ENTER now
camelia 0.270838002
lizmat wow, even more
on my Apple Silicon it's .213 vs .137 16:51
timo eliminating the interpreter overhead by jit compiling could be worth a lot here 16:52
actually, who knows if spesh dead-code-eliminates that create
yeah 16:53
m: use nqp; my $a; $a := nqp::create(Int) for ^10000000; say now - ENTER now
camelia 0.306393815
timo m: use nqp; my $a; $a := Int.CREATE for ^10000000; say now - ENTER now 16:54
camelia 0.276194725
timo .CREATE and nqp::create are pretty much exactly the same speed on my machine with that change 16:55
lizmat 0.208767584 vs 0.248389138 for me
so it appears to make sense on non-JITted hardware
although less than I would have hoped 16:56
timo: so do you think it would make sense t do such an opt ?
17:04 arunvickram joined
timo I'm not sure if the benefit will show up with anything but a microbenchmark that does nothing but loop + the create 17:05
oops, my moarvm was compiled with -O0 17:09
lizmat I'll wait for new benchmarks :-) 17:10
timo 1.57841 +- 0.00451 seconds time elapsed vs 1.52244 +- 0.00477 seconds time elapsed 17:12
for 10x as many runs of the loop
lizmat so the .CREATE continues to be a bit slower? 17:13
timo 2.87263 +- 0.00660 seconds time elapsed vs 2.5743 +- 0.0139 seconds time elapsed when JIT turned off 17:14
m: say "that's $(2.87263 / 100000000) seconds per nqp::create call" 17:15
camelia that's 0.0000000287263 seconds per nqp::create call
timo (not really per call, but per "go around the loop")
lizmat ok, but there's also the bytecode-size argument 17:17
m: dd sub a() { Int.CREATE }.bytecode-size
camelia 74
timo probably more sensible to count cycles rather than seconds
lizmat use nqp; dd sub a() { nqp::create(nqp::decont(Int)) }.bytecode-size
evalable6 44
timo wow, i've never seen that
lizmat evalable6 kicking in ?
or .bytecode-size ?
timo .bytecode-size 17:18
lizmat you actually implemented it if I remember correctly, as a syscall
timo git blame seems to suggest you implemented it 17:19
lizmat I did? in MoarVM ? wow 17:22
I recall doing the Rakudo side
hmmm....
ok, so could that be an argument to change .CREATE to be a "macro" rather than just a method call >? 17:23
better inlineability ?
timo a little surprising that it's that much smaller 17:25
lizmat I think the .CREATE version also throws in a nqp::hllize 17:26
timo ah, yeah
and it deconts the Int before it calls the method on it 17:27
lizmat yeah, but that would be inside the .CREATE method, no ?
or does the deconting happen at the callsite ?
timo in terms of inlinability i would expect those to not matter because inline size should be based on post-spesh size, not pre-spesh, right?
it really does decont before it does the lang-meth-call 17:28
lizmat so you're saying that spesh would have already removed the hllize ?
timo the "after" size of the looped-over block when speshed is just 70 bytes, 10 of which are from inside the inlined CREATE method 17:29
there's a guardconc there that i'm not sure why it survives
but that's only in the log where the frame by itself is optimized, when it gets inlined into the mainline the unnecessary guard then disappears 17:32
lizmat still I wonder what I'm missing in trying to adapt the QAST 17:44
gist.github.com/lizmat/7dfeaf0ac07...0d6f95c9d4 # timo work so far 18:09
timo from just the code I don't see where you're grabbing the existing $past 18:11
the other parts of the code work by just flipping the :op from callmethod to some other op, but what you want is to wrap the first child in a new Op node right? 18:13
but then i don't really understand how the output you posted in the comment can happen? 18:15
lizmat well, I'm as puzzled as you are 18:17
$past.op('decont'); 18:19
$past := QAST::Op.new(:op<create>, $past );
oops, sorry
produces: 18:20
│ │ - QAST::Op(create) :statement_id<1>
│ │ - QAST::WVal(Int) <wanted> Int
│ │ - QAST::Op(decont) CREATE2
I mean: $past.op("foo") just changed the op name to be used, right ? 18:21
so that by itself should change it to: 18:23
timo an idea appears
lizmat │ │ - QAST::Op(decont) :statement_id<1> CREATE2
│ │ - QAST::WVal(Int) <wanted> Int
which it does
timo we may be holding on to the $<args>.ast from code outside of this function 18:24
and the "make $past" may not actually have an effect
that could explain why making $past something else doesn't cause what we expect to see 18:25
lizmat well, it looks like the changes I make change someting
so given a $past, how do I remove the first arg ? 18:26
timo $past.shift should do it
lizmat so: 18:27
$past.op('create');
$past.push(QAST::Op.new(:op<decont>, $past.shift));
timo yeah
lizmat ===SORRY!===
MVMArray: Can't shift from an empty array
timo oh 18:28
i guess that means there was not actually a $<args>
makes sense, Int.CREATE doesn't have arguments
then it's even weirder though
lizmat well, the Int is the arg, no?
timo what does $past.dump look like?
oh 18:29
ok my guess is, the invocant gets unshifted into the Op node by the action that comes after the methodop one
so at the moment your code comes in, it isn't there yet
and if you just put a decont in there, it ends up as a sibling to the invocant 18:30
lizmat aaaah.... ok,. that would make sense
timo does it go via dottyop? 18:31
lizmat $past.dump says: 18:32
- QAST::Op(create) CREATE2
after the $past.op('create'); 18:33
methodop
so where does the "CREATE2" value live? is that a :name ? 18:34
but I guess you're right, the Int doesn't appear here yet, so that happens somewhere else 18:35
timo sounds like it's a little bit of magic that EXPR does to hook those things up
lizmat ok, I'm going to stop this exercise: the winnings are too small 18:36
timo the CREATE2 there in the output is probably the $/.Str?
lizmat and I guess in the end, that's the reason why .CREATE wasn't implemented as a macro to begin with
what felt like an easy fix wasn't 18:37
timo thanks for the listening ear and support 18:41
timo no problem
18:47 arunvickram left 19:17 arunvickram joined 19:21 arunvickram left 19:48 arunvickram joined