Nicolas Cellier uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-nice.830.mcz
==================== Summary ====================
Name: Collections-nice.830
Author: nice
Time: 7 May 2019, 9:25:17.144861 am
UUID: 3eccc0fe-9098-4c67-ad2b-78b02e5287e5
Ancestors: Collections-nice.829, Collections-nice.499
Merge: Collections-nice.829, Collections-nice.499
Rename RunArray unique selector #addLast:times: as #add:withOccurrences:
It's a bit less expressive but it's universal.
Deprecate #addLast:times:
After 6 years purgatory in inbox without further complaints, now is the last time I add an occurrence of this change.
=============== Diff against Collections-nice.829 ===============
Item was added:
+ ----- Method: RunArray>>add:withOccurrences: (in category 'adding') -----
+ add: value withOccurrences: times
+ "Add value as the last element of the receiver, the given number of times"
+ times = 0 ifTrue: [ ^self ].
+ lastIndex := nil. "flush access cache"
+ (runs size=0 or: [values last ~= value])
+ ifTrue:
+ [runs := runs copyWith: times.
+ values := values copyWith: value]
+ ifFalse:
+ [runs at: runs size put: runs last+times]!
Item was removed:
- ----- Method: RunArray>>addLast:times: (in category 'adding') -----
- addLast: value times: times
- "Add value as the last element of the receiver, the given number of times"
- times = 0 ifTrue: [ ^self ].
- lastIndex := nil. "flush access cache"
- (runs size=0 or: [values last ~= value])
- ifTrue:
- [runs := runs copyWith: times.
- values := values copyWith: value]
- ifFalse:
- [runs at: runs size put: runs last+times]!
Nicolas Cellier uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-nice.499.mcz
==================== Summary ====================
Name: Collections-nice.499
Author: nice
Time: 25 January 2013, 11:09:44.244 pm
UUID: a0703731-567b-4e87-9fbc-94cfbeed1534
Ancestors: Collections-bf.498
Rename RunArray unique selector #addLast:times: as #add:withOccurrences:
It's a bit less expressive but it's universal.
Deprecate #addLast:times:
=============== Diff against Collections-bf.498 ===============
Item was added:
+ ----- Method: RunArray>>add:withOccurrences: (in category 'adding') -----
+ add: value withOccurrences: times
+ "Add value as the last element of the receiver, the given number of times"
+ times = 0 ifTrue: [ ^self ].
+ lastIndex := nil. "flush access cache"
+ (runs size=0 or: [values last ~= value])
+ ifTrue:
+ [runs := runs copyWith: times.
+ values := values copyWith: value]
+ ifFalse:
+ [runs at: runs size put: runs last+times]!
Item was changed:
----- Method: RunArray>>addLast:times: (in category 'adding') -----
+ addLast: value times: times
- addLast: value times: times
"Add value as the last element of the receiver, the given number of times"
+ self deprecated: 'use add:withOccurrences:'.
+ ^self add: value withOccurrences: times!
- times = 0 ifTrue: [ ^self ].
- lastIndex := nil. "flush access cache"
- (runs size=0 or: [values last ~= value])
- ifTrue:
- [runs := runs copyWith: times.
- values := values copyWith: value]
- ifFalse:
- [runs at: runs size put: runs last+times]!
Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-nice.1227.mcz
==================== Summary ====================
Name: Kernel-nice.1227
Author: nice
Time: 6 May 2019, 9:16:48.105337 am
UUID: 2ae4c2a9-6e23-4f1b-90d3-6251a4766ba0
Ancestors: Kernel-nice.1226, Kernel-nice.1216
Merge: Kernel-nice.1226, Kernel-nice.1216
(durationToRun)
=============== Diff against Kernel-nice.1226 ===============
Item was changed:
----- Method: BlockClosure>>durationToRun (in category 'evaluating') -----
durationToRun
+ "Answer the duration taken before this block returns."
+ ^ Time durationToRun: self
- "Answer the duration taken to execute this block."
-
-
-
- ^ Duration milliSeconds: self timeToRun
-
-
-
!
Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-nice.1216.mcz
==================== Summary ====================
Name: Kernel-nice.1216
Author: nice
Time: 24 April 2019, 12:00:26.112717 am
UUID: e5e62c80-604a-4a15-a0ce-ec6486a0e3c0
Ancestors: Kernel-eem.1215
Connect #durationToRun to new high-resolution clock driven durationToRun: provided by Chronology-Core-nice.41
This is a must for micro-benchmarks.
=============== Diff against Kernel-eem.1215 ===============
Item was changed:
----- Method: BlockClosure>>durationToRun (in category 'evaluating') -----
durationToRun
+ "Answer the duration taken before this block returns."
+ ^ Time durationToRun: self
- "Answer the duration taken to execute this block."
-
-
-
- ^ Duration milliSeconds: self timeToRun
-
-
-
!
Nicolas Cellier uploaded a new version of Chronology-Core to project The Trunk:
http://source.squeak.org/trunk/Chronology-Core-nice.42.mcz
==================== Summary ====================
Name: Chronology-Core-nice.42
Author: nice
Time: 26 April 2019, 7:27:43.413216 pm
UUID: fd909f2b-275e-f44c-91fa-076eb32d64c7
Ancestors: Chronology-Core-nice.41
Make usage of highResolution clock for block-timing a Preference.
This is because TSC are not reliable enough on old CPU (or not available).
Always print duration subseconds by group of 3 digits (ms, us, ns)
=============== Diff against Chronology-Core-nice.41 ===============
Item was changed:
----- Method: Duration>>printOn: (in category 'squeak protocol') -----
printOn: aStream
"Format as per ANSI 5.8.2.16: [-]D:HH:MM:SS[.S]" | d h m s n |
d := self days abs.
h := self hours abs.
m := self minutes abs.
s := self seconds abs truncated.
n := self nanoSeconds abs. self negative ifTrue: [ aStream nextPut: $- ].
d printOn: aStream. aStream nextPut: $:.
h < 10 ifTrue: [ aStream nextPut: $0. ].
h printOn: aStream. aStream nextPut: $:.
m < 10 ifTrue: [ aStream nextPut: $0. ].
m printOn: aStream. aStream nextPut: $:.
s < 10 ifTrue: [ aStream nextPut: $0. ].
s printOn: aStream.
n = 0 ifFalse:
[ | z ps |
aStream nextPut: $..
ps := n printString padded: #left to: 9 with: $0.
z := ps findLast: [ :c | c asciiValue > $0 asciiValue ].
+ ps from: 1 to: z + 2 // 3 * 3 do: [ :c | aStream nextPut: c ] ]
- ps from: 1 to: z do: [ :c | aStream nextPut: c ] ]
!
Item was changed:
Magnitude subclass: #Time
instanceVariableNames: 'seconds nanos'
+ classVariableNames: 'ClockPolicy HighResClockTicksPerMillisecond LastClockTick UseHighResClockForTiming'
- classVariableNames: 'ClockPolicy HighResClockTicksPerMillisecond LastClockTick'
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 changed:
----- Method: Time class>>durationToRun: (in category 'general inquiries') -----
durationToRun: timedBlock
+ "Answer a duration timedBlock takes to return its value"
- "Answer a duration timedBlock takes to return its value.
- Use high resolution clock if available."
+ ^(self nanosecondsToRun: timedBlock) nanoSeconds!
- | ticks |
- self highResClock = 0 ifTrue: [^Duration nanoSeconds: 1000 * (self microsecondsToRun: timedBlock)].
- ticks := self highResClock.
- timedBlock value.
- ticks := self highResClock - ticks.
- ^Duration nanoSeconds: 1000000* ticks // self highResClockTicksPerMillisecond!
Item was changed:
----- Method: Time class>>microsecondsToRun: (in category 'general inquiries') -----
microsecondsToRun: timedBlock
"Answer the number of microseconds timedBlock takes to return its value."
| startUsecs |
+ (self useHighResClockForTiming and: [self highResClock ~= 0])
+ ifTrue: [ ^(self nanosecondsToRunHighRes: timedBlock) + 500 // 1000].
startUsecs := self utcMicrosecondClock.
timedBlock value.
^self utcMicrosecondClock - startUsecs!
Item was added:
+ ----- 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)].
+ "Fallback to microseconds clock"
+ startUsecs := self utcMicrosecondClock.
+ timedBlock value.
+ ^self utcMicrosecondClock - startUsecs * 1000!
Item was added:
+ ----- 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 constant rate, and is synchronized between multi-core CPU"
+
+ | ticks |
+ ticks := self highResClock.
+ timedBlock value.
+ ^(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 added:
+ ----- Method: Time class>>useHighResClockForTiming (in category 'preferences') -----
+ useHighResClockForTiming
+ <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'
+ type: #Boolean>
+ ^UseHighResClockForTiming ifNil: [ false ]!
Nicolas Cellier uploaded a new version of Chronology-Core to project The Trunk:
http://source.squeak.org/trunk/Chronology-Core-nice.41.mcz
==================== Summary ====================
Name: Chronology-Core-nice.41
Author: nice
Time: 23 April 2019, 11:52:55.257088 pm
UUID: e4abf0f8-228d-4456-b296-92764394926c
Ancestors: Chronology-Core-dtl.40
Provide access to high resolution clock (if any).
This is especially useful for micro-benchmarks, so provide a #durationToRun: based on high-res clock if available.
As the name tells, it will answer a Duration rather than a number of milliseconds, microseconds or whatever...
A duration is way more universal and self-explaining than currently obscure Integer encoding returned by:
[100 factorial] timeToRun.
The aim is either to provide a new #durationToRun selector, or replace #timeToRun semantics...
Provide a microsecondsToRun: fallback in case the host does not provide a high resolution clock.
Notes: the number of ticks per millisecond for the high-res clock is roughly estimated by a busy loop like found in the AndreasSystemProfiler.
It is reset at startup, and initialized once at first use with the assumption that it will be constant.
=============== Diff against Chronology-Core-dtl.40 ===============
Item was changed:
Magnitude subclass: #Time
instanceVariableNames: 'seconds nanos'
+ classVariableNames: 'ClockPolicy HighResClockTicksPerMillisecond LastClockTick'
- classVariableNames: 'ClockPolicy LastClockTick'
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 added:
+ ----- Method: Time class>>durationToRun: (in category 'general inquiries') -----
+ durationToRun: timedBlock
+ "Answer a duration timedBlock takes to return its value.
+ Use high resolution clock if available."
+
+ | ticks |
+ self highResClock = 0 ifTrue: [^Duration nanoSeconds: 1000 * (self microsecondsToRun: timedBlock)].
+ ticks := self highResClock.
+ timedBlock value.
+ ticks := self highResClock - ticks.
+ ^Duration nanoSeconds: 1000000* ticks // self highResClockTicksPerMillisecond!
Item was added:
+ ----- Method: Time class>>estimateHighResClockTicksPerMillisecond (in category 'clock') -----
+ estimateHighResClockTicksPerMillisecond
+
+ | t0 t1 t2 t3 |
+
+ "Count the ticks ellapsed during a 10ms busy loop"
+ t0 := Time utcMicrosecondClock + 200.
+ [Time utcMicrosecondClock >= t0] whileFalse.
+ t1 := Smalltalk highResClock.
+ [Time utcMicrosecondClock >= (t0 + 10000)] whileFalse.
+ t1 := Smalltalk highResClock - t1 * 1000 // (Time utcMicrosecondClock - t0).
+
+ "Count the ticks ellapsed during a 20ms busy loop"
+ t0 := Time utcMicrosecondClock + 200.
+ [Time utcMicrosecondClock >= t0] whileFalse.
+ t2 := Smalltalk highResClock.
+ [Time utcMicrosecondClock >= (t0 + 20000)] whileFalse.
+ t2 := Smalltalk highResClock - t2 * 1000 // (Time utcMicrosecondClock - t0).
+
+ "Count the ticks ellapsed during a 30ms busy loop"
+ t0 := Time utcMicrosecondClock + 200.
+ [Time utcMicrosecondClock >= t0] whileFalse.
+ t3 := Smalltalk highResClock.
+ [Time utcMicrosecondClock >= (t0 + 30000)] whileFalse.
+ t3 := Smalltalk highResClock - t3 * 1000 // (Time utcMicrosecondClock - t0).
+
+ "Take the median of the 3 estimates as the best"
+ ^ t1 <= t2
+ ifTrue: [t2 <= t3
+ ifTrue: [t2]
+ ifFalse: [t1 <= t3
+ ifTrue: [t3]
+ ifFalse: [t1]]]
+ ifFalse: [t1 <= t3
+ ifTrue: [t1]
+ ifFalse: [t2 <= t3
+ ifTrue: [t3]
+ ifFalse: [t2]]]!
Item was added:
+ ----- Method: Time class>>highResClock (in category 'clock') -----
+ highResClock
+ "Time highResClock"
+ "Primitive. Answer the value of the high resolution clock if this computer has one.
+ Usually, this should be the highest resolution value available, for example on Intel
+ it will be the value of the time stamp counter register."
+ <primitive: 'primitiveHighResClock'>
+ ^0!
Item was added:
+ ----- 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
"Time initialize"
"Initialize at startup time to protect for the case of an image saved with bad LastClockTick"
LastClockTick := 0.
+
+ HighResClockTicksPerMillisecond := 0.
"self clockPolicy: #acceptPlatformTime."
self clockPolicy: #monotonicAllowDuplicates.
"self clockPolicy: #monotonicForceMicrosecondIncrement."
"self clockPolicy: #monotonicForceNanosecondIncrement."
!
Item was added:
+ ----- Method: Time class>>microsecondsToRun: (in category 'general inquiries') -----
+ microsecondsToRun: timedBlock
+ "Answer the number of microseconds timedBlock takes to return its value."
+
+ | startUsecs |
+ startUsecs := self utcMicrosecondClock.
+ timedBlock value.
+ ^self utcMicrosecondClock - startUsecs!
Item was changed:
----- Method: Time class>>millisecondsToRun: (in category 'general inquiries') -----
millisecondsToRun: timedBlock
"Answer the number of milliseconds timedBlock takes to return its value."
+ ^(self microsecondsToRun: timedBlock) + 500 // 1000!
- | startUsecs |
- startUsecs := self utcMicrosecondClock.
- timedBlock value.
- ^self utcMicrosecondClock - startUsecs + 500 // 1000!
David T. Lewis uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System-dtl.1062.mcz
==================== Summary ====================
Name: System-dtl.1062
Author: dtl
Time: 5 May 2019, 10:54:56.642077 pm
UUID: c527ef41-51fb-4e49-b00a-90a9a09a935d
Ancestors: System-cmm.1061
If CodeLoader is loading a script that begins with a Unix shebang line, then skip over line one of the script. This accomodates the case of an executable Unix shell script that starts a Squeak image, then feeds itself to Squeak as a start script. For example, an executable script file might contain this:
#!/usr/local/bin/squeak --
Transcript show: 'Hello, world'; cr.
=============== Diff against System-cmm.1061 ===============
Item was added:
+ ----- Method: CodeLoader>>allButShebangLine: (in category 'private') -----
+ allButShebangLine: contentsString
+ "If tontentsString begins with '#!!' then assume that it contains a Unix
+ shebang line should be skipped prior to evaluating the contents."
+
+ (contentsString beginsWith: '#!!')
+ ifTrue: [contentsString lineIndicesDo: [:line :end :endOfLine |
+ ^ contentsString allButFirst: endOfLine ]]
+ ifFalse: [^ contentsString]
+
+ " CodeLoader new allButShebangLine:
+ '#!!/usr/llocal/bin/squeak --
+ Transcript cr; show: ''Hello world!!''
+ ' "!
Item was changed:
----- Method: CodeLoader>>installSourceFile: (in category 'installing') -----
installSourceFile: aStream
"Install the previously loaded source file"
| contents trusted |
aStream ifNil:[^self error:'No content to install'].
trusted := SecurityManager default positionToSecureContentsOf: aStream.
trusted ifFalse:[(SecurityManager default enterRestrictedMode)
ifFalse:[ aStream close.
^ self error:'Insecure content encountered']].
+ contents := self allButShebangLine: aStream upToEnd unzipped asString.
- contents := aStream upToEnd unzipped asString.
(aStream respondsTo: #close) ifTrue:[aStream close].
^contents readStream fileIn!