-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How should we handle print statements in Stan code? #93
Comments
Note: Julia's behavior is strictly better than Python's here, since their built-in
So without us doing anything, print statements in Stan work just like print statements in Julia natively. Python's library function of the same name does not behave the same, so there would be different behavior between print statements inside Stan and those inside Python. |
Related: Any handling (including Julia's mentioned above) is predicated on Stan's print statements properly flushing the stream they're printing to. Currently they do not, see stan-dev/stanc3#1301 If for some reason that PR does not go through, we could flush cout as part of BridgeStan, but I'd like to avoid that if at all possible. |
It might also be an option to allow users of the C Api (ie the language bindings) to add a function that handles messages that stan want to print. There could be a function The python interface could get a function that prints to the python stderr from the python c api: pythonapi = ctypes.cdll.LoadLibrary(None)
PySys_WriteStderr = pythonapi.PySys_WriteStderr
PySys_WriteStderr.argtypes = [ctypes.c_char_p]
PySys_WriteStderr.restype = None
PySys_WriteStderr_ptr = ctypes.cast(PySys_WriteStderr, ctypes.c_void_p).value I'm pretty sure something like this could be done for julia as well? Also, maybe a lock is necessary to protect handle_msg_callback. |
It seems like that’s a reasonable thing to do. I found at least one example of someone doing that, here: http://videocortex.io/2017/custom-stream-buffers/ The requirement to have a mutex for the function pointer would be slightly annoying, but I think we’re assuming most performant Stan program won’t have print statements anyway, it’s primarily for debugging and that sort of thing. You could definitely do something similar from Julia, but there’s not really any need for it since Julia just “does the right thing”, and I don’t think we could do it from R. So it’s a question of if we’d want to implement it just for our Python bindings |
Here's an existing Python library which does this: https://github.com/minrk/wurlitzer. It's using the same tricks we would if we were doing it purely from the Python side, and as a result confirms that this doesn't quite work on Windows (but they have an open PR to add support) It even supports @bob-carpenter's main use case, which is re-directing stdout and stderr to a jupyter notebook automatically with I don't think we'd do much better than that, so I'm personally happy to point users who need C stream redirection inside Python to them |
I put together something based on your callback suggestion and the above blog post @aseyboldt: It's definitely not ready for prime time, just wanted to confirm it would work (and it does!). Making the output stream a part of the model object seems like a bad idea (in particular, it makes all the log_density methods non- |
I like that we don't have to |
This would be pretty nice to have. |
Unlike Rust, C++ mutex's don't hold any object specifically. So the model object would need to have (seperately) a mutex and a pointer to the ostream, and that pointer needs to be passed in a non-const fashion to every usage. We could cast away that const, but that always makes me feel dirty. Even if we could structure it how we could it Rust, also means every call which could print - namely all the If we wanted to deal with callbacks which aren't thread safe, I think the right place to lock is inside the streambuf, during the xputsc and overflow functions. This goes against the common advice of locking/unlocking a mutex as few times as possible, but for our use case it has the big advantage that models which never write to the ostream never need to contend for a lock. That still requires a non-const ostream pointer though |
+1 |
You are right, it seems I didn't think this through... And good point about the GIL making the python function safe anyway. |
At this point my branch for this (https://github.com/WardBrian/bridgestan/tree/feature/print-callback-from-python) has the callback protected by a mutex and is hooked up to the Python interface and tested. It won't really work until Stan 2.32 is out and we've updated BridgeStan to use it, because of stan-dev/stanc3#1301, which is why I haven't opened a PR yet. |
Also forking off from #90.
Right now
print
statements in Stan end up getting sent tostd::cerr
unconditionally. Two things about thisstd:cout
sys.stdout
and C/C++'sstdout
are not necessarily the same, the former does not even need to point to a valid file descriptor but could be a class. Unifying Stan'sprint
statements with this language-specific behavior is tricky, though there are known tricks like what @bob-carpenter links to here: Improved error handling in the C API #90 (comment)This is in many ways trickier than error messaging, since it is much harder to have it be zero-cost when you don't need it (the various redirection tricks you can use in Python all have a cost even if you never print anything. One potential solution is to have it be opt-in behavior, where you could write code like:
The text was updated successfully, but these errors were encountered: