The Q6600
Benchmarks Game

n-body Pharo Smalltalk program

source code

"* The Computer Language Benchmarks Game
    https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
    contributed by Isaac Gouy *"!

Object subclass: #NBodySystem
   instanceVariableNames: 'bodies'
   classVariableNames: ''
   poolDictionaries: ''
   category: 'benchmarks game'!

Object subclass: #Body
   instanceVariableNames: 'x y z vx vy vz mass'
   classVariableNames: ''
   poolDictionaries: ''
   category: 'benchmarks game'!

Object subclass: #BenchmarksGame
   instanceVariableNames: ''
   classVariableNames: ''
   poolDictionaries: ''
   category: ''!

!Body class methodsFor: 'constants'!

daysPerYear
   ^365.24d0!

sun
   ^self new
      x: 0.0d0
      y: 0.0d0
      z: 0.0d0
      vx: 0.0d0
      vy: 0.0d0
      vz: 0.0d0
      mass: self solarMass!

uranus
   ^self new
      x: 1.28943695621391310d1
      y: -1.51111514016986312d1
      z: -2.23307578892655734d-1
      vx: 2.96460137564761618d-3 * self daysPerYear
      vy: 2.37847173959480950d-3 * self daysPerYear
      vz: -2.96589568540237556d-5 * self daysPerYear
      mass: 4.36624404335156298d-5 * self solarMass!

saturn
   ^self new
      x: 8.34336671824457987d0
      y: 4.12479856412430479d0
      z: -4.03523417114321381d-1
      vx: -2.76742510726862411d-3 * self daysPerYear
      vy: 4.99852801234917238d-3 * self daysPerYear
      vz: 2.30417297573763929d-5 * self daysPerYear
      mass: 2.85885980666130812d-4 * self solarMass!

solarMass
   ^4.0d0 * self pi * self pi!

pi
   ^3.141592653589793d0!

jupiter
   ^self new
      x: 4.84143144246472090d0
      y: -1.16032004402742839d0
      z: -1.03622044471123109d-1
      vx: 1.66007664274403694d-3 * self daysPerYear
      vy: 7.69901118419740425d-3 * self daysPerYear
      vz: -6.90460016972063023d-5 * self daysPerYear
      mass: 9.54791938424326609d-4 * self solarMass!

neptune
   ^self new
      x: 1.53796971148509165d1
      y: -2.59193146099879641d1
      z: 1.79258772950371181d-1
      vx: 2.68067772490389322d-3 * self daysPerYear
      vy: 1.62824170038242295d-3 * self daysPerYear
      vz: -9.51592254519715870d-5 * self daysPerYear
      mass: 5.15138902046611451d-5 * self solarMass! !


!Body methodsFor: 'accessing'!

z
   ^z!

x
   ^x!

mass
   ^mass!

x: d1 y: d2 z: d3 vx: d4 vy: d5 vz: d6 mass: d7
   x := d1.
   y := d2. 
   z := d3. 
   vx := d4.
   vy := d5.
   vz := d6.
   mass := d7!

y
   ^y! !

!Body methodsFor: 'nbody'!

offsetMomentum: anArray 
   | m |
   m := self class solarMass.
   vx := (anArray at: 1) negated / m.
   vy := (anArray at: 2) negated / m.
   vz := (anArray at: 3) negated / m!

decreaseVelocity: dx y: dy z: dz m: m
   vx := vx - (dx * m).
   vy := vy - (dy * m).
   vz := vz - (dz * m)!

positionAfter: dt
   x := x + (dt * vx).
   y := y + (dt * vy).
   z := z + (dt * vz)!

and: aBody velocityAfter: dt        
   | dx dy dz distance mag |
   dx := x - aBody x.
   dy := y - aBody y.
   dz := z - aBody z.
   
   distance := ((dx*dx) + (dy*dy) + (dz*dz)) sqrt.
   mag := dt / (distance * distance * distance).

   self decreaseVelocity: dx y: dy z: dz m: aBody mass * mag.   
   aBody increaseVelocity: dx y: dy z: dz m: mass * mag!

potentialEnergy: aBody
   | dx dy dz distance |
   dx := x - aBody x.
   dy := y - aBody y.
   dz := z - aBody z.

   distance := ((dx*dx) + (dy*dy) + (dz*dz)) sqrt.
   ^mass * aBody mass / distance!

addMomentumTo: anArray
   anArray at: 1 put: (anArray at: 1) + (vx * mass).
   anArray at: 2 put: (anArray at: 2) + (vy * mass).
   anArray at: 3 put: (anArray at: 3) + (vz * mass).
   ^anArray!

increaseVelocity: dx y: dy z: dz m: m
   vx := vx + (dx * m).
   vy := vy + (dy * m).
   vz := vz + (dz * m)!

kineticEnergy
   ^0.5d0 * mass * ((vx * vx) + (vy * vy) + (vz * vz))! !


!NBodySystem methodsFor: 'initialize-release'!

initialize
   bodies := OrderedCollection new
      add: Body sun; add: Body jupiter; add: Body saturn;
      add: Body uranus; add: Body neptune; yourself.

   bodies first offsetMomentum:
      (bodies inject: (Array with: 0.0d0 with: 0.0d0 with: 0.0d0)
         into: [:m :each | each addMomentumTo: m])! !

!NBodySystem methodsFor: 'nbody'!

after: dt
   1 to: bodies size do: [:i|
      i+1 to: bodies size do: [:j|                            
         (bodies at: i) and: (bodies at: j) velocityAfter: dt].
   ].   
   bodies do: [:each| each positionAfter: dt]!

energy
   | e |
   e := 0.0d0.
   1 to: bodies size do: [:i|       
      e := e + (bodies at: i) kineticEnergy.

      i+1 to: bodies size do: [:j| 
         e := e - ((bodies at: i) potentialEnergy: (bodies at: j))].
   ].
   ^e! !

!BenchmarksGame class methodsFor: 'initialize-release'!

do: n
   | bodies |
   bodies := NBodySystem new initialize.
   Stdio stdout print: bodies energy digits: 9; nl.
   n timesRepeat: [bodies after: 0.01d0].
   Stdio stdout print: bodies energy digits: 9; nl! !

!StdioStream methodsFor: 'benchmarks game'!

nl
   self nextPut: Character lf!

print: number digits: decimalPlaces
   | precision rounded |
   decimalPlaces <= 0 ifTrue: [^ number rounded printString].
   precision := (10 raisedTo: decimalPlaces negated) asFloat.
   rounded := number roundTo: precision.
   self nextPutAll: 
      ((rounded asScaledDecimal: decimalPlaces) printString copyUpTo: $s)! !


    

notes, command-line, and program output

NOTES:
64-bit Ubuntu quad core
Pharo8.0.0 build: 1122, commit: bbcdf97


Sun, 10 May 2020 04:03:30 GMT

MAKE:
cp /opt/src/pharo64-linux-stable/Pharo8.0.0-0-64bit-bbcdf97.image nbody.pharo_run.image
cp /opt/src/pharo64-linux-stable/Pharo8.0.0-0-64bit-bbcdf97.changes nbody.pharo_run.changes
ln -s /opt/src/pharo64-linux-stable/Pharo8.0-32bit-bbcdf97.sources .
cat Include/pharo/make.st

| prog |

(SystemWindow windowsIn: World
      satisfying: [:w | w model canDiscardEdits])
   do: [:w | w delete].

   "load program to be measured"
prog := Smalltalk getSystemAttribute: 3.
(prog notNil) ifTrue: [FileStream fileIn: prog].

ImageCleaner cleanUpForRelease.
Smalltalk garbageCollect.
SmalltalkImage current snapshot: true andQuit: true.


/opt/src/pharo64-linux-stable/pharo -headless nbody.pharo_run.image Include/pharo/make.st nbody.pharo 2>/dev/null
cat Include/pharo/main.st

BenchmarksGame do: (Smalltalk getSystemAttribute: 3) asInteger.!
SmalltalkImage current snapshot: false andQuit: true!



35.71s to complete and log all make actions

COMMAND LINE:
/opt/src/pharo64-linux-stable/pharo -headless nbody.pharo_run.image Include/pharo/main.st 50000000

PROGRAM OUTPUT:
-0.169075164
-0.169059907

pthread_setschedparam failed: Operation not permitted
This VM uses a separate heartbeat thread to update its internal clock
and handle events.  For best operation, this thread should run at a
higher priority, however the VM was unable to change the priority.  The
effect is that heavily loaded systems may experience some latency
issues.  If this occurs, please create the appropriate configuration
file in /etc/security/limits.d/ as shown below:

cat <<END | sudo tee /etc/security/limits.d/pharo.conf
*      hard    rtprio  2
*      soft    rtprio  2
END

and report to the pharo mailing list whether this improves behaviour.

You will need to log out and log back in for the limits to take effect.
For more information please see
https://github.com/OpenSmalltalk/opensmalltalk-vm/releases/tag/r3732#linux