[visionegg] optimizing my code since timing is a catastrophe

  • From: Christoph Lehmann <lehmann@xxxxxxxxxxxx>
  • To: visionegg@xxxxxxxxxxxxx
  • Date: Mon, 05 May 2003 18:48:26 +0200

Dear Andrew
Thanks for the LPT hint. It works fine now.

Another things, before despairing completely and quitting all attempts
(my complete code is below):

I logged the time, each time I get to the 

for event in pygame.event.get(pygame.locals.MOUSEBUTTONDOWN): 
            if event.button == 1:
                response_log.append(VisionEgg.time_func() - trial_onset)
code.

CONCLUSION:
with 120 images (totally 16.4MB) loaded as textures before entering the
main loop, the timing with and without maxpriority is a catastrophe in
the following way:

the time between a mouse-event check and its next event-check, if and
only if the inner while loop is left due to make a swap() in the outer
while loop, is for several trials more than 100ms (if I don't restart
the computer in few case even more than 1sec)

see this log-file excerpt:

after a system restart:

______ all times in s ____________
<= 0.010: 18091456    
<= 0.020: 142    
<= 0.030: 4    
<= 0.040: 41    
<= 0.050: 63    
<= 0.060: 3    
<= 0.080: 2    
<= 0.1: 5    
<= 0.2: 3    means, 3x between 0.1 and 0.2 s
<= 0.4: 1    
<= 0.6: 0    
<= 0.8: 0    
<= 1: 0    
<= 2: 0    
<= 3: 0    
<= 4: 0    
<= 5: 0    
> 5: 0    ___________________________________

if the computer is not restarted:

______ all times in s ____________
<= 0.010: 17722917    
<= 0.020: 140    
<= 0.030: 5    
<= 0.040: 73    
<= 0.050: 31    
<= 0.060: 2    
<= 0.080: 4    
<= 0.1: 0    
<= 0.2: 4    
<= 0.4: 1    
<= 0.6: 0    
<= 0.8: 2    
<= 1: 0    
<= 2: 0    
<= 3: 1    
<= 4: 0    
<= 5: 1    
> 5: 0    


This means, that I cannot use the code as it is now, for any behavioral
experiments, since subjects show RT < 100ms. With the trials showing
even seconds between, it's even worse, since so I will miss
trigger-signals from the scanner

I don't know, where I loose this time, but I cannot imagine it is the 

    stimulus.parameters.texture = preloaded_texture_list[stim_index]
    screen.clear()
    viewport.draw()
    swap_buffers()

part (this is code from you, and is very fast)

but which commands are that slow? list-appends? Is there any-thing wrong
with not released memory (target class?), since the problems seem to
appear only with a large number of stimuli (> e.g. 20) not with few
stimuli and the worse, if the computer is not restarted before running
the code.

I attach you my code, just change the two paths and put some pictures
(>100) in the data_orig directory and a fixation cross or anything else
in the other directory

Thanks a lot for your help. I was already too happy in thinking I got it
to work..

Christoph

==== code ====
#!/usr/bin/env python

#This bypasses the VisionEgg.Core.Presentation class.  It may be easier
#to create simple experiments this way."""

import VisionEgg
from VisionEgg.Core import *
import pygame
from pygame.locals import *
from VisionEgg.Text import *
from math import *
from operator import mod
from operator import div
from random import *
import VisionEgg.Daq
from VisionEgg.DaqLPT import *
from VisionEgg.Textures import *

screen = get_default_screen()
screen.parameters.bgcolor = (0.0,0.0,0.0,0.0) # black (RGBA)

path =
"/home/christoph/work/programming/my_ve_projects/load_picture/data_orig/" #the 
path the images are in
fixation =
"/home/christoph/work/programming/my_ve_projects/load_picture/fixation_stimuli/fixation02.bmp"

photo = []
photoX = []

# present them in random order
for filename in os.listdir(path):
    photo.append(filename)
length = len(photo)
for stim_index in range(0, length):
    ran = randint(0, len(photo)-1)
    file = photo[ran]
    photoX.append(file)
    photo.pop(ran)

# Insert a fixation cross in front of the texture list
photoX.insert(0,fixation)
os.chdir(path)

num_images = len(photoX)
ratio = 4 #4 volumes equal one trial (one TR fixtion, 3 TRs stimulus)

# Create list of stimuli
preloaded_texture_list = [] # empty at first
for stim_index in range(num_images):
    # Read the texture file
    texture = Texture(photoX[stim_index])

    # Add to list of stimuli
    preloaded_texture_list.append( texture )

x = screen.size[0]/2 - preloaded_texture_list[0].size[0]/2
y = screen.size[1]/2 - preloaded_texture_list[0].size[1]/2
stimulus = TextureStimulus(on = 1,
                           texture = preloaded_texture_list[0],
                           size = preloaded_texture_list[0].size,
                           lowerleft=(x,y))
