Created
September 10, 2018 16:22
-
-
Save Pentan/74d8611fab002eaf8f2da29cc51c7e05 to your computer and use it in GitHub Desktop.
Swift Array with Dispatch concurrent performance somparison
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
import Foundation | |
print("array bench") | |
print(" -o : output rendered image as \"result.ppm\"") | |
print(" -w Number : render image width") | |
print(" -h Number : render image height") | |
print(" -p Number : number of points") | |
print("----------") | |
var width = 4096 | |
var height = 2048 | |
var numPoints = 100 | |
var printPPM = false | |
var iarg = 1 | |
while iarg < CommandLine.arguments.count { | |
let a = CommandLine.arguments[iarg] | |
if a.compare("-o") == .orderedSame { | |
printPPM = true | |
} else if a.compare("-w") == .orderedSame { | |
iarg += 1 | |
let b = CommandLine.arguments[iarg] | |
width = Int(b)! | |
} else if a.compare("-h") == .orderedSame { | |
iarg += 1 | |
let b = CommandLine.arguments[iarg] | |
height = Int(b)! | |
} else if a.compare("-p") == .orderedSame { | |
iarg += 1 | |
let b = CommandLine.arguments[iarg] | |
numPoints = Int(b)! | |
} else { | |
print("unknown option \(a)") | |
} | |
iarg += 1 | |
} | |
print("width:\(width)") | |
print("height:\(height)") | |
print("number of points:\(numPoints)") | |
print("save result:\(printPPM)") | |
print("----------") | |
struct Point { | |
var x = 0.0 | |
var y = 0.0 | |
func distance(_ p:Point) -> Double { | |
let vx = p.x - x | |
let vy = p.y - y | |
return (vx * vx + vy * vy).squareRoot() | |
} | |
} | |
print("initializing...") | |
var points:[Point] = [] | |
points.reserveCapacity(numPoints) | |
srand48(time(nil)) | |
for _ in 0..<numPoints { | |
var p = Point() | |
p.x = drand48() | |
p.y = drand48() | |
points.append(p) | |
// print("(\(p.x), \(p.y))") | |
} | |
class Result { | |
var d = 0.0 | |
} | |
var results:[Result] = [] | |
results.reserveCapacity(width * height) | |
for _ in 0..<(width * height) { | |
results.append(Result()) | |
} | |
var startTime:TimeInterval | |
var finishTime:TimeInterval | |
// serial | |
print("start serial with iterator loop") | |
startTime = Date.timeIntervalSinceReferenceDate | |
for iy in 0..<height { | |
for ix in 0..<width { | |
let i = ix + iy * width | |
var p = Point() | |
p.x = Double(ix) / Double(width) | |
p.y = Double(iy) / Double(height) | |
var min_d = 1e10 | |
for pnt in points { | |
let tmp_d = pnt.distance(p) | |
if min_d > tmp_d { | |
min_d = tmp_d | |
} | |
} | |
results[i].d = min_d | |
} | |
} | |
finishTime = Date.timeIntervalSinceReferenceDate | |
print("done:\(finishTime - startTime)[sec]") | |
// concurrent | |
print("start concurrent with iterator loop") | |
startTime = Date.timeIntervalSinceReferenceDate | |
DispatchQueue.concurrentPerform(iterations: height) { (iy) in | |
for ix in 0..<width { | |
let i = ix + iy * width | |
var p = Point() | |
p.x = Double(ix) / Double(width) | |
p.y = Double(iy) / Double(height) | |
var min_d = 1e10 | |
for pnt in points { | |
let tmp_d = pnt.distance(p) | |
if min_d > tmp_d { | |
min_d = tmp_d | |
} | |
} | |
results[i].d = min_d | |
} | |
} | |
finishTime = Date.timeIntervalSinceReferenceDate | |
print("done:\(finishTime - startTime)[sec]") | |
// serial | |
print("start serial with index loop") | |
startTime = Date.timeIntervalSinceReferenceDate | |
for iy in 0..<height { | |
for ix in 0..<width { | |
let i = ix + iy * width | |
var p = Point() | |
p.x = Double(ix) / Double(width) | |
p.y = Double(iy) / Double(height) | |
var min_d = 1e10 | |
for k in 0..<points.count { | |
let pnt = points[k] | |
let tmp_d = pnt.distance(p) | |
if min_d > tmp_d { | |
min_d = tmp_d | |
} | |
} | |
results[i].d = min_d | |
} | |
} | |
finishTime = Date.timeIntervalSinceReferenceDate | |
print("done:\(finishTime - startTime)[sec]") | |
// concurrent | |
print("start concurrent with index loop") | |
startTime = Date.timeIntervalSinceReferenceDate | |
DispatchQueue.concurrentPerform(iterations: height) { (iy) in | |
for ix in 0..<width { | |
let i = ix + iy * width | |
var p = Point() | |
p.x = Double(ix) / Double(width) | |
p.y = Double(iy) / Double(height) | |
var min_d = 1e10 | |
for k in 0..<points.count { | |
let pnt = points[k] | |
let tmp_d = pnt.distance(p) | |
if min_d > tmp_d { | |
min_d = tmp_d | |
} | |
} | |
results[i].d = min_d | |
} | |
} | |
finishTime = Date.timeIntervalSinceReferenceDate | |
print("done:\(finishTime - startTime)[sec]") | |
// | |
if printPPM { | |
print("saving result.ppm") | |
func clampColor(_ x:Double) -> Int { | |
return Int(min(255.0, pow(max(0.0, x), 1.0 / 2.2) * 255.0)) | |
} | |
var maxD = 0.0 | |
for r in results { | |
let d = r.d | |
if maxD < d { | |
maxD = d | |
} | |
} | |
if maxD > 1.0 { | |
maxD = 1.0 | |
} | |
var resStr = "P3\n\(width) \(height)\n255\n" | |
for r in results { | |
let s = 1.0 - (r.d / maxD) | |
let c = clampColor(s) | |
resStr += "\(c) \(c) \(c)\n" | |
} | |
let url = URL(fileURLWithPath: "result.ppm") | |
do { | |
try resStr.write(to: url, atomically: true, encoding: .utf8) | |
print("result saved to \(url.absoluteString)") | |
} catch { | |
print("result save failed to \(url.absoluteString)") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment