zentara has asked for the wisdom of the Perl Monks concerning the following question:

Hi, this is sort of a "borderline OT" Perl question, but I was thinking about if it was possible for a single-cpu system to be able to generate identical timestamps using Time::HiRes.

How fast is "fast enough"?

The following script produces substantially different times, when run within the same script. So how fast would my processor have to be, in order to have the numbers be the same? On my 2Ghz single-cpu system, I get anywhere from 20 to 80 ticks difference. Are there any cpus fast enough to make the times identical in this script. Even more curious, could you get identical timestamps from different processes, knowing that the kernel's execution pointer can only be in 1 place at a time, and it takes a few instructions to switch to another process.

#!/usr/bin/perl use Time::HiRes qw(gettimeofday); # Get the timestamp (down to microseconds) ($secs_since_epoch, $microseconds) = gettimeofday(); print "$secs_since_epoch$microseconds\n"; # Get the timestamp (down to microseconds) ($secs_since_epoch, $microseconds) = gettimeofday(); print "$secs_since_epoch$microseconds\n";

I'm not really a human, but I play one on earth. flash japh

Replies are listed 'Best First'.
Re: OT How fast a cpu to overwhelm Time::HiRes
by tirwhan (Abbot) on Nov 30, 2005 at 13:13 UTC

    With some changes to your code I got the difference down to two microseconds:

    #!/usr/bin/perl use Time::HiRes qw(gettimeofday); my ($secs1,$sec2,$micro1,$micro2); #discard once gettimeofday(); ($secs1, $micro1) = gettimeofday(); ($secs2, $micro2) = gettimeofday(); print "$secs1$micro1\n"; print "$secs2$micro2\n"; __OUTPUT__ 1133355471176848 1133355471176850

    This is on a dual-2.8GHz Xeon, so I suspect you'll have trouble getting it to display identical values on a "normal" current system.

    As for whether it's theoretically possible, I am pretty sure it'd be possible on SMP machines.

    Update: after thinking about this some more, I'm pretty sure this is also possible on uniprocessor machines if you're running an operating system with a preemptible kernel.


    Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. -- Brian W. Kernighan
      More than theoretical. I got it down to reliable 1 microsecond and the occasional 0 microseconds on a dual Xeon 3.06 with HT.
      #!/usr/bin/perl use Time::HiRes qw(gettimeofday); my @timings = (0,0,0,0); #discard once @timings = (gettimeofday(), gettimeofday()); @timings = (gettimeofday(), gettimeofday()); print "$timings[0]$timings[1]\n"; print "$timings[2]$timings[3]\n"; __OUTPUT__ 1133364015468783 1133364015468783
      So the answer to the OP is yes - you *can* get identical timestamps out of Time::HiRes with a sufficiently fast system.
        Correction - that was a SINGLE 3.06 Xeon with HT.

        Sorry, but if this is true, and I don't doubt you are seeing what you say you are seeing, then something is being cached somewhere.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: OT How fast a cpu to overwhelm Time::HiRes
by BrowserUk (Patriarch) on Nov 30, 2005 at 15:52 UTC

    I seriously doubt that it is possible to get two identical timestamps from Time::HiRes on a single CPU system. At least not under Win32, and I doubt it is much different under other OSs.

    Under Win32, the mechanism underlying the timestamps is the QueryPerformanceCounter() API. It has a companion call, QueryPerformanceFrequency() which tells you how quickly the raw timer changes. On my 2.66 GHz system, this frequency is reported as 3579545 ticks/second. This second call is required because the speed of the counter underlying the timing mechanism is tied to the speed of the processor. As the processor gets faster, so does the counter.

    Calling the api directly from within Perl, I get

    P:\test>perl qpc.pl t/S: 3579545 Ticks1: 4139490207899 Ticks2: 4139490207925 Diff : 26 P:\test>perl qpc.pl t/S: 3579545 Ticks1: 4139494180449 Ticks2: 4139494180475 Diff : 26 P:\test>perl qpc.pl t/S: 3579545 Ticks1: 4139496939489 Ticks2: 4139496939517 Diff : 28 P:\test>perl qpc.pl t/S: 3579545 Ticks1: 4139500850229 Ticks2: 4139500850256 Diff : 27

    Showing that even bypassing the code in Time::HiRes, 2 consecutive calls take at least 25 ticks. On my system that translates into approximately 25 / 3579545 = 0.00000698 seconds, or at 2.66GHz, roughly 18500 cpu cycles. On modern processors, that can often equate to 18500 cpu instructions.

    If I drop into C

    P:\test>qpc Frequency: 3579545 T1: 823060571 T2: 823060575 P:\test>qpc Frequency: 3579545 T1: 829532517 T2: 829532521 P:\test>qpc Frequency: 3579545 T1: 833572712 T2: 833572716

    The closest I get is 4 ticks, or roughly 0.0000011 seconds or 3000 cpu cycles/instructions.

    Whilst there are many faster processors than mine, the salient point is that as the processor gets faster, the frequency of the counter will also increase.

    So the possibility for you being able to get two identical timestamps from within Perl on a single processor system, given the extra cycles that getting from perl to the hardware and back again involves, seems pretty unlikely.

    YMMV on other OSs and hardware.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Ah, but one of the OP's questions was whether this would be possible with two distinct processes. And I think it is, even on a single processors system, because the OS can switch contexts between processes at any time, even in the middle of a system call (well, not at any time, certain code paths are not preemptible, but nearly enough for this matter).


      Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. -- Brian W. Kernighan
        because the OS can switch contexts between processes at any time,

        But switching processes is not cheap. Take a good look at the code at the heart of your OS kernel and see what is involved with switching processes.

        All the saving and restoring of registers alone is not insubstantial, but before you get to all of that you have to go through the mechanics of deciding which process is next to run. This involves some sort of prioritised queue mechanism. You also have to update any dynamic priorities (eg. foreground boost), check for whether the next round-robin process within the current priority arbitration level is eligable to run.

        Is it sleeping or in an IO wait state, etc.

        And once you chosen the next process to run, you have to check whether it has been swapped out, and potentially shuffle memory to and from disk. Did the process swap invalidate any COW memory that now needs replicating? And almost every process swap is going to cause the processor to stall while the l2 cache is refreshed. Even kernel-level thread swaps involve a substantial amount of housekeeping by the kernel. Less than a process, but still substantial.

        Process swaps are not instantaneous. Can they be done in less than 2000 cycles/instructions? In C it's vaguely possible, but 18500 for perl?


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: OT How fast a cpu to overwhelm Time::HiRes
by admiral_grinder (Pilgrim) on Nov 30, 2005 at 13:09 UTC
    What happens when you move the print statements out from the time snapshots:
    ($secs_since_epoch_one, $microseconds_one) = gettimeofday(); ($secs_since_epoch_two, $microseconds_two) = gettimeofday(); print "......
    Is the results closer to what you are looking for? could try to call the gettimeofday() from within the print statement and skip over most of the memory access.
