0

I need to figure out the delay between sending a command to change the background color or playing a sound and these events actually occurring using timeit.(I'm on windows, Python 2.73)
I'm doing a reaction time test where I'll record the time(using time.clock()) before either changing the background color or playing a sound. Then, when the subject presses a key I record the time again and take difference to find the reaction time.
For the sound playing, here's what I did:

import timeit
t = timeit.Timer(stmt = "winsound.PlaySound('C:\WINDOWS\media\Windows XP Error.wav', winsound.SND_FILENAME)",setup = "import winsound")
n = t.timeit(number = 100) 
print n/100 -0.999  

The 0.999 is the duration of the Windows XP Error.wav in seconds.
This gave me something like 56ms. I'm not sure if its reasonable and if its the right way to do it as well as should I be enabling the garbage collection or not?


For the background changing I'm having more problems. Since I'm doing the test in fullscreen mode I tried to put all of these into the setup parameter:

from Tkinter import Tk
root=Tk()
root.overrideredirect(True)
root.geometry("{0}x{1}+0+0".format(root.winfo_screenwidth(),root.winfo_screenheight()))
root.mainloop()

Even though I separate them all with ; I still get syntax errors. When I try it not in full screen
setup = 'from Tkinter import Tk; root=Tk(); root.mainloop()' the window actually opens, yet nothing happens and if I close it I see other errors.Invalid command name "."
The statement that I'm actually measuring is root.configure(background='red').

user1830663
  • 521
  • 3
  • 8
  • 16
  • 1
    What version of Python do you have? Unless it's pretty old, you can pass a function to `timeit` instead of a string. If you can't do that, try separating the lines with `\n` instead of `;`. – abarnert Nov 17 '12 at 02:13
  • 1
    Meanwhile, the timing of these functions is going to vary wildly from one machine to the next. It may take 56ms on your machine, but 496ms on mine. So, if you're planning to just hardcode that 56 into your program, it's not going to be useful for anyone else. – abarnert Nov 17 '12 at 02:14
  • @abarnert I'm using 2.7.3. `\n` gave me the same error. I'm not quite sure how to pass a function to timeit, but if do so, wouldn't it also run each time all these things that I included in the setup? – user1830663 Nov 17 '12 at 02:47
  • I'll do the timing on the machine from which I will be testing(only 1). Have you any ideas on should I use the garbage collection or not? I don't quite understand what does it change. – user1830663 Nov 17 '12 at 02:51
  • To pass a function, you just pass a function instead of a string, and you normally don't use a setup. For example, http://pastebin.com/WF4m2yQm is equivalent to your first version, and http://pastebin.com/xhH61Ntp is equivalent to what I think your second is supposed to be. Of course if you want the test to happen inside the `mainloop` instead of before it, you have to get it into the loop via triggering it within `Tkinter` somehow (as martineau suggests in a comment to his answer). – abarnert Nov 19 '12 at 21:01
  • PS, it sounds like you want it to happen _after_ the `mainloop`, which doesn't make any sense. After that returns, `Tk` has been shut down and you can't make calls on it anymore. – abarnert Nov 19 '12 at 21:02

1 Answers1

1

Here's an example of a way to create a multi-line setup string for use with timeit:

setup = """
import random
l1 = [random.randrange(100) for _ in xrange(100)]
l2 = [random.randrange(100) for _ in xrange(10)]
"""

Here's another tip. To get an accurate measurement, it's important to time things following this basic pattern:

time = min(timeit.repeat(statements, setup=setup, repeat=R, number=N))

With an R of at least 3 (R = 3). This takes the fastest value obtained by doing everything 3 times, which will eliminate differences due to the many other things running on your system in the background.

This doesn't answer your whole question, but may be helpful in your quest.

martineau
  • 119,623
  • 25
  • 170
  • 301
  • This seems to solve the syntax issue but I'm still getting `invalid command name "."` – user1830663 Nov 17 '12 at 03:28
  • 2
    That's probably because of the backslashes in the `PlaySound` argument. Make it a raw string by adding an `r` prefix, as in `r'C:\WINDOWS\media\Windows XP Error.wav'`. – martineau Nov 17 '12 at 03:38
  • This one actually runs fine, its the background changing that doesn't. I just added these 3 lines `import timeit` `t = timeit.Timer(stmt = "root.configure(background = 'red')", setup = setup)` `print t.timeit()` to your multi-line setup string. – user1830663 Nov 17 '12 at 03:42
  • 1
    You wouldn't want the `print t.timeit()` statement in the setup string. Actually, you wouldn't put the `import` and creation of the `Timer` object there either. – martineau Nov 17 '12 at 03:47
  • They are not "inside" the setup string. My first line is `import timeit`, then the setup string in which I put all 5 parameters as in my first post and then the timer object and the print. Sorry for the confusion. – user1830663 Nov 17 '12 at 03:59
  • 2
    OK, sorry for the misunderstanding. `root.mainloop()` is, not surprisingly, a loop. When you put that in your setup string and it's executed, it doesn't end until the main window is closed and the `mainloop` terminates. I'm not a `tkinter` expert, but believe you're going to have to do the timing _inside_ the `mainloop`, probably as the result of some kind of event, like a keypress or button-click. – martineau Nov 17 '12 at 04:08
  • @martineau: Or, if he's got a "main loop" that just plays the sound and then quits, maybe make `root.mainloop()` the timed statement, instead of part of the setup? – abarnert Nov 19 '12 at 18:24
  • @abarnert: Because `mainloop()` does a multitude of fairly time-consuming things not a part of what the OP is trying to measure. – martineau Nov 19 '12 at 20:18
  • @martineau: Well, he could subtract the results of two `mainloop` invocations, one with and one without the function. (Considering his use case, "How long does it take on this specific machine in this specific scenario", that _might_ be reasonable.) But yeah, otherwise, he'll have to put the timing inside the `mainloop` rather than at the top level, as you suggest. – abarnert Nov 19 '12 at 20:52
  • @abarnert: That might work. On the other hand, doing it the way I suggested is not too different from the actual application being written, so some of the code for the effort can be reused or may already exist. – martineau Nov 19 '12 at 21:08