ParrallelProcessing cannot work well on M1 Mac

Hi, I am developing an extension based on ParrallelProcessing. This extension will run a python script in another CPU core. If the process ends, the script will be run again. It works well in most cases but fails sometimes (after several loops) on my M1 Mac. The 3D Slicer window closes automatically during calculation. I tried to run it on Windows PC. It never failed and everything is well. So, I think the problem comes from Rosetta2 on M1 Mac. I first checked the last line in error log:

[Python] (/Applications/Slicer.app/Contents/Extensions-30822/ParallelProcessing/lib/Slicer-5.0/qt-scripted-modules/Processes.py:230) - Name: state: Starting, last error: UnknownError

If it works fine, the next five lines should be:

[] (unknown:0) - Name: state: Starting, last error: UnknownError
[Python] (/Applications/Slicer.app/Contents/Extensions-30822/ParallelProcessing/lib/Slicer-5.0/qt-scripted-modules/Processes.py:230) – Name: state: Running, last error: UnknownError
Python] (/Applications/Slicer.app/Contents/Extensions-30822/ParallelProcessing/lib/Slicer-5.0/qt-scripted-modules/Processes.py:244) - Name: writing input
[] (unknown:0) - Name: state: Running, last error: UnknownError
[] (unknown:0) - Name: writing input

Therefore, there is something wrong on starting, not running. The error does not come from my script, but in line 227 of Processes.py:

self.start("PythonSlicer", [self.scriptPath,])

I added two logs before and after this line and only the first one is logged correctly.

Another interesting thing is, this phenomenon depends on the script. If I change some function in my script but remain the same input and output, it will work well on my M1 Mac. However, it seems to contradict the previous conclusion.

I think the problem comes from qt.QProcess. It may be not compatible with M1 Mac. I will be thankful if an ARM version 3DSlicer is provided.

Thanks for the report. I recently got an M2 mac and I didn’t see any problems with Slicer but I didn’t try the ParallelProcessing extension. Are you able to run the SelfTests? Or can you provide an example that replicates the error? Perhaps there’s a way to catch the error and retry.

Regarding a native ARM version of Slicer it’ll probably happen at some point but I don’t know a timeline, so better to see if this can bedebugged.

Yes, I can run the test in ParrallelProcessing extension. Would you please open the Processes module, click “reload and test” and close the Slicer window after finished? The MacOS will tell you Slicer quit unexpectedly. I think it is the similar problem as I faced. Thank you.

Hmm, I’m not seeing that behavior. I ran did the Reload and Test on the Processes module with Slicer 5.0.3 on a macbook air M2 and did not get an unusual messages or crash at exit. Mine is a pretty much fresh install. Maybe you have something else installed in your Slicer python environment? You can download a new copy of Slicer and test it in isolation.

Screen Shot 2022-07-28 at 9.32.10 AM

There is no crash at exit. But after exit about 3 seconds, the MacOS system will tell you Slicer quit unexpectedly. I have uninstalled Slicer 5.0.2 (just move to trash and clean it) and installed Slicer 5.0.3. Then, I installed ParrallelProcessing and did Reload and Test. I got the same result. Maybe there are other files I haven’t deleted. Do you know how to uninstall thoroughly?
PS: I am using MacOS 12.5 and M1Pro chip.

I had macOS 12.4 before, but today it updated to 12.5 so I tested again and this time I get the same message about quitting unexpectedly. This may not be related to the OS version though, because the stack trace indicates that PythonQtShell_QProcess::event(QEvent*) is being invoked during the application destruction process.

I take this to mean that the Process python class (which inherits from QProcess) still has signal/slot connections being invoked even though the object is out of scope or partially destructed. Inheriting a Python class from a PythonQt superclass isn’t something we typically do so maybe we need to be careful with the teardown process, especially when there are signal/slot connections.

One possible solution would be to call disconnect in onFinished for all the connect calls made in __init__.

0   libpython3.9.dylib            	       0x138713f12 PyErr_Occurred + 18
1   libpython3.9.dylib            	       0x138645955 find_name_in_mro + 165
2   libpython3.9.dylib            	       0x13864581f _PyType_Lookup + 111
3   libpython3.9.dylib            	       0x138633133 _PyObject_GenericGetAttrWithDict + 131
4   libPythonQt.dylib             	       0x11626aa5a PythonQtShell_QProcess::event(QEvent*) + 106
5   QtWidgets                     	       0x10f2eca1a QApplicationPrivate::notify_helper(QObject*, QEvent*) + 266
6   QtWidgets                     	       0x10f2ede41 QApplication::notify(QObject*, QEvent*) + 497
7   QtCore                        	       0x111dbf9d4 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 212
8   QtCore                        	       0x111dea316 QObjectPrivate::setParent_helper(QObject*) + 374
9   QtCore                        	       0x111de9ebd QObject::~QObject() + 2125
10  libPythonQt.dylib             	       0x11620fab4 PythonQtSignalReceiver::~PythonQtSignalReceiver() + 212
11  libPythonQt.dylib             	       0x11620fc1e PythonQtSignalReceiver::~PythonQtSignalReceiver() + 14
12  libPythonQt.dylib             	       0x1161a78ee PythonQt::removeSignalHandlers() + 190
13  libPythonQt.dylib             	       0x1161a7805 PythonQt::cleanup() + 21
14  libCTKScriptingPythonCore.0.1.dylib	       0x10d6a612b ctkAbstractPythonManager::~ctkAbstractPythonManager() + 43
15  libqSlicerBaseQTGUI.dylib     	       0x10dbbdc7e qSlicerPythonManager::~qSlicerPythonManager() + 14
16  libqSlicerBaseQTCore.dylib    	       0x10eaec9bd qSlicerCoreApplicationPrivate::~qSlicerCoreApplicationPrivate() + 173
17  libqSlicerBaseQTGUI.dylib     	       0x10db21b1e qSlicerApplicationPrivate::~qSlicerApplicationPrivate() + 14
18  libqSlicerBaseQTCore.dylib    	       0x10eaf7ff6 qSlicerCoreApplication::~qSlicerCoreApplication() + 38
19  Slicer                        	       0x104cc4b0f main + 527
20  dyld                          	       0x204e5352e start + 462
1 Like

I went ahead and made the change I had in mind and the crash on exit is now gone on my M2 mac. @wrc can you see if this makes a difference for your issue?

It’s funny that this only showed up (that we know) on macOS with Apple processors and Rosetta but I’d guess it reveals an inconsistency in the destructor cleanup when python classes inherit from Qt classes so we should be careful anywhere we use that pattern.

1 Like