cfbolz changed the topic of #pypy to: #pypy PyPy, the flexible snake https://pypy.org | IRC logs: https://quodlibet.duckdns.org/irc/pypy/latest.log.html#irc-end and https://libera.irclog.whitequark.org/pypy | insert pithy quote here
Corbin has joined #pypy
_0az has quit [Read error: Connection reset by peer]
_0az has joined #pypy
_0az has quit [Read error: Connection reset by peer]
_0az has joined #pypy
_0az has quit [Remote host closed the connection]
_0az has joined #pypy
lritter has joined #pypy
lritter has quit [Ping timeout: 255 seconds]
smarr has quit [Quit: Connection closed for inactivity]
[Arfreve1] has quit [Quit: leaving]
[Arfrever] has joined #pypy
kor1 has quit [Quit: Leaving.]
smarr has joined #pypy
otisolsen70 has joined #pypy
<mattip> here is a writeup of my efforts to whittle down the numpy + win64 + pypy segfault to something workable
<mattip> bottom line: a struct is being passed into a function but ends up being zeroed out
Julian has joined #pypy
Julian has quit [Quit: leaving]
<cfbolz> mattip: wow
<cfbolz> mattip: lots of sleuthing
<cfbolz> mattip: the GC does not start threads, btw
<cfbolz> mattip: another random thought: the struct is passed not as a pointer? is it really passing the struct as an argument to the function?
<cfbolz> if yes, that makes me suspicious, passing structs directly is very different depending on the calling convention maybe?
Julian has joined #pypy
<mattip> it is all inside the same compilation unit (file), so should be consistent with itself
<mattip> btw, no AVX512 needed, that specific reproducer crashes on my older machine
<cfbolz> right
<antocuni> mattip: what is the line which prints "14 14616" in your example?
<antocuni> ah ok, it's in the python code
<antocuni> mattip: with gdb, there is a way to put a hw watchpoint and immediately interrupt the execution of the program as soon as a specific variable changes
<antocuni> maybe you can try to use it and see who is that writes zeros in the struct
<mattip> antocuni: in the caller (the external function), the variable is optimized out, so I don't see it in the debugger,
<mattip> and as far as I can tell it is a different address in each invocation of the caller
<antocuni> yes, but you should see it inside the called function
<antocuni> you can put a breakpoint when you enter ufunc_generic_fastcall
<antocuni> and then put a watchpoint on full_args.in
<antocuni> or a "location watchapoint" on &full_args.in (I don't know what is the visual studio jargon for that)
<antocuni> actually, the equivalent of watch -l &full_args.in is preferable, since it should work even if it's changed outside the function
<mattip> I cannot "see" full_args in the debugger, it is optimized out. Only inside of PyUFunc_GenericFunctionInternal can I see it in the debugger
<antocuni> print the address, then
<antocuni> printf("%p\n", &full_args.in)
<antocuni> and then you put a breakpoint
<antocuni> and then you tell visual studio to break whenever the memory at that location changes
* mattip trying
<mattip> that is basically what I did with patch, I sprinkled printf statements all over and came to the conclusion that it changed at the function call
<mattip> but that doesn't make any sense to me
<antocuni> yes, but if you can convince the debugger to break on the very specific moment that someone writes to the memory, you should be able to at least know who is writing to it
<antocuni> "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, [...]. Structs or unions of other sizes are passed as a pointer to memory allocated by the caller."
<mattip> every invocation of the function the address changes, so I need to reset the breakpoint for each iteration, and it only happens after a couple thousand iterations
<mattip> randomly
<antocuni> ah ok :(
<antocuni> years ago I wrote a hack for gdb which allowed you to set watchpoint from within the debugged program, but I have no idea if/how to do that with visual studio
<mattip> the strange thing is - it is only this specific use pattern:
<mattip> in the setup code of a ufunc when calling += on a view of an array
<mattip> at least that is what I have so far, any other simpler case does not segfault
<antocuni> I agree that it's all very weird
<mattip> well, any other simpler case I can contrive so far
<antocuni> the fact that it happens only with the JIT suggests that the JIT is the culprit, but I can't imagine how
<mattip> just what I was going to write :)
<antocuni> if I interpret correctly the calling convention which I linked above, passing a 128bit struct is equivalent to allocating the struct on the caller stack and pass a pointer to the callee
ronan_ has joined #pypy
<antocuni> i.e., something like that: https://paste.opendev.org/show/807528/
dustinm- has joined #pypy
Julian has quit [Ping timeout: 258 seconds]
jerith_ has joined #pypy
<antocuni> so, if the culprit is the JIT, it means that the JIT is randomly overwriting the stack of a C function, which looks unlikely, else everything else would crash
raek1 has joined #pypy
<antocuni> mattip: did you try to compile with the equivalent of -O0?
atomizer_ has joined #pypy
ronan has quit [Ping timeout: 255 seconds]
<mattip> yes, even removing the `/GL` and `/LTCG` flags is enough to make it pass
<mattip> as is changing the signature to a pointer
<mattip> from ufunc_full_args full_args
<mattip> to from ufunc_full_args *full_args
<mattip> to ufunc_full_args *full_args
Corbin has quit [*.net *.split]
atomizer has quit [*.net *.split]
stkrdknmibalz has quit [*.net *.split]
jerith has quit [*.net *.split]
raek has quit [*.net *.split]
dustinm has quit [*.net *.split]
Ninpo has quit [*.net *.split]
jerith_ is now known as jerith
<mattip> I tried editing the stack size with editbin /STACK ...,
<mattip> that did not clear the segfault
<mattip> I will edit the hackmd with a "things I tried" section
Ninpo has joined #pypy
Corbin has joined #pypy
<antocuni> mattip: fwiw, I played a bit with this code on linux64+gcc (I don't have windows)
<antocuni> if sizeof(MyStruct)==16, the struct fields are passed in two registers (as if they were two different variables)
<antocuni> if I uncomment "long c" and sizeof(MyStruct) becomes 24, the struct is actually passed by value for real
<antocuni> i.e., the memory is allocated in the caller, and a pointer to it is passed to the callee
<antocuni> note that in the 2nd case, foo:s is clearly allocated in the stack of main
<antocuni> which is what it should happens on windows as well
<antocuni> I don't know if it's useful or not for your investigation, but it might be worth trying to understand whether the address of full_args is really where you expect it to be
<mattip> at one stage I had a patch to numpy to change the function signature, but it seems like this is the kind of problem it would be good to understand before releasing it too widely
Julian has joined #pypy
<antocuni> I agree
<mattip> There is this in the calling convention document "ntrinsic functions that don't allocate stack space, and don't call other functions, sometimes use other volatile registers to pass additional register arguments. This optimization is made possible by the tight binding between the compiler and the intrinsic function implementation."
<mattip> but the function in question definitely has stack arguments and calls other functions
<antocuni> yes but I don't think you are using any intrinsic function, aren't you?
<antocuni> I think that "intrinsic functions" are things like __builtin_frame_address & co., i.e. not functions that you write
<mattip> ok, gotta go. Please let me know if you have more ideas
<antocuni> ok
raek1 is now known as raek
Julian has quit [Quit: leaving]
ambv has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
ambv has joined #pypy
ronan_ is now known as ronan
otisolsen70_ has joined #pypy
otisolsen70 has quit [Ping timeout: 252 seconds]
stkrdknmibalz has joined #pypy
otisolsen70_ has quit [Read error: Connection reset by peer]
otisolsen70_ has joined #pypy
kor1 has joined #pypy
ambv has quit [Quit: Textual IRC Client: www.textualapp.com]
Jin^eLD has joined #pypy
<habnabit_> so https://cffi.readthedocs.io/en/latest/embedding.html says that there will be a cffi_start_python function available.. but it seems to be declared static in the generated source file: https://paste.ee/p/o5oWv#s=0&l=1281
<habnabit_> is the function meant to be exported? or how is it meant to be used?
<Jin^eLD> to add to the above (its actually me who ran into the issue), I managed to wrap cffi_start_python() in set_source() like this: https://paste.ee/p/8hwZ0 and that seems to be a workaround that does the trick
<Jin^eLD> it would still be interesting to learn how this was meant to be used?
<LarstiQ> habnabit_: it also says "In case you need to force, from C code, Python to be initialized before the first @ffi.def_extern() is called,", if that is not the case I would ignore it
<Jin^eLD> LarstiQ: it was actually the case, because my Python code was subscribing to a callback in C, but the Python code never gets run if you don't need to call any @ffi.def_extern() function from C
<LarstiQ> aha
<Jin^eLD> so I wanted a controlled point in time to get python started, I first achieved that with a workaround of defining a dummy @ffi._def_extern() function and doing a C->Python call to trigger initialization, but that seemed hacky
<LarstiQ> right
<Jin^eLD> and I also appreciate the cffi_start_python() return code in the application
<Jin^eLD> so how did you guys meant for it to be used? or is it being generated as a static function a bug?
<LarstiQ> I'm just guessing based on the rest of the code in that paste, but "_cffi_call_python_org, which on CPython is actually part of the _cffi_exports[] array, is the function pointer copied from _cffi_backend." implies to me there is either a struct or some other code in the .so you'd call
<Jin^eLD> I am in the embedding scenario
<Jin^eLD> so I link the generated .c source into the application
<Jin^eLD> it was not clear to me what to call though to trigger the init
<LarstiQ> are you compiling the .c code together with the application? Then you should just be able to call `cffi_start_python` directly?
<Jin^eLD> especially since the docs clearly say you're suppose dto call the cffi_start_python() function and not something else... so that was kind of confusing
<Jin^eLD> I can't call it directly becase its generated with a static declaration by ffibuilder
<LarstiQ> that is visible within the same compilation unit though
<Jin^eLD> linker won't "see" it, even if I add an extern fwd declearation in my own sources
<LarstiQ> so compiling source together, or linking object files?
<Jin^eLD> aaah... the latter
<Jin^eLD> I dump all the ffi related stuff into a local static lib that gets linked to the rest
<LarstiQ> right, so one option then would be to have an additiona small .c to go into that lib that does the exposing-a-symbol and calling the static function?
<LarstiQ> it's ages since I've done any C work, but I believe that should work
<Jin^eLD> that'd be workaround #2, indeed
<Jin^eLD> workaround #1 is what I posted above, a non static wrapper function that gets injected into the generated sources via ffibuilder.set_source
<Jin^eLD> that works too
<LarstiQ> right, which is less hacky?
<Jin^eLD> less hacky than going via a dummy call to some extern "Python" func
<Jin^eLD> at least here you also get the return code
<cfbolz> Jin^eLD: the dummy exported python function that does nothing sounds not so unreasonable to me
<Jin^eLD> cfbolz: you don't get a return code though if initialization succeeded or not, which I find useful with cffi_start_python()
<LarstiQ> hmm, what's `PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void);`?
<Jin^eLD> but question is why is it being generated as static in the first place?
<cfbolz> right
<cfbolz> anyway, this sounds like a very reasonable feature request
otisolsen70_ has quit [Quit: Leaving]
<Jin^eLD> cfbolz: I failed to find "the official" cffi bugtracker, where would I post that feature request?
<Jin^eLD> thank you, thought it'd be something distro related like launchpad
<Jin^eLD> I'll add a request there then, thanks!
<LarstiQ> pypy (and cffi) moved to heptapod when bitbucket shut down hg support
<Jin^eLD> ah
<Jin^eLD> I was not familiar with heptapod at all
<cfbolz> it's a gitlab fork with mercurial support
* LarstiQ stares at `_CFFI_PYTHON_STARTUP_CODE`
<Jin^eLD> LarstiQ: I glanced at the generated stuff, but it seemed way too convoluted to understand :P
<LarstiQ> Jin^eLD: the feature request is definitely a good idea, I'm not sure how long I want to play archealogist ;)
<Jin^eLD> :))
<LarstiQ> hui, the _cffi_carefully_make_gil comments
<LarstiQ> I'm also wondering what the `_CFFI_UNUSED_FN` does, `__attribute__((unused))` on gcc
<LarstiQ> just for warnings it seems
<Jin^eLD> seems so, yes, probably supresses the warning if nobody calls the generated function
<Jin^eLD> added an issue, let's see what happens: https://foss.heptapod.net/pypy/cffi/-/issues/504
lritter has joined #pypy