views:

475

answers:

4

While testing Pythons time.clock() function on FreeBSD I've noticed it always returns the same value, around 0.156

The time.time() function works properly but I need a something with a slightly higher resolution.

Does anyone the C function it's bound to and if there is an alternative high resolution timer?

I'm not profiling so the TimeIt module is not really appropriate here.

+3  A: 

Python's time.clock calls C function clock(3) -- man clock should confirm that it's supposed to work on BSD, so I don't know why it's not working for you. Maybe you can try working around this apparent bug in your Python port by using ctypes to call the clock function from the system C library directly (if you have said library as a .so/.dynlib/.dll or whatever dynamic shared libraries are called on FreeBSD)?

time.time is supposed to be very high resolution, BTW, as internally it calls gettimeofday (well, in a properly built Python, anyway) -- what resolution do you observe for it on your system?

Edit: here's wat.c, a BSD-specific extension (tested on my Mac only -- sorry but I have no other BSD flavor at hand right know) to work around this apparent FreeBSD port problem:

#include "Python.h"
#include <sys/time.h>

static PyObject *
wat_time(PyObject *self, PyObject *args)
{
    struct timeval t;
    if (gettimeofday(&t, (struct timezone *)NULL) == 0) {
        double result = (double)t.tv_sec + t.tv_usec*0.000001;
        return PyFloat_FromDouble(result);
    }
    return PyErr_SetFromErrno(PyExc_OSError);
}

static PyMethodDef wat_methods[] = {
      {"time",  wat_time,  METH_VARARGS,
       PyDoc_STR("time() -> microseconds since epoch")},
      {NULL,  NULL}  /* sentinel */
};

PyDoc_STRVAR(wat_module_doc,
"Workaround for time.time issues on FreeBsd.");

PyMODINIT_FUNC
initwat(void)
{
    Py_InitModule3("wat", wat_methods, wat_module_doc);
}

And here's the setup.py to put in the same directory:

from distutils.core import setup, Extension

setup (name = "wat",
       version = "0.1",
       maintainer = "Alex Martelli",
       maintainer_email = "[email protected]",
       url = "http://www.aleax.it/wat.zip",
       description = "WorkAround for Time in FreeBSD",
       ext_modules = [Extension('wat', sources=['wat.c'])],
)

The URL is correct, so you can also get these two files zipped up here.

To build & install this extension, python setup.py install (if you have permission to write in your Python's installation) or python setup.py build_ext -i to write wat.so in the very directory in which you put the sources (and then manually move it wherever you prefer to have it, but first try it out e.g. with python -c'import wat; print repr(wat.time())' in the same directory in which you've built it).

Please let me know how it works on FreeBSD (or any other Unix flavor with gettimeofday!-) -- if the C compiler complains about gettimeofday, you may be on a system which doesn't want to see its second argument, try without it!-).

Alex Martelli
time.time() is only return 1/100 of a second e.g: 1247253412.26
Dan
Must be a problem with the FreeBSD port, because on my Mac (also essentially a BSD dialect) I get microseconds from both time.time() and time.clock(). Unfortunately I don't have a FreeBSD around to check why HAVE_GETTIMEOFDAY doesn't get defined in that port (if it did, you'd surely get microseconds). If ctime's too slow for you I think I may be able to help you get a workaround -- stay tuned.
Alex Martelli
OK done, please try out my little workaround extension now in my answer (or a zipfile the answer points to, as well).
Alex Martelli
My FreeBSD systems has more than 1/100s: time.time()1248948841.266459
Thomas
@Thomas, so you and Dan Jul must exchange much more detailed notes -- what versions of everything (kernel, cc, python, its port, ...)? then configurations can be compared and the bug pinpointed on the Python tracker (if it affects the recent, currently maintained versions of Python).
Alex Martelli
+1  A: 

time.clock() returns CPU time on UNIX systems, and wallclock time since program start on Windows. This is a very unfortunate insymmetry, in my opinion.

You can find the definition for time.time() in the Python sources here (link to Google Code Search). It seems to use the highest-resolution timer available, which according to a quick Googling is gettimeofday() on FreeBSD as well, and that should be in the microsecond accuracy class.

However, if you really need more accuracy, you could look into writing your own C module for really high-resolution timing (something that might just return the current microsecond count, maybe!). Pyrex makes Python extension writing very effortless, and SWIG is the other common choice. (Though really, if you want to shave as many microseconds off your timer accuracy, just write it as a pure C Python extension yourself.) Ctypes is also an option, but probably rather slow.

Best of luck!

AKX
time.time() doesn't seem to show microsecond accuracy, could it be the print function is truncating the double? (microseconds would be great! All I'm observing is 1/100 of a second e.g. 1247253412.26
Dan
A: 

time.clock() is implemented to return a double value resulting from

 ((double)clock()) / CLOCKS_PER_SEC

Why do you think time.time() has bad resolution? It uses gettimeofday, which in turn reads the hardware clock, which has very good resolution.

Martin v. Löwis
When I call time.clock() on FreeBSD all I get is a small value that doesn't change... what do you observe?
Dan
See Lennart's response. It is correct to get a small value from time.clock.
Martin v. Löwis
I agree i should get observe a small value... but that value should change when called repeatedly (with a little sleep thrown in between)
Dan
No, a little sleep in between will not increase the time.clock result, since no CPU time is consumed while sleeping.
Martin v. Löwis
+1  A: 

time.clock() returns the processor time. That is, how much time the current process has used on the processor. So if you have a Python script called "clock.py", that does import time;print time.clock() it will indeed print about exactly the same each time you run it, as a new process is started each time.

Here is a python console log that might explain it to you:

>>> import time
>>> time.clock()
0.11
>>> time.clock()
0.11
>>> time.clock()
0.11
>>> for x in xrange(100000000): pass
... 
>>> time.clock()
7.7800000000000002
>>> time.clock()
7.7800000000000002
>>> time.clock()
7.7800000000000002

I hope this clarifies things.

Lennart Regebro
Yes, this is exactly the behavior I observed but for my test I have a small sleep [time.sleep(.5)] in between calls to time.clock(). On windows, i see gradual changes between each step. On FreeBSD, nothing.
Dan
That is as it should be.
Lennart Regebro
+1 for that. I just got it. You have to do some useful work in the script to get a different result from time.clock().
Seun Osewa
How long does it take for your script to spin in that loop? I would think a sleep of a 1/2 second would be very close to your spinning?
Dan
No, sleep() doesn't use up ANY processor time, and doesn't increase clock() at all. You still don't get what processor time is, do you? :-) It's NOT how much time has passed since the start, but how much time the processor has WORKED. Except on Windows, which is broken.
Lennart Regebro
Ah, no i didn't understand that. Thanks again.
Dan