Skip to content

Instantly share code, notes, and snippets.

@lolgab
Created October 23, 2018 15:07
Show Gist options
  • Save lolgab/b8b2a7da03b2c4572fe32edf8c73d4c0 to your computer and use it in GitHub Desktop.
Save lolgab/b8b2a7da03b2c4572fe32edf8c73d4c0 to your computer and use it in GitHub Desktop.
NBody Performance Test with using Scala Native CStrucs and malloc
import scalanative.native._
import stdlib.malloc
object implicits {
type MVect3 = CStruct3[Double, Double, Double]
type MutableBody = CStruct3[MVect3, MVect3, Double]
implicit class MVect3Ops(val ptr: Ptr[MVect3]) extends AnyVal {
def x: Double = !ptr._1
def y: Double = !ptr._2
def z: Double = !ptr._3
def x_=(v: Double): Unit = !ptr ._1 = v
def y_=(v: Double): Unit = !ptr ._2 = v
def z_=(v: Double): Unit = !ptr ._3 = v
def zero(): Unit = {
x = 0.0
y = 0.0
z = 0.0
}
}
implicit class MutableBodyOps(val ptr: Ptr[MutableBody]) extends AnyVal {
def p: Ptr[MVect3] = ptr._1
def v: Ptr[MVect3] = ptr._2
def mass: Double = !ptr._3
def mass_=(v: Double): Unit = !ptr._3 = v
}
}
class NBodyMutableClass(val numBodies: Int, val dt: Double) {
import implicits._
private val bodies = malloc(numBodies * sizeof[MutableBody]).cast[Ptr[MutableBody]]
for(i <- 0 until numBodies) (bodies + i).mass = 1e-10
private val accel = malloc(numBodies * sizeof[MVect3]).cast[Ptr[MVect3]]
initBodies()
def initBodies(): Unit = {
bodies.mass = 1.0
for(i <- 1 until numBodies) {
(bodies + i).p.x = i
(bodies + i).v.y = math.sqrt(1.0/i)
}
}
def forSim(steps: Int): Unit = {
for(_ <- 1 to steps) {
for(i <- 0 until numBodies) {
(accel + i).zero()
}
for (i <- 0 until numBodies) {
val pi = bodies + i
val acceli = accel + i
for (j <- i+1 until numBodies) {
val pj = bodies + j
val dx = pi.p.x-pj.p.x
val dy = pi.p.y-pj.p.y
val dz = pi.p.z-pj.p.z
val dist = math.sqrt(dx*dx+dy*dy+dz*dz)
val magi = pj.mass/(dist*dist*dist)
val magj = pi.mass/(dist*dist*dist)
acceli.x -= magi*dx
acceli.y -= magi*dy
acceli.z -= magi*dz
val accelj = (accel + j)
accelj.x += magj*dx
accelj.y += magj*dy
accelj.z += magj*dz
}
}
for(i <- 0 until numBodies) {
val p = bodies + i
val acceli = (accel + i)
p.v.x += acceli.x*dt
p.v.y += acceli.y*dt
p.v.z += acceli.z*dt
p.p.x += p.v.x*dt
p.p.y += p.v.y*dt
p.p.z += p.v.z*dt
}
}
}
}
object MainTiming extends App {
def timeCode[T](timeRuns: Int)(body: => T): Seq[Double] = {
for(_ <- 1 to timeRuns) yield {
val start = System.nanoTime()
body
(System.nanoTime()-start)*1e-9
}
}
def printTimeInfo(times: Seq[Double]): Unit = {
val mean = times.sum/times.length
val rms = math.sqrt(times.map(x => (x-mean)*(x-mean)).sum/times.length)
println(s"mean = $mean, rms = $rms")
}
val numBodies = 1000
val dt = 0.01
val mutSim = new NBodyMutableClass(numBodies, dt)
println("Mutable Class:")
printTimeInfo(timeCode(5){ mutSim.forSim(100) })
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment