TouchQueue demands 100% of a CPU core and stimulus freezes

Hi Mario,

Possibly my problem is related to this. Basically, I created a stimulus with 4 parts: an intertrial interval, a sample period, a delay interval and a test period. The code runs for around 200 correct trials and at some point it freezes without giving me any feedback. It might be a bug or a mistake from my part. A description of the stimulus goes below.

[Optional: Description of the stimulus] The intertrial interval is a preparation phase where nothing appears in the screen. During the sample period, a light gray square appears in the middle of the screen and the monkey has to touch this square to advance to the delay period. The delay is just a waiting period when nothing is displayed. Finally, in the test phase the monkey needs to touch a gray square which will appear in a random position. As soon as the monkey touches it, the arduino is invoked to turn on a water pump to deliver juice to the monkey. After that, a new trial starts.

Basically, in my code I created a nested function modified from the MultiTouchMinimalDemo.m to register the touch of only one finger, the finger that touches the screen first (see nested function below). I constantly call this nested function throughout my main function, at every flip of the screen. As I’ve written before, evth works fine until around 200 trials. At some point around it, one of the cores of the CPU gets stuck at 100% and matlab freezes (see figure below). Note that typically the monkey is continuously dragging his finger in the screen, and not removing and retouching the screen. So, there is constant input in the queue.

%% Function to process touch events
    function process_touch_event()
       
        % TouchEventAvail reports the number of events in a touch queue.
        % One single touch can contain many events.
        while TouchEventAvail(dev)
           
            evt_count = evt_count + 1;
           
            %  Return oldest pending event
            evt = TouchEventGet(dev, w);
           
            % Touch blob id - Unique in the session at least as
            % long as the finger stays on the screen:
            id = evt.Keycode;
            % fprintf("%d %d\n", evt.Keycode, evt.Type)
           
            % Only consider the id of the firstard = serialport('/dev/ttyACM0', 9600); touch event
            if evt_count == 1
                first_event_id = id;
            end
           
            if id == first_event_id
                switch evt.Type
                    case 0
                        % Not a touch point, but a button press or release on a
                        % physical (or emulated) button associated with the
                        % touch device:ard = serialport('/dev/ttyACM0', 9600);
                        buttonstate = evt.Pressed;
                       
                    case 1
                        % Not really a touch point, but movement of the
                        % simulated mouse cursor, driven by the primary
                        % touch-point:
                        Screen('DrawDots', w, [evt.MappedX; evt.MappedY], ...
                            baseSize, [1,1,1], [], 1, 1);
                       
                    case {2, 3}
                        % 2: New touch point -> New blob!
                        % 3: Moving touch point -> Moving blob!
                        blob.mul = 1.0; % size of the blob
                        blob.x = evt.MappedX;
                        blob.y = evt.MappedY;
                        blob.t = evt.Time;
                       
                    case 4
                        % Touch released -> Dying blob!
                        blob.mul = 0.999;
                        blob.x = evt.MappedX;
                        blob.y = evt.MappedY;
                       
                    case 5
                        % Lost touch data for some reason:
                        % Flush screen red for one video refresh cycle.
                        fprintf(['Ooops - Sequence data loss! 3rd party ' ...
                            'interference or overload?\n']);
                        Screen('FillRect', w, [1 0 0]);
                        Screen('Flip', w);
                        Screen('FillRect', w, 0);
                end
            end
        end
       
        % Now that all touches for this iteration are processed, repaint
        % the live blob in its new position or fade out a dying blob
        if ~isempty(blob) && blob.mul > 0.1
            % Draw the blob: .mul defines size of the blob:
            Screen('DrawDots', w, [blob.x, blob.y], ...
                blob.mul * baseSize, orange / 255, [], 1, 1);
           
            % An orphaned blob with no finger touching anymore,
            % so slowly fade it out:
            if blob.mul < 1
                blob.mul = blob.mul * 0.3;
            end
        else
            % Below threshold: Kill the blob
            blob = [];
        end
       
        % To determine if blobcol is empty
        if evt_count && isempty(blob)
            evt_count = 0;
        end
       
        if buttonstate
            Screen('FrameRect', w, [1, 1, 0], [], 5);
        end
       
    end

Core 3 of the CPU stuck at 100%:

After debugging it, I’ve found a workaround for the problem. I must delete and recreate the queue at every few trials, let’s say, at every 30 trials (snippet below).

  if ~mod(total_trials, 30)
        TouchQueueStop(dev);
        TouchQueueRelease(dev);
        Pause(0.1);
        TouchQueueCreate(w, dev);
        TouchQueueStart(dev);
  end

The pause is necessary otherwise the whole pc crashes in a non-predictable way. My hypothesis is that sth is being stored in the cue and not being deleted, as I would have expected. If you are interested in exploring this further, I can send you the whole code.

My hardwares are a Microsoft Surface Pro 6 i5 8Gb RAM 128GB connected to an arduino leonardo. I am using psychtoolbox v3.0.16, Matlab r2019b, Ubuntu 18.04 LTS Desktop and Jakeday Linux Kernel for Surfaces.

Best,
Fred.

Hi Fred,

i can’t see anything wrong with your code. The default touch queue size if created via TouchQueueCreate(w, dev) would be 100k touch events, so at a touchscreen update rate of say 120 Hz, you should be able to wait for ~13 Minutes between calls to your process_touch_event function, without anything overflowing. I rechecked my code and can’t see anything wrong. And i tested in the past and couldn’t find any malfunctions – the queue was properly emptied. I don’t have a touch screen to test - Donations welcome!

Can you check what n = TouchEventAvail(dev), or [evt, n] = TouchEventGet(dev, w) actually returns for n? As long as it stays below 100000 there should not be an overflow. This hang does not make much sense.

Another thing to check would be (sudo apt install octave) installing GNU/Octave, then “octave --no-gui” launch it in a terminal without GUI, cd(your psychtoolbox installation directory), SetupPsychtoolbox, to set up PTB, then see what happens if you run it in Octave. I wonder if there’s something really odd going on wrt. Matlab.

Another thing you can try is to attach the debugger to octave and find out where it hangs:

  1. gdb --args octave --no-gui
  2. Then type “r” + ENTER to run it. Maybe do a PsychDebugWindowConfiguration, so the terminal still stays visible below the onscreen window, once you run your script.
  3. If it hangs, CTRL+C to get into the debugger.
  4. Give me the output of the command “bt”
  5. Also output of “info threads”
  6. Also find the “Id” number in the list from 5. which says PsychHIDKbQueue, and say it is the number 5, do a “thread 5” then “bt” then give me that output.
  7. Then you can “q” to quite the debugger, kill octave etc.

Of course if Octave would not expose the problems, that would also be a result. Or if matlab -nojvm would not show a problem.

The output of the “dmesg” command during the hang would also be interesting. Or of “more .local/share/xorg/” whaterver Xorg log file in that folder is the most recent one.

This is not likely to get resolved until i actually have a touch screen and the time to debug it. But lets see if there’s some clue somewhere.

thanks,
-mario