Re: OT How fast a cpu to overwhelm Time::HiRes
by Perl Mouse (Chaplain) on Nov 30, 2005 at 13:23 UTC
    You don't need a fast CPU for that. Just add two lines to your program:
    use Memoize; memoize 'gettimeofday';
    HTH. HAND.
    Perl --((8:>*
      That is good, but I don't think it is in the nature of the question. He is trying for 2 seperate timestamps from 2 seperate points in time that happens to look the same when rounded to microseconds. Your solution will just give him the timestamp from the first call twice.

        One joke leads almost inevitably to another:

        $admiral_grinder->append( Sense->new(of => "humor") );
Re: OT How fast a cpu to overwhelm Time::HiRes
by ikegami (Patriarch) on Nov 30, 2005 at 15:21 UTC

    Some versions (of perl?) are buggy and return a low resultion value:

    #!/usr/bin/perl use Time::HiRes qw(gettimeofday); for (1..10) { ($secs, $micro) = gettimeofday(); print "$secs.$micro\n"; }

    outputs

    1133364163.866375 1133364163.866375 1133364163.866375 1133364163.866375 1133364163.882000 1133364163.882000 1133364163.882000 1133364163.882000 1133364163.882000 1133364163.882000

    on my ActivePerl 5.8.0

      That's not Perl, that's Windows. If I recall correctly, the timer resolution is only 30msec or so. Cheers, Rob
        That's not Perl, that's Windows.

        Wrong. That's not windows, that early versions of Time::HiRes running on windows that didn't use the correct APIs to get good resolution.

        That said, the timer resolution available under very old versions of windows is very low.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        Even if its a windows issue it still concerns perl code. The question was if you could count on perl to return unique timestamps for consecutive or concurrent calls to Time::HiRes and the answer is obviously no. ;)


        ___________
        Eric Hodges $_='y==QAe=e?y==QG@>@?iy==QVq?f?=a@iG?=QQ=Q?9'; s/(.)/ord($1)-50/eigs;tr/6123457/- \/|\\\_\n/;print;
Re: OT How fast a cpu to overwhelm Time::HiRes
by eric256 (Parson) on Nov 30, 2005 at 15:58 UTC

    Here is some interesting test code. Lowest difference I could get was 1 microsecond. I certainly wouldn't take this as proof, combining the timestamp with some other info is easy and pretty fool proof.

    #!/usr/bin/perl use Time::HiRes qw(gettimeofday); my $min = 10; my $max = 0; for (0..1_000_000) { ($secs1, $micro1) = gettimeofday(); ($secs2, $micro2) = gettimeofday(); $diff = (($secs2 * 1_000_000) + $micro2) - (($secs1 * 1_000_000) + + $micro1); $max = $diff if $diff > $max; $min = $diff if $diff < $min; } print "Min difference: $min\n"; print "Max difference: $max\n";

    ___________
    Eric Hodges $_='y==QAe=e?y==QG@>@?iy==QVq?f?=a@iG?=QQ=Q?9'; s/(.)/ord($1)-50/eigs;tr/6123457/- \/|\\\_\n/;print;
Re: OT How fast a cpu to overwhelm Time::HiRes
by ctilmes (Vicar) on Nov 30, 2005 at 12:46 UTC
    Are there any cpus fast enough to make the times identical in this script.

    Are you asking if there are any today, or if there will ever be any?

Re: OT How fast a cpu to overwhelm Time::HiRes
by thor (Priest) on Nov 30, 2005 at 15:41 UTC
    I may be reading a little into your question, but if you're looking to generate guaranteed unique values, Data::UUID might be worth a look...

    thor

    The only easy day was yesterday