freenode/#clasp - IRC Chatlog
Search
14:21:24
drmeister
I got clasp building against llvm12 pulled last night with Lang’s new changes for jitlink and linux.
14:21:54
drmeister
Testing it failed on Linux so I sent him the module and object file that broke it.
14:22:27
drmeister
Currently in the future branch aclasp and bclasp build and run. Cclasp is broken.
14:24:08
drmeister
I’ll implement the new code gcing and then I’ll fix backtraces and then I’ll tackle cclasp
14:43:00
drmeister
Bike - backtraces are broken. The name of the functions in the backtraces are wrong. I’ll dump and example.
14:43:43
drmeister
It means the function that takes a return address and returns a function name is broken - right?
14:50:46
Bike
this is in your branch, right? maybe the template stuff you put in involves actual pointers
14:52:52
drmeister
Going forward we should have just two ways to search symbols. 1. executable/libraries 2. object files in memory from jitting, faso files and image save/load.
14:55:17
drmeister
operating_system_backtrace calls the operating system 'backtrace(buffer,num)' facility.
15:09:55
drmeister
We create a std::vector<BacktraceEntry> - BacktraceEntry is a low level C++ object, not exposed to Common Lisp. We fill it with everything that we can get.
15:10:34
drmeister
Then we copy the info into Frame_O objects, cons up a list of them and pass them to a callback using (core:call-with-backtrace ...)
15:11:09
drmeister
That way it's clear what is in the backtrace. Everything above the callback is in the backtrace and everything below it is not.
15:14:15
drmeister
I broke up gc_interface.cc into 8 files and astExpose.cc into two. It shaves several minutes off the C++ build.
15:28:59
drmeister
Object file maintenance is tied up in what I'm doing here - so it's not surprising that I broke somethign.
15:34:21
drmeister
Ah - it's getting the name out of the FunctionDescription_O - and those are also broken.
15:36:08
drmeister
Then we use that to look up the function description and pull the name out of that.
15:39:15
drmeister
https://github.com/clasp-developers/clasp/blob/future/src/llvmo/debugInfoExpose.cc#L510
15:39:43
drmeister
And that will take a return address and should return a bunch of info about the function from the very roundabout path through the object file.
15:45:06
drmeister
We need to make FunctionDescription_O objects literals so they can be saved and reconstituted by the literal compiler.
15:50:41
Bike
"In the case of exact garbage collection, yieldpoints are known as GC-safe points" yeah, ok.
15:56:23
drmeister
--verify-safepoint-ir , --rewrite-statepoints-for-gc , --strip-gc-relocates , --place-safepoints
15:57:08
drmeister
There's a thing in llvm where you can use address-space(1) for certain pointers and the --rewrite-statepoints-for-gc does something to them with yieldpoints that makes them gc roots.
15:57:29
drmeister
Now - we can't get that for C++ code I don't think - but it would be good to understand it.
16:00:36
drmeister
Anyway, yieldpoints are what Steve Blackburn calls them and they are integral to MMTk.
16:01:13
drmeister
In MPS there is a complicated song and dance for allocations that avoids the problem of scanning incompletely initialized objects.
16:01:38
drmeister
Boehm doesn't care - it will scan anything in the conservative mode and I still don't see how the precise mode is supposed to work.
16:08:28
drmeister
I was surprised by this in the paper: "We find that Java benchmarks execute about 100 M yieldpoints per second,"
16:08:49
drmeister
I was always afraid that the impact on performance would be high - but if Java can support this then it can't be that bad.
16:10:07
drmeister
Thinking about yieldpoints - they could enable other things like truly lock free data structures.
16:10:57
drmeister
If I can pause each thread when I can guarantee that not one of them is in a certain block of code - then I could fix up data structures so that they could always be read lock free.
16:13:27
drmeister
But I could represent it as a hash-table and an atomic linked list of fixups that at certain yieldpoints would be applied to the hash-table.
16:16:08
drmeister
Pause the world when we can be sure that certain data structures are not actively being altered, fix them up and then set the world in motion again.
16:34:06
docl
drmeister: I know this is a little off topic here but just wondering your opinion, is artificial photosynthesis by spiroligomer photocatalyst decades away, or has the foundation already been laid? I note there are competing approaches in this realm already, e.g. nanowire photocatalysts https://patents.google.com/patent/US9528192B1/en
16:36:10
docl
I'm a little skeptical of the nanowire approach being cost effective for large areas. ideally you'd have something that can go over large cropland areas or maybe big ponds akin to solar salt production facilities
17:09:02
drmeister
Bike: I think with pausing the world you can control how often you do it with a lot of control./
17:09:56
drmeister
We would add an atomic linked list of hash-table 'fixups' like an a-list that gets searched alongside the hash-table.
17:10:36
drmeister
So to write to the hash-table you push a #<hash-table-write key value> onto the atomic fixup list.
17:11:41
drmeister
GETHASH would then check the hash-table and the fixup list - this would be lock free.
17:12:08
drmeister
You don't want the fixup list to get too long because it's linear time to check it.
17:12:42
drmeister
Occasionally, when you know that no thread is reading the hash-table you pause, apply the fixups to the hash-table and clear the fixup list.
17:13:31
drmeister
We can control how long we let the fixup list grow before you want to pause and fix hash-tables.
17:14:01
drmeister
The implementation of the fixup list would probably be a vector for faster reads.
17:14:49
drmeister
Oh - you know what - you can' use a vector - because that can't be updated atomically without a mutex.
17:15:33
Bike
you can update a vector atomically. you just atomically increment the fill pointer, then store whatever at the old index. right?
17:16:23
Bike
i guess there'd be another problem if another thread is simultaneously reading the vector up to the fill pointer, and gets the uninitialized entry
17:17:29
drmeister
Hmm, I'll have to think about that. The atomic linked list is definitely safe and flexible.
17:18:06
drmeister
You could keep a pool of cons cells to draw from to add to the atomic linked list.
17:19:07
drmeister
So (setf gethash) would grab a cons cell and a fixup record from a pool and fill the fixup record and push it to the head of the atomic fixup list.
17:20:27
drmeister
The yieldpoints would check a bitmap of different kinds of yields against a thread local bitmap of what yields are permitted.
17:21:04
drmeister
Then we would have suppress-yield and allow-yield calls that would modify the thread-local bitmap of yields that are allowed.
17:24:31
Bike
those kind of worklist things are usually how wait-free algorithms work (i think) but they don't need safepoints
17:25:21
drmeister
We already have safe points - we check a global variable to see if a signal handler has been activated.
17:26:30
drmeister
If you don't have safepoints - you use signals? If you use signals - you have to poll occasionally (at a safepoint) to see if a signal came in.
17:30:08
drmeister
Ok - I think we can put this on a firmer foundation. Can you take a look at the safepoint/yieldpoint injection pass in llvm?
17:30:56
drmeister
You could generate a .ll file using compile-file and then run the pass on it with opt --place-backedge-safepoints-impl
17:31:18
drmeister
Then what does it look like in the new llvm-IR and what does it look like in the disassembled object file.
17:31:49
drmeister
I added a facility to dump every JIT generated object file to /tmp/ one after the other.
17:32:19
drmeister
I can do the same with modules and then absolutely everything the compiler generates can be inspected.
17:45:16
drmeister
They are mostly straightforward - like pathname literals - but they have a twist.
17:45:42
drmeister
They contain function entry points (currently only one) and a ObjectFile_sp tagged pointer.
17:45:50
drmeister
The ObjectFile_sp will be the same for every FunctionDescription_O in the current object file.
17:46:32
drmeister
I think I can get the ObjectFile_sp from a thread local slot that stores the current ObjectFile_sp that is being load-time evaluated.
17:48:45
drmeister
https://github.com/clasp-developers/clasp/blob/future/include/clasp/core/functor.h#L82
17:49:48
drmeister
I have all of the function entry points in a vector within the Module - so I can reference them using an integer.
17:51:47
drmeister
I think I need to set up a call to a function like ltvc_make_function_description that is like ltvc_make_pathname
17:51:48
drmeister
https://github.com/clasp-developers/clasp/blob/future/src/llvmo/link_intrinsics.cc#L396
17:52:49
drmeister
It will take an integer argument for each entry point function and no argument for the ObjectFile_O object because it will get it from a thread local slot.
17:53:28
drmeister
The rest of the info like sourcePathname, functionName, lambdaList, docstring, lineno, column, filepos - those will all be regular literals.
17:54:06
drmeister
I could argue that I don't need some of these because they are made redundant by pulling the info out of the DWARF metadata.
17:54:50
drmeister
multiple entry points will be handled in the future by adding more integer arguments, one for each entry point.
18:23:52
Bike
i think the problem was that sometimes we get an offset, and sometimes we get a lineno + column
18:24:38
drmeister
Oh wait - it is redundant. This is the filepos of the function itself. Most of the time we need the filepos of a return address - that we only get from DWARF - and there all we get is what is in the line tables.
18:26:43
drmeister
Is it the case that we get the offset only from the FunctionDescription objects. If we got rid of filepos maybe that would be best?
18:27:01
drmeister
As in filepos is a complicating feature that doesn't bring a lot of value. Adds complexity with little value.
18:27:08
Bike
mostly i remember that we really should have one single structure representing source pos info
18:27:46
drmeister
Ok and DWARF kind of makes our choice for us - lineno+column is what DWARF gives us.
18:28:58
Bike
for example swank's compiler-condition class has a "location" that i think has to be the offset
18:40:47
Bike
https://github.com/slime/slime/blob/master/slime.el#L3353-L3358 i guess this is what we have. so lineno column is fine. maybe.
19:20:29
kpoeck
drmeister Earlier today you said "- we check a global variable to see if a signal handler has been activated. ". Could you point me to that code? As Bike mentioned, at least fpe handling seems to be delayed and I would like to look into that.
19:24:08
drmeister
kpoeck: I think it's in the gcalloc.h file - every call to handle_all_queued_interrupts();
19:24:57
drmeister
https://github.com/clasp-developers/clasp/blob/master/src/gctools/interrupt.cc#L209
19:29:05
drmeister
The queue_signal_or_interrupt is what adds a handler to the thread local list of interrupts to handle.
19:29:56
drmeister
Yeah - and that gets called from handle_or_queue_signal and that is a signal handler.
19:31:18
drmeister
So a thread gets a signal, handle_or_queue_signal is called. That may handle it or it pushes an interrupt onto the current threads list. Then handle_all_queued_interrupts gets called after almost every allocation to handle any interrupts that came in asynchronously.
19:32:14
drmeister
https://github.com/clasp-developers/clasp/blob/master/src/gctools/interrupt.cc#L252
19:33:07
drmeister
I think this means we are invoking our code from a signal handler - I think this is dangerous. Maybe we do it properly - maybe we don't.
19:34:20
drmeister
My understanding is that there is very little that we are allowed to do in a signal handler.
19:35:15
Bike
yeah so the problem is we kind of have to unwind out of them to use them for conditions.
19:36:21
drmeister
We can't unwind out of them is my understanding. Unix signals and C++ exceptions are fundamentally incompatible.
19:37:00
drmeister
What we can do is insert yieldpoints in the code and check if a signal came in and then unwind from there.
19:38:00
drmeister
Hmm then there are problems with threads. Does the thread that generated the FPE get the FPE signal?
19:44:15
drmeister
Then we should be able to add a thread-local flag that an FPE occurred and inject a test for that into the arithmetic code.
19:48:07
Bike
if we wanted to check flags on every single floating point operation we could turn off the signal handling and do that
20:45:55
Bike
also if we leave NaNs around or want particular rounding i think it really is every operation
20:48:04
kpoeck
for an fpe, we run directly this: https://github.com/clasp-developers/clasp/blob/master/src/gctools/interrupt.cc#L316
20:50:41
Bike
i looked it over and as far as i can tell, sbcl does unwind out of signal handlers and that works fine for it
20:51:39
Bike
because the exceptions library does all kidns of goofy shit that probably not reentrant
20:52:23
drmeister
sbcl doesn't use C++ exception handling - it may be leaving something in the stack frames to let them unwind out of a signal handler but from everything that I've been told we cannot do this with C++ exception handling.
20:53:16
Bike
i don't really understand why unwinding out of a signal handler in particular is not allowed. longjmp ought to work, i think
20:54:07
Bike
assuming longjmp is reentrant i guess. maybe all the dumb shit stuffed into jmp_bufs makes that hard
21:00:03
drmeister
A signal can happen between any two instructions - right? Is the stack frame that the signal handler sets up able to synchronize with the itanium unwinding machinery.
21:03:07
Bike
my impression was that within a handler you still have, like, a normal stack with frames and everything
21:03:25
Bike
above your handler function is whatever operating system machinery, and then above that is the frame of the function that was running when the signal interrupted
21:07:58
kpoeck
apart from what are discussing, I believe we have 1 more issue. Just try (mod 1 0) in clasp, sometimes, we get the fpe, sometimes clasp hangs with 99,9% cpu in core::clasp_truncate. lldb knows that an exception happens, but handle_fpe is not called.
21:10:43
Bike
"the main problem with unwinding is dlopen and dlclose" i really hate the C++-brain on this topic, man
21:13:17
drmeister
I don't have the mental bandwidth to follow the whole talk - but there may be something about signal handlers in there.
21:21:03
Bike
looking through stack frames and stuff is no problem. so in a lisp-style unwinding setup, unwinding would be no issue, since all the cleanup and destination info is on the stack. on the other hand, getting the corresponding dwarf info from disc/wherever is not signal safe
21:21:30
Bike
i guess if we like, receive a signal in the middle of dl_iterate_phdr, or something weird like that
21:28:03
Bike
my understanding though is that this stuff should be less of a problem for _synchronous_ signals like sigfpe, which is after all signaled at only particular places (where we do a floating point operation)
21:41:18
drmeister
Does the unwinding happen with a library that we can get debug information for on linux?
22:02:20
Bike
i could try. at the moment it's just crashing outright instead of just signaling weird errors like it used to, though
22:14:32
Bike
and then if you try to abort you get the same out-of-extent-unwind so you're stuck in the debugger forever.
23:12:39
drmeister
Do we need to be able to get the declarations for a function from the function-description?