clock clicks

clock clicks ?-option?

clock clicks returns a high-resolution time value as a system-dependent integer value. See the clock reference page for more detail.

If -milliseconds is provided as an option, then the command is synonymous with clock milliseconds. In 8.5+, clicks -milliseconds is deprecated.

If -microseconds is provided as an option, then the command is synonymous with clock microseconds. In 8.5+, clicks -microseconds is deprecated. -microseconds doesn't exist in 8.4.

Click duration

In Classic MacOS, the clicks were typically as long as 1/60 second, but in recent MacOS X, they are instead so fast that

expr {[clock clicks] == [clock clicks]}

never seems to return true (more than µs resolution). Other platforms still have had clicks = milliseconds, and this assumption is sometimes made in Tcl code, which can lead to bugs that don't show up on all platforms.

In other words, the uniqueness of this value is often high but notoriously unreliable, especially for cross-platform comparisons.

Use for unique numbers

An alternative source when generating unique IDs (cf. GUID and UUID) is info cmdcount.

Scott Beasley: I feel that info cmdcount is totally useless for Unique key generation. It stays very small in size for too long and changes at a MUCH lower rate then does clock clicks in a modern tcl (8.4-8.5) system. Not saying it couldn't be used as an "enhancement" number though in the generation process.

Lars H: Why is it a problem to be small? The need (as I understand it) is for uniqueness of values, not for having them look random.

Scott Beasley: A uuid is 128 bits. You need enough in terms of size and variation to generate one. I do see the value of info cmdcount in combination with clock clicks on older systems. I may look into that for my needs as well and publish my results.

Lars H: OK, so essentially a randomness argument — I'm generating these things, others are too, and we want to be reasonably sure there won't be a collision. Not all unique-IDs are supposed to be "universally" unique however, many just need to be locally unique.

Limitations

AMG: [clock clicks] has several shortcomings limiting its usefulness:

  • No guaranteed epoch
  • No guaranteed word size
  • No guaranteed rate

Because of the undefined epoch, [clock clicks] is suitable only for timing comparisons, i.e. taking the difference between before-and-after return values of [clock clicks]. (See also: time)

Because of the undefined word size, [clock clicks] return values may roll over unexpectedly. If a [clock clicks] difference value is negative when it should be positive, add 2**$tcl_platform(wordSize) to get the true difference value, provided the interval is not so long that multiple rollovers occurred.

Because of the undefined rate, [clock clicks] difference values are not useful on their own but may be compared to see the ratio between two intervals, or simply to check if one interval is longer or shorter than the other. For example:

proc compareTiming {a b {count 1}} {
    set result 0
    for {set step 0} {$step < $count} {incr step} {
        while {1} {
            set start [clock clicks]
            uplevel 1 $a
            set mid [clock clicks]
            uplevel 1 $b
            set end [clock clicks]
            set aTime [expr {$mid - $start}]
            set bTime [expr {$end - $mid}]
            if {$aTime && $bTime} {
                break
            }
        }
        if {$aTime < 0} {
            incr aTime [expr {2 ** $::tcl_platform(wordSize)}]
        }
        if {$bTime < 0} {
            incr bTime [expr {2 ** $::tcl_platform(wordSize)}]
        }
        set result [expr {$result + double($aTime - $bTime) / $bTime}]
    }
    expr {$result / $count}
}

For me, [compareTiming {lsort {z a y b x c w d v e u f}} {lsort {z a}} 1000000] returns 0.2359321885723455, meaning that the longer list takes 23% longer to sort than the shorter list, averaged over one million trials.

Well, even this isn't fully accurate, since the uplevel adds some degree of overhead to both scripts being timed, and that overhead would have to be subtracted from the denominator in order to get the right ratio.