viewport = Viewport( screen=screen, stimuli=[stimulus] ) #does not
display the texture until viewport.draw() is called


# The main loop below is an alternative to using the
# VisionEgg.Core.Presentation class.

trial_log_list = []
trial_log = []
response_log_list = []
response_log = []        
  
swap_time = 0
stim_index = 0
trial_index = 0
trial_onset = 0 #the time, a stimulus is drawn (not fixation)
trigger_onset = 0 #the time, a trigger has been detected on the lpt
start_time = -1
trigger_counter = -1
loop_ctr = 0 #to check, whether the outer while loop is entered the
first time (log start_time)
trigger_armed = 1

timestamp = [] #for time loggging only
looptime = 0 #for time loggging only
last_time = VisionEgg.time_func()

while (not pygame.event.peek((QUIT,KEYDOWN))):
    # wait for mouse response and trigger on the parallel port
    while (not pygame.event.peek((QUIT,KEYDOWN))):
        # only during developing check timing accuracy
        actualtime = VisionEgg.time_func()
        looptime = (actualtime - last_time)*1000 #log in ms
        last_time = actualtime
        timestamp.append(looptime)
        #log the mouse response (which button, and RT)
        for event in pygame.event.get(pygame.locals.MOUSEBUTTONDOWN): 
            if event.button == 1:
                response_log.append(VisionEgg.time_func() - trial_onset)
                response_log.append('L') #left
            elif event.button == 3:
                response_log.append(VisionEgg.time_func() - trial_onset)
                response_log.append('R') #right
        # poll the LPT for the TTL trigger, sent by the MR scanner
        if trigger_counter == 3:
            trigger_counter = -1 #reset ctr, since 4 volumes equal one
trial (one TR fixtion, 3 TRs stimulus)
        input_value = raw_lpt_module.inp(0x379) & 0x20        # pin nr
12
        # if TTL signal on lpt, increment the index for the texture-list
        if input_value == 0x20 and trigger_armed == 1: 
            trigger_counter = trigger_counter + 1
            trigger_armed = 0 #don't increment the texture-index, until
a new trigger puls is received (TTL pulse ca. 50ms)
            if mod(trigger_counter,ratio) == 0: #0: draw fixation
                trial_index = trial_index + 1 #after the drawn fixation
cross, the next swap will draw a new stimulus
                stim_index = 0
                break #leave the loop and update the screen, drawing a
fixation cross (begin of a new trial-compound)
            if mod(trigger_counter,ratio) == 1: #1: draw stimulus
                stim_index = trial_index #has been incremented during
the previous fixation loop
                break #leave the loop and update the screen with the new
stimulus
        elif input_value == 0 and trigger_armed == 0:  #first lpt
poll-loop after the TTL signal has fallen from 1 to 0 (-> arm trigger)
            trigger_armed = 1

    # quit if all stimuli shown
    if trial_index == num_images:
        response_log_list.append(response_log) #append last response log
and quit
        break

    # draw the stimulus (during first loop: fixation)
    stimulus.parameters.texture = preloaded_texture_list[stim_index]
    screen.clear()
    viewport.draw()
    swap_buffers()
    swap_time = VisionEgg.time_func()
    
    if loop_ctr == 0: #first fixation shown
        start_time = swap_time

    # logging
    if stim_index > 0: 
        # log the stimulus with onset-time info
        trial_onset = swap_time #confusing: trial_onset is the time the
stimulus is drawn 
        trial_log = (stim_index, trial_onset - start_time,
photoX[stim_index]) #create next new log
        trial_log_list.append(trial_log) #append last log
        # log the mouse-response info
        if loop_ctr > 0: #1st loop: fixation; only after the first
stimulus, response makes sense
            response_log_list.append(response_log) #append last response
