Skip to content
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

BUG: Weird interaction with other modules #42

Closed
larsoner opened this issue Feb 8, 2021 · 6 comments
Closed

BUG: Weird interaction with other modules #42

larsoner opened this issue Feb 8, 2021 · 6 comments

Comments

@larsoner
Copy link

larsoner commented Feb 8, 2021

This bit of code is adapted from two pylsl examples and just starts one thread to send samples and receives them in the main thread, works on Linux (Ubuntu 20.10, pip) as it correctly starts printing a bunch of random samples:

import time
from multiprocessing import Process
from random import random as rand

from pylsl import StreamInfo, StreamOutlet, local_clock, resolve_stream, StreamInlet
import scipy.fft


def _send():
    info = StreamInfo('BioSemi', 'EEG', 8, 100, 'float32', 'myuid34234')
    outlet = StreamOutlet(info)
    start_time = local_clock()
    sent_samples = 0
    while True:
        elapsed_time = local_clock() - start_time
        required_samples = int(100 * elapsed_time) - sent_samples
        for sample_ix in range(required_samples):
            # make a new random n_channels sample; this is converted into a
            # pylsl.vectorf (the data type that is expected by push_sample)
            mysample = [rand() for _ in range(8)]
            # now send it
            outlet.push_sample(mysample)
        sent_samples += required_samples
        # now send it and wait for a bit before trying again.
        time.sleep(0.01)


print('Starting serving process')
process = Process(target=_send, daemon=True)
process.start()

print("looking for an EEG stream...")
streams = resolve_stream('type', 'EEG')
inlet = StreamInlet(streams[0])
while True:
    sample, timestamp = inlet.pull_sample()
    print(timestamp, sample)

However, if I move the import scipy.fft to before the pylsl import, things break. The stream is never found and it just hangs on the resolve_stream step. I narrowed the from scipy import fft issue down to it being due to an import of scipy.fft._pocketfft.pypocketfft, which is a pybind11-compiled module. (I can also experience it when other modules are imported in that same spot in the script, so I don't think it's specific to SciPy, though.)

This is on Linux, where I noticed there is a known issue that multiple threads are not supported. Is this what is meant by "not supported" in that it might work in some situations but not others depending on the import order? If so, is it expected that the conda-forge version will not have this problem, or is it some fundamental limitation? Also I'm not sure if this is related to #6 / #5 or not.

The above example is a minimized version of how we unit test and build docs for MNE-Realtime, hence my interest in it being fixed if at all possible.

@larsoner
Copy link
Author

larsoner commented Feb 8, 2021

Okay looks like it's not a threading problem -- doing this with the built-in examples works fine:

$ python -u SendData.py & python -u ReceiveData.py 
[1] 132179
looking for an EEG stream...
2021-02-08 15:27:11.392 (   0.000s) [        2CC42740]             common.cpp:50    INFO| v1.14.0
now sending data...
2021-02-08 15:27:11.891 (   0.500s) [        7E6CC740]             common.cpp:50    INFO| v1.14.0
1612816032.1011267 [0.32223236560821533, 0.4601549804210663, 0.6337152719497681, 0.37596964836120605, 0.6952264308929443, 0.7275350689888, 0.5970755815505981, 0.5940881967544556]
1612816032.1011553 [0.5168118476867676, 0.18368901312351227, 0.8172319531440735, 0.6709344387054443, 0.7501394152641296, 0.33982735872268677, 0.8810415863990784, 0.16764724254608154]
...

But if I add a import scipy.fft to the ReceiveData.py script, it just hangs:

$ python -u SendData.py & python -u ReceiveData.py 
[2] 131766
2021-02-08 15:25:36.148 (   0.000s) [        2FBBB740]             common.cpp:50    INFO| v1.14.0
now sending data...
looking for an EEG stream...

So something about the pylsl and scipy.fft (and other modules) seems not to work.

I've tried this on latest scipy master built from source, plus SciPy 1.6.0 from PyPi. And CircleCI using pip also has a variant of this problem on our CIs.

@larsoner
Copy link
Author

larsoner commented Feb 8, 2021

... and it looks like it works okay with pylsl-1.12.2 but not pylsl-1.13.1 based on pip install-based version testing. So something about the code and/or lib change over that span seems to have broken things.

If it matters, this is all Python 3.9 on Ubuntu 20.10 x86_64.

@cboulay
Copy link
Contributor

cboulay commented Feb 8, 2021

What Linux distro are you on? I only have Ubuntu 20.04 in easy reach.
Edit: Sorry I saw the Linux distro after.

It would help narrow down the problem tremendously if you could please try the following.

pip install pylsl to get the latest version. Then git clone https://github.com/sccn/liblsl.git, build that, and copy the liblsl.so it outputs to the pylsl folder (replacing the old liblsl.so). If this works then we know it's not a liblsl version problem, it's just how liblsl is built for the linux pylsl packages on pypi. (Aside: there seems to be a problem with the MacOS packages too for some versions)

We're hoping the next version of liblsl will have a different distribution process. See sccn/liblsl#110
Then we don't need to build liblsl for manylinux, so hopefully we can avoid this problem altogether. Getting liblsl into Debian or NeuroDebian might take longer than you'd like, so maybe we can start with a custom conda channel.

is it expected that the conda-forge version will not have this problem?

Sorry what are you referring to here? Did you test something installed from conda and it didn't have the bug?
I'm guessing not pylsl because that's not on conda-forge.

@larsoner
Copy link
Author

larsoner commented Feb 9, 2021

I 1) git cloned this repo, 2) pip install -ve .ed it to use latest master, 3) git cloned liblsl.git, and then:

$ cmake -S . -B build -G Ninja
$ cd build
$ ninja -j 4
$ ln -s $PWD/liblsl.so ../../liblsl-Python/pylsl/lib/

And everything works! And when I replace liblsl-Python/pylsl/lib/liblsl.so with:

And then I verified that the 1.14.0 manylinux2010 library has the same MD5 (1793cbd2a45621572a14ff9090c57f32) as the 1.14.0 from PyPi / ~/.local/.... So it seems like the manylinux2010 build is for some reason problematic.

@cboulay
Copy link
Contributor

cboulay commented Feb 9, 2021

Thank you so much! This was tremendously helpful.
I deleted all of the manylinux2010 releases from pypi. I hope the manylinux1 release is adequate for most users until we start shipping liblsl through package managers.

@larsoner
Copy link
Author

larsoner commented Feb 9, 2021

Indeed I just did pip uninstall pylsl; pip install --no-cache pylsl and things appear to be working, thanks!

@larsoner larsoner closed this as completed Feb 9, 2021
cboulay added a commit that referenced this issue May 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants