Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
534 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
class MutexSuite usingPlatform: platform andHarness: harness = Value ( | ||
| private Benchmark = harness Benchmark. | ||
private processes = platform processes. | ||
private Channel = processes Channel. | ||
private Process = processes Process. | ||
private Array = platform kernel Array. | ||
private Condition = platform threading Condition. | ||
private Delay = platform threading Delay. | ||
private Mutex = platform threading Mutex. | ||
private Thread = platform threading Thread. | ||
|)( | ||
(* A simple PRNG, to be as portable as possible. *) | ||
public class Random new: seed = ( | ||
| private seed ::= seed. | ||
private gotNextGaussian ::= false. | ||
private nextNextGaussian ::= 0.0. | | ||
) ( | ||
public next = ( | ||
seed:: ((seed * 1309) + 13849) & 65535. | ||
^ seed | ||
) | ||
|
||
(* Returns an integer within the range of [0, bound) *) | ||
public next: bound = ( | ||
^ next % bound | ||
) | ||
|
||
(* Returns a double uniformly distributed in the range of [0.0, 1.0) *) | ||
public nextDouble = ( | ||
^ next // 65536 | ||
) | ||
|
||
public nextBoolean = ( | ||
^ next < 32768 | ||
) | ||
|
||
(* Returns a double normally distributed with mean 0.0 | ||
and standard deviation of 1.0 *) | ||
public nextGaussian = ( | ||
| v1 v2 s multiplier | | ||
gotNextGaussian ifTrue: [ | ||
gotNextGaussian:: false. | ||
^ nextNextGaussian ]. | ||
|
||
v1:: (2.0 * nextDouble) - 1.0. | ||
v2:: (2.0 * nextDouble) - 1.0. | ||
s:: (v1 * v1) + (v2 * v2). | ||
|
||
[s >= 1.0 or: [s = 0.0]] whileTrue: [ | ||
v1:: (2.0 * nextDouble) - 1.0. | ||
v2:: (2.0 * nextDouble) - 1.0. | ||
s:: (v1 * v1) + (v2 * v2). | ||
]. | ||
|
||
multiplier:: (-2.0 * s log // s) sqrt. | ||
nextNextGaussian:: v2 * multiplier. | ||
gotNextGaussian:: true. | ||
^ v1 * multiplier | ||
) | ||
) : ( | ||
public new = ( | ||
^ new: 74755 | ||
) | ||
) | ||
|
||
(* === Savina Microbenchmarks === *) | ||
|
||
public class Philosophers new = Benchmark <: Value ()( | ||
|
||
private class Arbitrator new: numPhil numRounds: numRounds = ( | ||
| private numPhil = numPhil. | ||
private numRounds = numRounds. | ||
private forks = Array new: numPhil withAll: false. | ||
private numExitedPhilosophers ::= 0. | ||
private m = Mutex new. | ||
private m2 = Mutex new. | ||
|)( | ||
private hungry: leftForkId = ( | ||
| rightForkId | | ||
rightForkId:: 1 + ((leftForkId + 1) % numPhil). | ||
|
||
((forks at: leftForkId) or: [forks at: rightForkId]) | ||
ifTrue: [ | ||
^ false. | ||
] | ||
ifFalse: [ | ||
forks at: leftForkId put: true. | ||
forks at: rightForkId put: true. | ||
^ true ] | ||
) | ||
|
||
private done: leftForkId = ( | ||
| rightForkId | | ||
rightForkId:: 1 + ((leftForkId + 1) % numPhil). | ||
|
||
forks at: leftForkId put: false. | ||
forks at: rightForkId put: false. | ||
) | ||
|
||
private exit = ( | ||
numExitedPhilosophers:: numExitedPhilosophers + 1. | ||
|
||
numPhil = numExitedPhilosophers ifTrue: [ | ||
| forksTaken | | ||
forksTaken:: 0. | ||
forks do: [:f | f ifTrue: [ forksTaken:: forksTaken + 1 ] ]. | ||
forksTaken = 0 ifFalse: [ | ||
self error: 'invalid benchmark result'. | ||
]. | ||
] | ||
) | ||
|
||
public benchmark = ( | ||
|philosophers| | ||
philosophers:: Array new: numPhil. | ||
philosophers doIndexes: [:i | | ||
philosophers at: i put: (Thread spawn: [:id | | ||
| roundsSoFar isEating | | ||
roundsSoFar:: 0. | ||
[roundsSoFar < numRounds] whileTrue: [ | ||
m critical: [ | ||
isEating:: (hungry: id). | ||
]. | ||
|
||
isEating ifTrue: [ | ||
roundsSoFar:: roundsSoFar + 1. | ||
m critical: [done: id]. | ||
]. | ||
]. | ||
|
||
m2 critical: [ | ||
exit. | ||
]. | ||
] with: { i }) | ||
]. | ||
|
||
philosophers do: [:ph | ph join ]. | ||
^ true. | ||
) | ||
) | ||
|
||
public innerBenchmarkLoop: numRounds numThreads: threads = ( | ||
| arbitrator | | ||
arbitrator:: Arbitrator new: (threads - 1) numRounds: numRounds. | ||
^ arbitrator benchmark | ||
) | ||
) : ( | ||
public newInstance = ( ^ self new ) | ||
public setupVerifiedRun: run = ( run problemSize ) | ||
) | ||
|
||
|
||
public class ProducerConsumer new = Benchmark <: Value ()( | ||
private class SynchronizedRingBuffer new: capacity = ( | ||
| buffer = Array new: capacity. | ||
capacity = capacity. | ||
head ::= 1. (* points to next write location *) | ||
tail ::= 1. (* points to next read location *) | ||
size ::= 0. | ||
mutex = Mutex new. | ||
waitingProducers = mutex newCondition. | ||
waitingConsumers = mutex newCondition. | ||
| | ||
)( | ||
private add: val = ( | ||
buffer at: tail put: val. | ||
tail:: (tail % capacity) + 1. | ||
size:: size + 1. | ||
) | ||
|
||
private remove = ( | ||
|result| | ||
result:: buffer at: head. | ||
head:: (head % capacity) + 1. | ||
size:: size - 1. | ||
^ result. | ||
) | ||
|
||
public offer: val = ( | ||
mutex critical: [ | ||
(size = capacity) ifTrue: [ | ||
(*'producer wait' println.*) | ||
waitingProducers await. | ||
(*'producer woke up' println.*) | ||
]. | ||
|
||
add: val. | ||
size > 0 ifTrue: [ | ||
waitingConsumers signalOne. | ||
] | ||
] | ||
) | ||
|
||
public poll = ( | ||
mutex critical: [ | ||
|res| | ||
size > 0 ifFalse: [ | ||
(*'consumer wait' println.*) | ||
waitingConsumers await. | ||
(*'consumer woke up' println.*) | ||
]. | ||
res:: remove. | ||
size < capacity ifTrue:[ | ||
waitingProducers signalOne. | ||
]. | ||
^ res | ||
] | ||
) | ||
) | ||
|
||
private busyWait: limit = ( | ||
| test | | ||
test:: 0. | ||
limit timesRepeat: [ | ||
test:: test + 1 ]. | ||
^ test | ||
) | ||
|
||
public innerBenchmarkLoop: bufferSize numThreads: threads = ( | ||
|consumers producers buffer numCycles| | ||
consumers:: Array new: (threads / 2 ). | ||
producers:: Array new: (threads / 2 ). | ||
buffer:: SynchronizedRingBuffer new: bufferSize. | ||
numCycles:: bufferSize * 10. | ||
|
||
consumers doIndexes: [:i | | ||
consumers at: i put: (Thread spawn: [:id | | ||
| rand | | ||
rand:: Random new: id * 97 . | ||
numCycles timesRepeat: [ | ||
| rn | | ||
rn:: rand next: 1000. | ||
busyWait: rn. | ||
buffer poll. | ||
]. | ||
] with: { i }) | ||
]. | ||
|
||
producers doIndexes: [:i | | ||
producers at: i put: (Thread spawn: [:id | | ||
| rand | | ||
rand:: Random new: id * 53. | ||
numCycles timesRepeat: [ | ||
| rn | | ||
rn:: rand next: 1000. | ||
busyWait: rn. | ||
buffer offer: rn. | ||
]. | ||
] with: { i }) | ||
]. | ||
|
||
consumers do: [:ph | ph join ]. | ||
producers do: [:ph | ph join ]. | ||
|
||
^ true. | ||
) | ||
) : ( | ||
public newInstance = ( ^ self new ) | ||
public setupVerifiedRun: run = ( run problemSize ) | ||
) | ||
) |
Oops, something went wrong.