OS: OSX PsychoPy version: 3.6 Standard Standalone? (y/n): Anaconda env
What are you trying to achieve?
To present a dot stimulus with N=400 dots with the direction set every frame.
Problem:
When I define a dot stimulus with 400 dots in the Builder mode, the presentation time (not the frame numbers) get stretched by 2x. So if I have a 60Hz monitor and I set the presentation time to 60 frames, the duration is ~2sec. If I lower it to the default 100 dots, this doesn’t happen. I’ve also played around with the dotlife time and the direction (that I wan to set every frame according to a coding element at the start of each trial), but this doesn’t seem to influence things. You can download a simplified code here to see it for yourself (that doesn’t make sense and is only for the purpose of testing the dotStim properties).
Is this problem known? Is there anything else I can do to make the presentation time accurate, because I would like to keep 400 dots per dot stimulus.
Bouncing this topic up. I’ve done a lot of “control experiments” and the problem really comes down to the number of dots used in a dot stimulus. Or even the number of dots presented on the screen altogether, as the same problem occurs when replacing one 400 dot stimulus by four 100 dot stimuli…
This problem occurs by just changing only the number of dots in DotStim, and keeping everything else at default settings. Thus, it looks to me that it is a pretty fundamental problem. I would really appreciate if someone could help with this. Thank you!
Hardware performance can also be a limiting factor here. What specs does your computer have? In particular, does it have a proper graphics card, or, like many Macs these days, integrated Intel graphics? Have you run PsychoPy’s benchmarking script? How does your experiment perform on other systems?
I think it’s a combination of how PsychoPy renders dots and the drivers. Presently, dot attributes reside in client-side arrays (system RAM) and need to uploaded to the GPU every frame which may be a significant performance bottleneck on some hardware/drivers.
On a related note, I’ve rendered dots by mapping GPU buffers with PsychoPy. I was able to render >100K (up to a million before I started to notice lag) of them and update their positions randomly every frame via Numpy functions on my GTX 2080. So it may be possible in the future to update ElementArray and DotStim to use GPU buffers and get every ounce of performance out of the GPU.
@Michael I’ve done the timeByFrames demo, and the frame rate is very consistent. I’ve only run it on my 2018 MacbookPro, and there it performs similarly, though the delay is more consistent on the Mac Pro I run the experiment on. On My Macbook the delay is always there, though by how much the stimulus is delayed is not always consistent (probably because I have much more going on in the background).
@mdc This sounds promising. I have very little knowledge on how to map GPU buffers. Do you have some references concerning this in relation to PsychoPy? Or would you be comfortable sharing some DotStim code including this GPU buffer mapping?
Try using a square field and see if performance improves.
After looking at the source code, I suspect it depends on how the dots are sampled here. It seems that with circular fields, dots are sampled for a square field and sampling continues until the number of dots requested falls within the circular field. This process is not deterministic and can take many passes until that condition is met. I’ve written a patch that makes sampling occur within a fixed interval of time, should happen as quickly as with square fields. Hopefully this will fix the problem here.
EDIT: I used newer rendering techniques using GPU buffers with a custom DotStim. Surprisingly, not much in terms of performance improvements. Likely due PsychoPy performing CPU bound operations. DotStim is actually a pretty complex class with lots of features, quite a lot is going on in there each frame to produce the stimulus. It might be sped up substantially by moving those CPU bound operations into the GPU (I found numerous points were this can be done). But I can’t see a cases where one needs more than 1000 dots, it starts to look like a blizzard at the point.
@mdc Thank your for the additional comments! Did I see correctly that you proposed a change in the dot.py code in the PsychoPy github? I’ve been trying that new code and it does improve!! I can now present ~800 dots at the same time instead of ~250 before. It does not completely solve it for me though. While you say you can’t imagine that you’d want more than 1000 dots, I actually do want that. I have two dot stimuli with each 800 dots. I think it is too much detail to explain exactly why, but depending on the field size (which is quite large in my case) this definitely does not look like a blizzard
I’m glad that there was some improvement there. I’ll need to refactor the dot class and loads of other supporting functions to get the ability to render a massive amount of dots. I know it’s absolutely possible to get >100K dots drawn and refreshed every frame on my PC, just that that code is not wrapped up nicely in a class.
PsychoPy has some really high-performance math and GL helper modules now built-in to it, now it’s just a matter of using them.
EDIT: Actually, I seem to have fixed it with a few optimizations. I can render 10K points without dropping a frame. I’ll push those changes out later today.
@mdc A bit busy here, but finally got the chance to test this on my original script (1600 simultaneous dots). And it works!!! (I have not tested the boundaries of the timing accuracy yet, in terms of number of dots, so can’t confirm the 10K dots yet…) Thank you very very much! This is really a major help.