Marcel Taeumel uploaded a new version of Chronology-Core to project The Trunk: http://source.squeak.org/trunk/Chronology-Core-mt.87.mcz
==================== Summary ====================
Name: Chronology-Core-mt.87 Author: mt Time: 25 July 2023, 10:29:46.67268 am UUID: 76a3f1ce-b428-8e44-8317-f80bc70eba42 Ancestors: Chronology-Core-dtl.86
Revise #nanosecondsToRunHighRes: to be somewhat useful: - Convert ticks-to-nanos for each block run, not constant per session anymore - Let a block run for at least 10 milliseconds to reliably convert ticks to time. - Sanity check for core switch by checking monotonicity of value.
Time nanosecondsToRunHighRes: [Morph new].
Note that most results (even for 'Object new') seem to be microseconds at best. No nano-precision. See #microsecondsToRun: and #useHighResClockForTiming.
[Object new] bench. " '65,400,000 per second. 15.3 nanoseconds per run. 38.29234 % GC time.' " 10 timesCollect: [Time nanosecondsToRunHighRes: [Object new]] " #(7914 1948 862 321 135 231 312 464 240 402) "
At least that high-res clock will not distort #timeToRun values (milliseconds) anymore:
Time useHighResClockForTiming: false. 5 timesCollect: [[Project current world imageForm] timeToRun]. "#(241 224 248 226 222) " Time useHighResClockForTiming: true. 5 timesCollect: [[Project current world imageForm] timeToRun]. " #(229 215 220 224 225) "
=============== Diff against Chronology-Core-dtl.86 ===============
Item was changed: Magnitude subclass: #Time instanceVariableNames: 'seconds nanos' + classVariableNames: 'ClockPolicy LastClockTick UpdateVMTimeZoneCacheAt UseHighResClockForTiming' - classVariableNames: 'ClockPolicy HighResClockTicksPerMillisecond LastClockTick UpdateVMTimeZoneCacheAt UseHighResClockForTiming' poolDictionaries: 'ChronologyConstants' category: 'Chronology-Core'!
!Time commentStamp: 'dew 10/23/2004 17:58' prior: 0! This represents a particular point in time during any given day. For example, '5:19:45 pm'.
If you need a point in time on a particular day, use DateAndTime. If you need a duration of time, use Duration. !
Item was removed: - ----- Method: Time class>>highResClockTicksPerMillisecond (in category 'clock') ----- - highResClockTicksPerMillisecond - HighResClockTicksPerMillisecond = 0 - ifTrue: - [HighResClockTicksPerMillisecond := self estimateHighResClockTicksPerMillisecond]. - ^HighResClockTicksPerMillisecond!
Item was changed: ----- Method: Time class>>initialize (in category 'class initialization') ----- initialize " self initialize "
LastClockTick ifNil: [ LastClockTick := 0 ]. - HighResClockTicksPerMillisecond ifNil: [ HighResClockTicksPerMillisecond := 0 ]. - ClockPolicy ifNil: [ "self clockPolicy: #acceptPlatformTime." self clockPolicy: #monotonicAllowDuplicates. "self clockPolicy: #monotonicForceMicrosecondIncrement." "self clockPolicy: #monotonicForceNanosecondIncrement." ]!
Item was changed: ----- Method: Time class>>nanosecondsToRun: (in category 'general inquiries') ----- nanosecondsToRun: timedBlock "Answer the number of nanoseconds timedBlock takes to return its value. Use high resolution clock if available and preferred."
| startUsecs | (self useHighResClockForTiming and: [self highResClock ~= 0]) + ifTrue: [^ (self nanosecondsToRunHighRes: timedBlock)]. - ifTrue: [ ^(self nanosecondsToRunHighRes: timedBlock)]. "Fallback to microseconds clock" startUsecs := self utcMicrosecondClock. timedBlock value. ^self utcMicrosecondClock - startUsecs * 1000!
Item was changed: ----- Method: Time class>>nanosecondsToRunHighRes: (in category 'general inquiries') ----- nanosecondsToRunHighRes: timedBlock "Answer the number of nanoseconds timedBlock takes to return its value using high resolution clock. + This assumes that high resolution clock is available, has a somewhat constant rate, and is synchronized between multi-core CPU. Let the timer run at least 10 milliseconds to convert ticks to nanoseconds more reliably." - This assumes that high resolution clock is available, has a constant rate, and is synchronized between multi-core CPU"
+ | start ticks1 ticks2 ticks3 delta overhead | + ticks1 := self highResClock. + start := self utcMicrosecondClock. - | ticks | - ticks := self highResClock. timedBlock value. + ticks2 := self highResClock. + [(delta := self utcMicrosecondClock - start) < 10000 "10 ms"] whileTrue. + ticks3 := self highResClock. + overhead := (self highResClock - self highResClock) negated. + (ticks1 < ticks2 and: [ticks2 < ticks3] and: [overhead > 0]) ifFalse: [ + "Try again. We probably switched cores by accident." + ^ self nanosecondsToRunHighRes: timedBlock]. + ^ (ticks2 - ticks1 + - overhead "subtract the ticks taken by the call to highResClock itself" + * 1e3 // (ticks3 - ticks1 // delta)) "and convert ticks to nanoSeconds"! - ^(self highResClock - ticks - + (self highResClock - self highResClock ) "subtract the ticks taken by the call to highResClock itself" - * 1e6 // self highResClockTicksPerMillisecond) "and convert ticks to nanoSeconds"!
Item was changed: ----- Method: Time class>>startUp: (in category 'system startup') ----- startUp: resuming
+ resuming ifTrue: [LastClockTick := 0]! - resuming ifTrue: [ - LastClockTick := 0. - HighResClockTicksPerMillisecond := 0 ]!
Item was changed: ----- Method: Time class>>useHighResClockForTiming (in category 'preferences') ----- useHighResClockForTiming + <preference: 'Use high-resolution clock for timing' - <preference: 'Use high resolution clock for timing' category: 'performance' + description: 'This is used for measuring time ellapsed for running a block. High-resolution clocks (known as TSC) are counter embedded on CPU and incremented at each cycle. They enable timing close to the nanosecond for GHz CPU. However, on older models, they might have a non constant rate depending on power saving: converting ticks to seconds is not reliable in this case, but knowing the number of cycles taken to perform the task is still a valuable information. TSC might also be un-synchronized between the multi-cores: if Squeak process is switched from 1 core to another during the timing, timing results could be random. If you have a recent CPU, you might prefer this option' - description: 'This is used for measuring time ellapsed for running a block. High resolution clocks (known as TSC) are counter embedded on CPU and incremented at each cycle. They enable timing close to the nanosecond for GHz CPU. However, on older models, they might have a non constant rate depending on power saving: converting ticks to seconds is not reliable in this case, but knowing the number of cycles taken to perform the task is still a valuable information. TSC might also be un-synchronized between the multi-cores: if Squeak process is switched from 1 core to another during the timing, timing results could be random. If you have a recent CPU, you might prefer this option' type: #Boolean> ^UseHighResClockForTiming ifNil: [ false ]!
squeak-dev@lists.squeakfoundation.org