log (since we want only one response log per trial
        response_log = [] #clear response_log
        response_log.append(stim_index)
        response_log.append(photoX[stim_index])      

    loop_ctr = loop_ctr + 1

#end of the main loop


# write all log info to several files
# create a histogramm of the loop-repeats in ms
t10 = 0
t20 = 0
t30 = 0
t40 = 0
t50 = 0
t60 = 0
t80 = 0
t100 = 0
t200 = 0
t400 = 0
t600 = 0
t800 = 0
t1000 = 0
t2000 = 0
t3000 = 0
t4000 = 0
t5000 = 0
t6000 = 0
t7000 = 0
t8000 = 0
t9000 = 0
t10000 = 0
t11000 = 0
t12000 = 0
t13000 = 0
t14000 = 0
t15000 = 0
t16000 = 0
t17000 = 0
t18000 = 0
t19000 = 0
t20000 = 0
t30000 = 0
t40000 = 0
t50000 = 0
t100000 = 0
tt = 0

for x in timestamp: #all in ms (milliseconds!)
    if x <= 10:
        t10 = t10 + 1
    elif x <= 20:
        t20 = t20 + 1
    elif x <= 30:
        t30 = t30 + 1
    elif x <= 40:
        t40 = t40 + 1
    elif x <= 50:
        t50 = t50 + 1
    elif x <= 60:
        t60 = t60 + 1
    elif x <= 80:
        t80 = t80 + 1
    elif x <= 100:
        t100 = t100 + 1
    elif x <= 200:
        t200 = t200 + 1
    elif x <= 400:
        t400 = t400 + 1
    elif x <= 600:
        t600 = t600 + 1
    elif x <= 800:
        t800 = t800 + 1
    elif x <= 1000:
        t1000 = t1000 + 1
    elif x <= 2000:
        t2000 <= 2000
    elif x <= 3000:
        t3000 = t3000 + 1
    elif x <= 4000:
        t4000 = t4000 + 1
    elif x <= 5000:
        t5000 = t5000 + 1
    elif x > 100000:
        tt = tt + 1



f=open('/home/christoph/work/programming/my_ve_projects/load_picture/timing.txt',
 'w')
f.write('______ all times in s ____________' + '\n')
f.write("<= 0.010: %d    " % t10)
f.write('\n')
f.write("<= 0.020: %d    " % t20)
f.write('\n')
f.write("<= 0.030: %d    " % t30)
f.write('\n')
f.write("<= 0.040: %d    " % t40)
f.write('\n')
f.write("<= 0.050: %d    " % t50)
f.write('\n')
f.write("<= 0.060: %d    " % t60)
f.write('\n')
f.write("<= 0.080: %d    " % t80)
f.write('\n')
f.write("<= 0.1: %d    " % t100)
f.write('\n')
f.write("<= 0.2: %d    " % t200)
f.write('\n')
f.write("<= 0.4: %d    " % t400)
f.write('\n')
f.write("<= 0.6: %d    " % t600)
f.write('\n')
f.write("<= 0.8: %d    " % t800)
f.write('\n')
f.write("<= 1: %d    " % t1000)
f.write('\n')
f.write("<= 2: %d    " % t2000)
f.write('\n')
f.write("<= 3: %d    " % t3000)
f.write('\n')
f.write("<= 4: %d    " % t4000)
f.write('\n')
f.write("<= 5: %d    " % t5000)
f.write('\n')
f.write("> 5: %d    " % tt)
f.write('___________________________________' + '\n')
f.close()


f=open('/home/christoph/work/programming/my_ve_projects/load_picture/trial_log_file.txt',
 'w')
f.write('trial   onset_t         stim' + '\n')
f.write('______________________________' + '\n')

x = 0
while x < len(trial_log_list):
    y = 0
    while y < len(trial_log_list[x]):
        if (type(trial_log_list[x][y]) == types.FloatType):
            if y == 0:
                 f.write("%04.0f    " % trial_log_list[x][y])          
#trial index
            elif y == 1:                                           # y =
0: onset_time of the stimulus             
                f.write("    %010.2f    " % (trial_log_list[x][y] *
1000)) #onset time of the stimulus
            else:
                f.write("%010.2f    " % (trial_log_list[x][y] * 1000))
#RT
        else:
            f.write(str(trial_log_list[x][y]) + "  ")                 
#mouse response (left/right)
        y = y + 1
    f.write('\n')
    x = x + 1
f.write('______________________________' + '\n')
f.write('Remarks:' + '\n')
f.write('(i) onset_t: time of the stimulus onset relative to the first
volume of the scanner' + '\n')
f.close()


f=open('/home/christoph/work/programming/my_ve_projects/load_picture/response_log_file.txt',
 'w')
f.write('trial   stim          RT  button (L/R)' + '\n')
f.write('___________________________________________________________________________________'
 + '\n')

x = 0
while x < len(response_log_list):
    y = 0
    while y < len(response_log_list[x]):
        if (type(response_log_list[x][y]) == types.FloatType):
           if (y == 0):
                f.write("%04.0f    " % response_log_list[x][y])         
#trial index
           else:
                f.write("    %010.2f    " % (response_log_list[x][y] *
1000)) #RT
        else:
            f.write(str(response_log_list[x][y]) + " 
")                  #mouse response (left/right)
        y = y + 1
    f.write('\n')
    x = x + 1
f.write('___________________________________________________________________________________'
 + '\n')
f.write('Remarks:' + '\n')
f.write('(i) RT: reaction-time of the subject, measured relative to the
corresponding stimulus onset' + '\n')
f.close()







===================================================================================


-- 
Christoph Lehmann <lehmann@xxxxxxxxxxxx>
University Hospital of Clinical Psychiatry

======================================
The Vision Egg mailing list
Archives: //www.freelists.org/archives/visionegg
Website: http://www.visionegg.org/mailinglist.html

Other related posts: