github.com/moarvm/moarvm | IRC logs at colabti.org/irclogger/irclogger_logs/moarvm
Set by AlexDaniel on 12 June 2018.
01:03 konvertex left 03:42 farcas1982regreg joined 08:10 konvertex joined 08:20 sena_kun joined
MasterDuke nine: around? 09:29
nine yes 09:30
MasterDuke re github.com/MoarVM/MoarVM/pull/1281...626137192, are you suggesting running MVM_hll_sym_get in spesh's optimize_getcurhllsym and then removing the getcurhllsym and replacing with a getspeshslot instruction? 09:32
similar to what is done with hllbool(for) 09:36
nine Not exactly. If the symbol name passed to getcurhllsym is a contant known value, we can in theory get the hash slot directly in optimize_getcurhllsym and put that into a spesh slot. Then at runtime we only have to fetch that slot, thus get the hash entry and follow its value pointer. 09:39
If the symbol name is not a constant, we can still get the cur HLL's symbol hash, saving at least one hash lookup.
The thing is, that I still can't see where getcurhllsym is used for IO 09:40
DYNAMIC doesn't use it either
MasterDuke uh, i see it when i do a spesh log of `my $o; $o := $*OUT for ^1_000_000;` 09:47
but yeah, it's not used directly by IO, but because the IO is looking up $*OUT 09:48
nine But where?
MasterDuke BB 14 09:49
nine There aren't that many HLL symbols in the first place. It's mostly used for getting the low level ModuleLoader, GLOBAL and @END_PHASERS
MasterDuke 1000009 calls to MVM_hll_sym_get looking up 'GLOBAL' in 'Raku' 09:54
but afk for a bit 09:55
nine Ah, so it is about GLOBAL. Those lookups are done with static strings, which means it could indeed be that perfect case I wrote about
10:16 Altai-man_ joined 10:18 sena_kun left 10:21 mtj_ joined
MasterDuke so an `if (facts->flags & MVM_SPESH_FACT_KNOWN_VALUE)` branch which stores the result of actually calling MVM_hll_sym_get in a spesh slot? and an else branch which does the second part of MVM_hll_sym_get manually? 11:14
to be precise, `if (sym_facts->flags & MVM_SPESH_FACT_KNOWN_VALUE)`? or sym and hll? 11:17
12:07 MasterDuke left
nine Not the result of MVM_hll_sym_get, because that would be the actual value which may change. Instead the result of the MVM_HASH_GET, i.e. the pointer to the hash entry struct which holds the ->value pointer 12:07
This way, it still works when the hash entry gets updated, i.e. a nqp::bindcurhllsym('GLOBAL', $myglobal) 12:08
12:17 sena_kun joined 12:18 Altai-man_ left 12:33 MasterDuke joined
MasterDuke nine: ah, so both branches will manually implement part of MVM_hll_sym_get (just the first branch will do more)? 12:34
nine yes 12:35
MasterDuke ok. i'll give that a shot 12:38
13:54 discord6 joined, discord6 left, discord6 joined
timotimo wasn't there a worry that something in the hll mapping could change that invalidates the lookup we do? 14:01
14:16 Altai-man_ joined 14:18 sena_kun left
MasterDuke i think that's why i'm only going to store a hash entry, not it's value 14:30
though right now i'm getting: `src/jit/x64/emit.dasc:2126: error: bad operand mode in `mov x?,x?': | mov WORK[dst], OBJECT:TMP1->value;` 14:31
nine MasterDuke: TMP1 is no OBJECT 14:40
It's an MVMHashEntry
MasterDuke yeah, i made that change. moarvm now compiles, but i'm getting the occasional segv 14:41
nine timotimo: I'm reasonably sure that my plan is correct, though jnthn may still veto on the grounds that we may not want to fulfil the assumptions I made
timotimo storing a hash entry into a spesh slot sounds like a very bad idea, is that what you're doing? 14:42
MasterDuke yep. seems to work
well, sometimes it works. other times i get a segv or `MoarVM panic: Internal error: invalid thread ID -1071437992 in GC work pass` 14:43
nine Oh, seems like spesh slots are for MVMCollectables only
But....it actually doesn't have to be a spesh slot. Since it's not garbage collected, you may as well use the pointer to the MVMHashEntry as a literal 14:44
It won't change, that's the whole point.
It can only be free'd if the whole HLL disappears, in which case the code that has that pointer baked in would have to be gone, too 14:45
timotimo so is the MVMHashEntry kept around when the hash gets resized? 14:46
nine As well as I understood the macro soup, yes
MasterDuke hm, something doesn't like that change 14:50
timotimo may be easier to introspect the addresses in a live hash in gdb 14:52
MasterDuke this is what i have so far gist.github.com/MasterDuke17/fa730...ee8fa993ef 14:55
but i just realized it shouldn't be sslot in the oplist 14:56
nine No, it's a int64 literal
timotimo don't forget a use_facts 14:57
MasterDuke hm. should it be `ins->operands[1].lit_i64 = entry;` or `sym_facts->value.i = entry`? 15:00
nine I'd say ins->operands[1].lit_i64 15:01
Though they are not mutually exclusive. Both make sense actually 15:02
The code's missing a few error checks (hash and entry != NULL) and needs to mark the thread as blocked before taking the lock 15:04
MasterDuke well either by themselves or both and i still get a segv
i thought we could assume hash would not be null since this wouldn't be the first time we see it? 15:06
nine It's extremely unlikely, but not guaranteed. If there's a language that doesn't use hll syms much and you have hot code like sub i'm-hot() { if $++ > 1000000 { nqp::getcurhllsym("foo") } } then it's possible the getcurhllsym has never been run when we spesh 15:08
MasterDuke ah 15:09
nine Won't happen, but it's just more correct to check
MasterDuke in the asm?
nine No, check in optimize_getcurhllsym and just bail on the optimization if you don't get a hash - it's an unrealistic scenario anyway 15:10
MasterDuke same with entry? 15:15
nine yes
That's actually much more likely to return a negative result 15:16
MasterDuke gist updated. still segvs 15:20
15:21 zakharyas joined
MasterDuke do i need a size on any of my movs? 15:22
oh, think i got it now 15:24
nine what was it?
MasterDuke heh. nope. now it's back to usually working, something a panic
but i changed to `MVMint64 entry = ins->operands[1].lit_i64; | mov64 TMP1, entry;` 15:25
nine You don't need the mov64, plain mov will do the right thing according to the register you use 15:26
But of course, lit_i64 is the right thing
Also make sure no now invalid facts remain 15:27
MasterDuke MVM_spesh_usages_delete_by_reg?
i backed out the mov64, but now it's segv all the time, 15:29
yep, that makes a big difference
nine ??? 15:31
No idea what the rules are then... There are 655 mov in emit.dasc vs. only 14 mov64 15:33
MasterDuke well, just build nqp and rakudo 15:34
nqp tests pass
but a couple fails in spectests 15:39
nine: oh, you mentioned "needs to mark the thread as blocked before taking the lock". MVM_hll_sym_get doesn't do that, but do we need to because we're in a special spesh thread? 15:48
nine The way I see it that's actually a bug in MVM_hll_sym_get. If 2 threads enter that function and the HLL hash doesn't exist and allocating that hash triggers a GC run, we end in a dead lock. 15:50
Because the thread waiting for the lock doesn't let other threads steal it's GC
MasterDuke ah. btw, the segv i'm getting is in my interp.c implementation of sp_getcurhllsym
oh, i removed an operand 15:52
nine Shouldn't that be cur_op += 4;?
15:52 AlexDaniel left
MasterDuke yeah, just made that change. same error though 15:52
nine what causes the segfault? Should be easy to see in gdb
MasterDuke GET_REG(cur_op, 2).i64 is 0 15:53
nine But...you now protect against exactly that? 15:54
MasterDuke yeah...
nine does the spesh log shine any light on this? 15:56
MasterDuke huh. it's not segfaulting if i log... 15:58
it has `sp_getcurhllsym r12(2), liti64(94107760500576) # [000] specialized from getcurhllsym` in the after of DYNAMIC
nine that looks quite ok 16:00
If you run with spesh log in gdb, can you look at that value if it actually points to an MVMHashEntry? 16:07
16:16 sena_kun joined 16:18 Altai-man_ left 16:22 zakharyas left 16:26 zakharyas joined
MasterDuke hm, in gdb with a spesh log it doesn't end up in interp.c 16:27
nine Of course not. That would be too easy now, wouldn't it?
MasterDuke same thing with some of the other test files that failed. segv without a spesh log, no segv with a spesh log 16:29
oh, one did just segv with a spesh log
`(gdb) p *(MVMHashEntry *)93825016168416$2 = {value = 0x555557cef4d8, hash_handle = {tbl = 0x555555ba26f8, hh_next = 0x0, key = 0x555555e9e170, keylen = 0, hashv = 6044822457095861110}}` 16:33
but still segv in interp.c 16:34
nine does *(MVMObject*)((MVMHashEntry *)93825016168416)->value look sensible? 16:35
MasterDuke `(gdb) call MVM_string_utf8_encode_C_string(tc, ((MVMHashEntry *)93825016168416)->hash_handle->key)$4 = 0x555560c4e390 "GLOBAL"`
`$5 = {header = {sc_forward_u = {forwarder = 0x100000016, sc = {sc_idx = 22, idx = 1}, st = 0x100000016}, owner = 1, flags = 17, size = 24}, st = 0x555558208520}`
nine Yep, that's definitely correct 16:36
So...how comes it has a correct value according to the spesh log, but no longer when interpreting the byte code?
MasterDuke so my optimize_getcurhllsym is probably correct, but there's something wrong with my asm? 16:37
nine is the gist up to date? 16:40
Does it work when the JIT is disabled? 16:44
Not sure if it should be .type MVMHASHENTRY, MVMHashEntry or .type MVMHASHENTRY, MVMHashEntry*
MasterDuke updated the gist just to be sure it has exactly what i'm running now 16:46
nine So does it work with JIT disabled? 18:15
18:16 Altai-man_ joined 18:18 sena_kun left 18:22 discord6 left, raku-bridge joined, raku-bridge left, raku-bridge joined
MasterDuke nope 18:48
same segv 18:49
19:08 zakharyas left 19:16 farcas1982regreg left
MasterDuke and still a valid MVMHashEntry pointer in the spesh log 19:27
but GET_REG(cur_op, 2).i64 is 0 19:28
nine Does a call MVM_dump_bytecode(tc) at that position show any light on the issue? 19:29
MasterDuke uh, i think that segfaulted 19:46
yeah
recompiled with optimization off. still segv, but slightly different 19:58
speshlog say pointer is 93825016043664. GET_REG(cur_op, 2).i64 is 137438953554
20:17 sena_kun joined 20:18 Altai-man_ left 20:23 zakharyas joined
MasterDuke is it something about the facts? am i not correctly deleting usage or using facts? 20:30
nine So, no chance of getting a MVM_dump_bytecode? That would tell us what the bytecode really looks like, as the spesh log doesn't seem to tell the full story 20:31
MasterDuke oh, that worked with this unoptimized build
nine can you gist? 20:32
MasterDuke gist.github.com/MasterDuke17/98198...14a3b6d124
nine But, but, but, that still shows the 93825016038512? 20:33
MasterDuke same value as in the spesh log
nine And you have checked *(MVMObject*)((MVMHashEntry *)93825016038512)->value to be sensible
MasterDuke $1 = {header = {sc_forward_u = {forwarder = 0x100000016, sc = {sc_idx = 22, idx = 1}, st = 0x100000016}, owner = 1, flags = 2065, size = 24}, st = 0x55555898cfb0}
nine You haven't deleted usage of the string constant, so spesh didn't delete it. But that won't cause any trouble. 20:34
MasterDuke that's not what `MVM_spesh_usages_delete_by_reg(tc, g, ins->operands[1], ins);` does?
nine Maybe MVM_SPESH_CHECK_DU tells us something 20:35
oh...you did
And GET_REG(cur_op, 2).i64 is NULL in gdb?
MasterDuke $1 = 36426291347713 20:36
if i set MVM_SPESH_CHECK_DU should i expect some output somewhere? 20:39
timotimo only if things are wrong 20:49
MasterDuke ok. there wasn't any output 20:52
nine MasterDuke: what do the other work registers look like? Is the value anywhere to be found? 20:54
20:56 zakharyas left
nine Wait a minute....is the value actually expected to be in a work register at all? How do constants work? 20:56
MasterDuke well, extend_u8 is `GET_REG(cur_op, 0).u64 = (MVMuint64)GET_REG(cur_op, 2).u8` 20:57
nine All ops that take literals do so with code like this: MVMuint64 idx = MVM_BC_get_I64(cur_op, 4);
There's surely a difference between literals and native values in registers 20:58
Does MVM_BC_get_I64(cur_op, 2) yield the value?
MasterDuke yes. yes it does
nine Ah, finally....should have realized this so much sooner :/ 20:59
MasterDuke hm. but i'm still getting a segv. and how there's no backtrace 21:01
jit still disabled 21:02
nine cur_op += 10 21:05
2 bytes for the opcode + 8 bytes for the actual literal value
MasterDuke and how that test file passes 21:06
*now
nine Usually an op consists of the opcode + the 16 bit indices into the WORK array for the arguments, that's why we increment cur_op with some multiple of 2.
MasterDuke time to try nqp+rakudo rebuild and full testing again
nine and a benchmark :)
MasterDuke nine++ i've learned a bunch doing this
nine Oh, does the JIT work as well now?
probably does 21:07
MasterDuke yep
`my $o; $o := $*OUT for ^1_000_000; say $o` takes ~1.14s before, ~0.98s after (rough numbers) 21:08
timotimo wow 21:09
lizmat MasterDuke++ 21:10
nine Nice work! :) 21:17
MasterDuke all tests pass
i still have both `ins->operands[1].lit_i64 = entry;` and `sym_facts->value.i = entry;`. are they both required and/or useful? 21:18
nine I think so 21:19
MasterDuke k 21:20
anything else to do or clean up before pushing a commit? and should i just rebase this over the first commit? 21:21
does this look correct based on the newly changed implementation? `(template: sp_getcurhllsym (^getf (copy $1) MVMHashEntry value))` 22:08
22:16 Altai-man_ joined 22:18 sena_kun left
MasterDuke i'm off to sleep, hopefully will get these last questions cleared up and a finalized PR ready tomorrow 22:39
also, any reason not to do the same thing for gethllsym (assuming MVM_SPESH_FACT_KNOWN_VALUE for both sets of facts)? 22:41
22:54 Kaiepi joined 23:01 Altai-man_ left 23:58 raku-bridge1 joined, raku-bridge1 left, raku-bridge1 joined