Problem with time.time() standing still

Bob Cowdery bob at bobcowdery.plus.com
Tue May 8 11:42:29 EDT 2012


Hopefully somebody can add the last piece of this puzzle. My code didn't 
work because I did make a silly mistake. The number of seconds since 
EPOC is a large number but it also needs a high precision. Attempting to 
put this value into a 32 bit float corrupts the least significant part 
because 24 bits  cannot hold that precision. Now Python floats are C 
doubles and the calculation in timemodule.c is in doubles right back to 
Python. Normally this retains the precision. For some inexplicable 
reason when I make certain calls into this vendors SDK, ftime()  is 
getting precision problems and appears to be frozen as a result.

C, only supporting early binding cannot change the function referenced 
at runtime so how the devil is it managing to do this.

On 08/05/2012 12:17, Bob Cowdery wrote:
> Can anyone make sense of this.
>
> I've looked over the Python timemodule.c again and it uses one of 
> gettimeofday(), ftime() or time(). The gettimeofday() is not available 
> on Windows so its going to use ftime() or time(). As time() only has a 
> resolution of 1 second and returns a long and I know Python 
> time.time() has a ms resolution it must be using ftime().
>
> After going round the houses - a lot. I've made a trivially simple 
> extension that goes wrong. I can only think I must be doing something 
> incredibly stupid. Perhaps someone can put me out of my misery.
>
> In the full app what happens is that it reports the correct time as 
> given by time() by gets the ms from somewhere also. When it goes wrong 
> it reports the same time as ftime().
>
> Bob
>
> >>> import mytime
> >>> mytime.doTime()
> TIME : 1336474857
> FTIME secs 1336474880.000000
> FTIME ms 0.601000
> FTIME secs+ms 1336474880.601000
> 0
> >>> mytime.doTime()
> TIME : 1336474871
> FTIME secs 1336474880.000000
> FTIME ms 0.548000
> FTIME secs+ms 1336474880.548000
> 0
> >>> mytime.doTime()
> TIME : 1336474897
> FTIME secs 1336474880.000000
> FTIME ms 0.007000
> FTIME secs+ms 1336474880.007000
> 0
>
> The extension just prints out the time as got from time() and ftime(). 
> For a start the two do not agree on what the time is. Secondly ftime() 
> stops incrementing while the python session is running. If I start a 
> new session it will have incremented.
>
> >>> import mytime
> >>> mytime.doTime()
> TIME : 1336475029
> FTIME secs 1336475008.000000
> FTIME ms 0.265000
> FTIME secs+ms 1336475008.265000
> 0
>
> Code and build file
> ================
>
> #include "Python.h"
> #include <sys/types.h>
> #include <stdio.h>
> #include <time.h>
> #include <sys/timeb.h>
>
> static struct timeb t;
> static float secs = 0.0;
> static float ms = 0.0;
> static float both = 0.0;
>
> static PyObject *doTime(
>                 PyObject *self,
>                 PyObject *args) {
>         time_t seconds;
>     seconds = time (NULL);
>     printf ("TIME : %ld\n", seconds);
>         ftime(&t);
>         secs = (float)t.time;
>         ms = (float)((float)t.millitm * 0.001);
>         printf("FTIME secs+ms %f\n",  secs + ms);
>
>     return PyInt_FromLong((long)0);
> }
>
> static PyMethodDef pyInst_Methods[] = {
>
>         {"doTime",
>             doTime,
>             METH_VARARGS},
>         {NULL, NULL, 0, NULL}
> };
>
> #ifndef PyMODINIT_FUNC
> #define PyMODINIT_FUNC void
> #endif /* PyMODINIT_FUNC */
>
> PyMODINIT_FUNC initmytime(void)
> {
>     PyObject *module;
>     module = Py_InitModule3("mytime", pyInst_Methods,"Time module");
>     if (!module) return;
> }
>
> Build file
> ========
> import os
> from distutils.core import setup
> from distutils.extension import Extension
>
> if os.path.exists('C:\\Program Files (x86)'):
>     # 64 bit
>     ProgramFiles = 'Program Files (x86)'
> else:
>     # 32 bit
>     ProgramFiles = 'Program Files'
>
> setup(
>     name='Time Test',
>     author='Bob Cowdery',
>     ext_modules = [
>         Extension('mytime',
>                     ['pytime.cpp'],
>                     include_dirs = ['C:\\' + ProgramFiles + 
> '\\Microsoft SDKs\\Windows\\v7.0A\\Include', 'C:\\Python26\\include'],
>                     #define_macros = [("_AFXDLL", None)],
>                     library_dirs = ['C:\\' + ProgramFiles + 
> '\\Microsoft SDKs\\Windows\\v7.0A\\Lib', 'C:\\Python26\\libs'],
>                     libraries = ['User32', 'Gdi32', 'python26', 
> 'odbc32', 'odbccp32']
>         )
>     ]
> )
>
> On 06/05/2012 10:19, Bob Cowdery wrote:
>> On 06/05/2012 09:49, Cameron Simpson wrote:
>>> On 06May2012 09:18, Bob Cowdery<bob at bobcowdery.plus.com>  wrote:
>>> | On 05/05/2012 23:05, Cameron Simpson wrote:
>>> |>  On 05May2012 20:33, Bob Cowdery<bob at bobcowdery.plus.com>  wrote:
>>> |>  | [...] calls to time.time() always return the same
>>> |>  | time which is usually several seconds in the past or future 
>>> and always
>>> |>  | has no fractional part.
>>> |>
>>> |>  Thought #1: you are calling time.time() and haven't unfortunately
>>> |>  renamed it? (I doubt this scenario, though the lack of 
>>> fractional part
>>> |>  is interesting.)
>>> |
>>> | Not sure what you mean by renamed it.
>>>
>>> Like this:
>>>
>>>    from time import time
>>>    [...]
>>>    time = some_unfortunate_other_function
>>>    [...]
>>>    now = time()  # calls wrong function
>>>
>>> It seems unlikely, but possible.
>>>
>>> | I also tried datetime and that had
>>> | the same behaviour.
>>>
>>> Makes my suggestion even less likely unless the time module itself gets
>>> monkeypatched (i.e. "time.time = bad_function" somewhere).
>> I don't think the function is subverted unless there is some way inside
>> the vendor SDK or even DirectShow (the SDK uses this as a COM object)
>> which can somehow hijack it. It does catch up every few minutes so there
>> has to be a clue there.
>>> |>  | If I leave it long enough time will suddently
>>> |>  | jump forward after a few minutes, then again after a few 
>>> minutes more.
>>> |>  |
>>> |>  | I've never encountered this behaviour before and can't 
>>> understand what
>>> |>  | on earth is going on. If I call the 'C' time() function just 
>>> the other
>>> |>  | side of my call to the extension the time is ticking along 
>>> fine. It's
>>> |>  | just the one Python thread that is affected.
>>> |>  [...]
>>> |>
>>> |>  Thought #2: On a UNIX system I'd be running the process under 
>>> strace (or
>>> |>  dtrace or ktrace depending on flavour) to see what actual OS 
>>> system calls are
>>> |>  being made during this behaviour. Is this feasible for you?
>>> |
>>> | I'm on Windows for this particular part of the application.
>>>
>>> I'd guessed so. I've no Windows programming background; I was wondering
>>> if there was something like this you had to hand on windows.
>> Maybe, but not that I know of.
>>> | [...] But debugging into this is probably the only way. I
>>> | looked at the built-in time module. As far as I can tell it just 
>>> calls
>>> | the underlying C time() function as an extension. This is more
>>> | mystifying as that is pretty much what I'm doing by checking the 
>>> time in
>>> | my own extension module where it ticks along fine.
>>>
>>> Hmm. A C extension I presume? How about writing a little pure Python
>>> thread to call time.time(), and spin it off parallel to the rest of the
>>> app; does it also get bad time.time() behaviour?
>> I've tried that. It's only the Python thread (or Python main thread)
>> that calls the extension that behaves like this. Other Python threads
>> tick along fine with the correct time including a fractional part.
>>> | I have another
>>> | scenario using a different part of their SDK where the time does 
>>> still
>>> | tick but the fractional part is frozen, not 0 but frozen.
>>>
>>> Curiouser and curiouser.
>> Indeed. Away now but battle will resume on Tuesday.
>>
>> Bob
>>
>>
>>
>




More information about the Python-list mailing list