Python print not working when embedded into MPI program

2024/9/8 8:54:25

I have an Python 3 interpreter embedded into an C++ MPI application. This application loads a script and passes it to the interpreter.

When I execute the program on 1 process without the MPI launcher (simply calling ./myprogram), the script is executed properly and its "print" statements output to the terminal. When the script has an error, I print it on the C++ side using PyErr_Print().

However when I lauch the program through mpirun (even on a single process), I don't get any output from the "print" in the python code. I also don't get anything from PyErr_Print() when my script has errors.

I guess there is something in the way Python deals with standard output that do not match the way MPI (actuall Mpich here) deals with redirecting the processes' output to the launcher and finally to the terminal.

Any idea on how to solve this?

Answer

[edit, following the advice from this issue]

You need to flush_io() after each call to PyErr_Print, where flush_io could be this function:

void flush_io(void)
{PyObject *type, *value, *traceback;PyErr_Fetch(&type, &value, &traceback);  // in Python/pythonrun.c, they save the traceback, let's do the the samefor (auto& s: {"stdout", "stderr"}) {PyObject *f = PySys_GetObject(s);if (f)  PyObject_CallMethod(f, "flush", NULL);else    PyErr_Clear();}PyErr_Restore(type, value, traceback);
}

[below my old analysis, it still has some interesting info]

I ended up with the same issue (PyErr_Print not working from an mpirun). Tracing back (some gdb of python3 involved) and comparing the working thing (./myprogram) and non-working thing (mpirun -np 1 ./myprogram), I ended up in _io_TextIOWrapper_write_impl at ./Modules/_io/textio.c:1277 (python-3.6.0 by the way).

The only difference between the 2 runs is that self->line_buffering is 1 vs. 0 (at this point self represents sys.stderr). Then, in pylifecycle.c:1128, we can see who decided this value:

if (isatty || Py_UnbufferedStdioFlag)line_buffering = Py_True;

So it seems that MPI does something to stderr before launching the program, which makes it not a tty. I haven't investigated if there's an option in mpirun to keep the tty flag on stderr ... if someone knows, it'd be interesting (though on second thought mpi probably has good reasons to put his file descriptors in place of stdout&stderr, for its --output-filename for example).

With this info, I can come out with 3 solutions (the first 2 are quick-fixes, the 3rd is better):

1/ in the C code that starts the python interpreter, set the buffering flag before creating sys.stderr. The code becomes :

Py_UnbufferedStdioFlag = 1;   // force line_buffering for _all_ I/O
Py_Initialize(); 

This brings Python's traceback back to screen in all situations; but will probably give catastrophic I/O ... so only an acceptable solution in debug mode.

2/ in the python (embedded) script, at the very beginning add this :

import sys
#sys.stderr.line_buffering = True  # would be nice, but readonly attribute !
sys.stderr = open("error.log", 'w', buffering=1 )

The script then dumps the traceback to this file error.log.

I also tried adding a call to fflush(stderr) or fflush(NULL) right after the PyErr_Print() ... but this didn't work (because sys.stderr has its own internal buffering). That'd be a nice solution though.

3/ After a little more digging, I found the perfect function in

Python/pythonrun.c:57:static void flush_io(void);

It is in fact called after each PyErr_Print in this file. Unfortunately it's static (only exists in that file, no reference to it in Python.h, at least in 3.6.0). I copied the function from this file to myprogram and it turns out to do exactly the job.

https://en.xdnf.cn/q/72987.html

Related Q&A

Detecting USB Device Insertion on Windows 10 using python

I cant get the following code for Detecting USB Device Insertion to work on my Windows 10 (64 bit) computer with Python 3.7.import win32serviceutil import win32service import win32event import servicem…

I get NotImplementedError when trying to do a prepared statement with mysql python connector

I want to use prepared statements to insert data into a MySQL DB (version 5.7) using python, but I keep getting a NotImplementedError. Im following the documentation here: https://dev.mysql.com/doc/con…

parsing transcript .srt files into readable text

I have a video transcript SRT file with lines in conventional SRT format. Heres an example:1 00:00:00,710 --> 00:00:03,220 Lorem ipsum dolor sit amet consectetur, adipisicing elit.2 00:00:03,220 --…

Sphinx Public API documentation

I have a large number of python file and I would like to generate public API documentation for my project. All the functions that are part of the api I have decorated with a decorator. for example:@api…

Debugging a scripting language like ruby

I am basically from the world of C language programming, now delving into the world of scripting languages like Ruby and Python.I am wondering how to do debugging. At present the steps I follow is, I c…

Running unittest Test Cases and Robot Framework Test Cases Together

Our group is evaluating Robot Test Framework for our QA group, not just for BDD, but also to possibly cover a lot of our regular functionality testing needs. It certainly is a compelling project.To wha…

numpy.ndarray enumeration over a proper subset of the dimensions?

(In this post, let np be shorthand for numpy.)Suppose a is a (n + k)‑dimensional np.ndarray object, for some integers n > 1 and k > 1. (IOW, n + k > 3 is the value of a.ndim). I w…

How can I work with a GLib.Array in Python?

I am writing a plugin for Rhythmbox, wherein a signal raised is passing in an object of type GArray. The documentation for GLib Arrays shows me a few methods I am interested in, but am unable to acces…

Categorical dtype changes after using melt

In answering this question, I found that after using melt on a pandas dataframe, a column that was previously an ordered Categorical dtype becomes an object. Is this intended behaviour?Note: not looki…

python apscheduler not consistent

Im running a scheduler using python apscheduler inside web.py framework. The function runserver is supposed to run everyday at 9 a.m but it is inconsistent. It runs most days but skips a day once in a …