Skip to content

Commit 244322c

Browse files
spacelanhuningxin
authored andcommitted
Add SIMD benchmarks for kazmath
1 parent 89a721e commit 244322c

File tree

13 files changed

+1005
-0
lines changed

13 files changed

+1005
-0
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// SIMD Kernel Benchmark Harness
2+
// Author: Peter Jensen
3+
4+
function Benchmark (config) {
5+
this.config = config;
6+
this.initOk = true; // Initialize all properties used on a Benchmark object
7+
this.cleanupOk = true;
8+
this.useAutoIterations = true;
9+
this.autoIterations = 0;
10+
this.actualIterations = 0;
11+
this.simdTime = 0;
12+
this.nonSimdTime = 0;
13+
}
14+
15+
function Benchmarks () {
16+
this.benchmarks = [];
17+
}
18+
19+
Benchmarks.prototype.add = function (benchmark) {
20+
this.benchmarks.push (benchmark);
21+
return this.benchmarks.length - 1;
22+
}
23+
24+
Benchmarks.prototype.runOne = function (benchmark) {
25+
26+
function timeKernel(kernel, iterations) {
27+
var start, stop;
28+
start = Date.now();
29+
kernel(iterations);
30+
stop = Date.now();
31+
return stop - start;
32+
}
33+
34+
function computeIterations() {
35+
var desiredRuntime = 1000; // milliseconds for longest running kernel
36+
var testIterations = 10; // iterations used to determine time for desiredRuntime
37+
38+
// Make the slowest kernel run for at least 500ms
39+
var simdTime = timeKernel(benchmark.config.kernelSimd, testIterations);
40+
var nonSimdTime = timeKernel(benchmark.config.kernelNonSimd, testIterations);
41+
var maxTime = simdTime > nonSimdTime ? simdTime : nonSimdTime;
42+
while (maxTime < 500) {
43+
testIterations *= 2;
44+
simdTime = timeKernel(benchmark.config.kernelSimd, testIterations);
45+
nonSimdTime = timeKernel(benchmark.config.kernelNonSimd, testIterations);
46+
maxTime = simdTime > nonSimdTime ? simdTime : nonSimdTime;
47+
}
48+
maxTime = simdTime > nonSimdTime ? simdTime : nonSimdTime;
49+
50+
// Compute iteration count for 1 second run of slowest kernel
51+
var iterations = Math.ceil(desiredRuntime * testIterations / maxTime);
52+
return iterations;
53+
}
54+
55+
// Initialize the kernels and check the correctness status
56+
if (!benchmark.config.kernelInit()) {
57+
benchmark.initOk = false;
58+
return false;
59+
}
60+
61+
// Determine how many iterations to use.
62+
if (benchmark.useAutoIterations) {
63+
benchmark.autoIterations = computeIterations();
64+
benchmark.actualIterations = benchmark.autoIterations;
65+
}
66+
else {
67+
benchmark.actualIterations = benchmark.config.kernelIterations;
68+
}
69+
70+
// Run the SIMD kernel
71+
benchmark.simdTime = timeKernel(benchmark.config.kernelSimd, benchmark.actualIterations);
72+
73+
// Run the non-SIMD kernel
74+
benchmark.nonSimdTime = timeKernel(benchmark.config.kernelNonSimd, benchmark.actualIterations);
75+
76+
// Do the final sanity check
77+
if (!benchmark.config.kernelCleanup()) {
78+
benchmark.cleanupOk = false;
79+
return false;
80+
}
81+
82+
return true;
83+
}
84+
85+
Benchmarks.prototype.report = function (benchmark, outputFunctions) {
86+
87+
function fillRight(str, width) {
88+
str += ""; // make sure it's a string
89+
while (str.length < width) {
90+
str += " ";
91+
}
92+
return str;
93+
}
94+
95+
function fillLeft(str, width) {
96+
str += ""; // make sure it's a string
97+
while (str.length < width) {
98+
str = " " + str;
99+
}
100+
return str;
101+
}
102+
103+
if (!benchmark.initOk) {
104+
outputFunctions.notifyError(fillRight(benchmark.config.kernelName + ": ", 23) + "FAILED INIT");
105+
return;
106+
}
107+
if (!benchmark.cleanupOk) {
108+
outputFunctions.notifyError(fillRight(benchmark.config.kernelName + ": ", 23) + "FAILED CLEANUP");
109+
return;
110+
}
111+
112+
var ratio = benchmark.nonSimdTime / benchmark.simdTime;
113+
ratio = ratio.toFixed(2);
114+
outputFunctions.notifyResult(
115+
fillRight(benchmark.config.kernelName + ": ", 23) +
116+
"Iterations(" + fillLeft(benchmark.actualIterations, 10) + ")" +
117+
", SIMD(" + fillLeft(benchmark.simdTime + "ms)", 8) +
118+
", Non-SIMD(" + fillLeft(benchmark.nonSimdTime + "ms)", 8) +
119+
", Speedup(" + ratio + ")");
120+
outputFunctions.timeData.labels.push(benchmark.config.kernelName);
121+
outputFunctions.timeData.datasets[0].data.push(benchmark.simdTime);
122+
outputFunctions.timeData.datasets[1].data.push(benchmark.nonSimdTime);
123+
outputFunctions.speedupData.labels.push(benchmark.config.kernelName);
124+
outputFunctions.speedupData.datasets[0].data.push(ratio);
125+
}
126+
127+
Benchmarks.prototype.runAll = function (outputFunctions, useAutoIterations) {
128+
if (typeof useAutoIterations === "undefined") {
129+
useAutoIterations = false;
130+
}
131+
for (var i = 0, n = this.benchmarks.length; i < n; ++i) {
132+
var benchmark = this.benchmarks[i];
133+
benchmark.useAutoIterations = useAutoIterations;
134+
this.runOne(benchmark);
135+
this.report(benchmark, outputFunctions);
136+
}
137+
}
138+
139+
var benchmarks = new Benchmarks ();
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Kazmath SIMD benchmarks</title>
6+
</head>
7+
<link href="http://cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
8+
<body>
9+
<h1 align="center" id="head">Running benchmarks...</h1>
10+
<div sytle="padding: 10px">
11+
<div style="width: 50%;float: left">
12+
<h2 align="center" id="time"></h2>
13+
<canvas id="canvasTime"></canvas>
14+
</div>
15+
<div style="width: 50%;float: left">
16+
<h2 align="center" id="speedup"></h2>
17+
<canvas id="canvasSpeedup"></canvas>
18+
</div>
19+
</div>
20+
<div id='echo'></div>
21+
<script>
22+
var cc = cc || {};
23+
cc.doNotUseSIMD = true;
24+
</script>
25+
<script src="../utility.js"></script>
26+
<script src="../vec3.js"></script>
27+
<script src="../vec4.js"></script>
28+
<script src="../mat4.js"></script>
29+
<script src="base.js"></script>
30+
<script src="kernel-template.js"></script>
31+
<script src="kmMat4Multiply.js"></script>
32+
<script src="kmMat4Assign.js"></script>
33+
<script src="kmMat4AreEqual.js"></script>
34+
<script src="kmMat4Inverse.js"></script>
35+
<script src="kmMat4IsIdentity.js"></script>
36+
<script src="kmMat4Transpose.js"></script>
37+
<script src="kmMat4LookAt.js"></script>
38+
<script src="kmVec3TransformCoord.js"></script>
39+
<script src="http://cdn.bootcss.com/Chart.js/1.0.2/Chart.min.js"></script>
40+
<!-- Execute -->
41+
<script src="run_browser.js"></script>
42+
</body>
43+
</html>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Kernel template
2+
// Author: Peter Jensen
3+
(function () {
4+
5+
// Kernel configuration
6+
var kernelConfig = {
7+
kernelName: "Test",
8+
kernelInit: init,
9+
kernelCleanup: cleanup,
10+
kernelSimd: simd,
11+
kernelNonSimd: nonSimd,
12+
kernelIterations: 100000000
13+
};
14+
15+
// Hook up to the harness
16+
benchmarks.add (new Benchmark (kernelConfig));
17+
18+
// Kernel Initializer
19+
function init () {
20+
// Do initial sanity check and initialize data for the kernels.
21+
// The sanity check should verify that the simd and nonSimd results
22+
// are the same.
23+
// It is recommended to do minimal object creation in the kernels
24+
// themselves. If global data needs to be initialized, here would
25+
// be the place to do it.
26+
// If the sanity checks fails the kernels will not be executed
27+
// Returns:
28+
// true: First run (unoptimized) of the kernels passed
29+
// false: First run (unoptimized) of the kernels failed
30+
return simd (1) === nonSimd (1);
31+
}
32+
33+
// Kernel Cleanup
34+
function cleanup () {
35+
// Do final sanity check and perform cleanup.
36+
// This function is called when all the kernel iterations have been
37+
// executed, so they should be in their final optimized version. The
38+
// sanity check done during initialization will probably be of the
39+
// initial unoptimized version.
40+
// Returns:
41+
// true: Last run (optimized) of the kernels passed
42+
// false: last run (optimized) of the kernels failed
43+
return simd (1) === nonSimd (1);
44+
}
45+
46+
// SIMD version of the kernel
47+
function simd (n) {
48+
var s = 0;
49+
for (var i = 0; i < n; ++i) {
50+
s += i;
51+
}
52+
return s;
53+
}
54+
55+
// Non SIMD version of the kernel
56+
function nonSimd (n) {
57+
var s = 0;
58+
for (var i = 0; i < n; ++i) {
59+
s += i;
60+
}
61+
return s;
62+
}
63+
64+
} ());
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// kmMat4AreEqual
2+
3+
(function () {
4+
5+
// Kernel configuration
6+
var kernelConfig = {
7+
kernelName: "kmMat4AreEqual",
8+
kernelInit: init,
9+
kernelCleanup: cleanup,
10+
kernelSimd: simd,
11+
kernelNonSimd: nonSimd,
12+
kernelIterations: 10000
13+
};
14+
15+
// Hook up to the harness
16+
benchmarks.add(new Benchmark(kernelConfig));
17+
18+
// Benchmark data, initialization and kernel functions
19+
var T1 = new cc.kmMat4();
20+
var T2 = new cc.kmMat4();
21+
var T1x4 = new cc.kmMat4();
22+
var T2x4 = new cc.kmMat4();
23+
var areEqual, areEqualSIMD;
24+
25+
function equals(A, B) {
26+
for (var i = 0; i < 16; ++i) {
27+
if (A[i] != B[i])
28+
return false;
29+
}
30+
return true;
31+
}
32+
33+
function init() {
34+
T1.mat[0] = 1.0;
35+
T1.mat[5] = 1.0;
36+
T1.mat[10] = 1.0;
37+
T1.mat[15] = 1.0;
38+
39+
T2.mat[0] = 1.0;
40+
T2.mat[5] = 1.0;
41+
T2.mat[10] = 1.0;
42+
T2.mat[15] = 1.0;
43+
44+
T1x4.mat[0] = 1.0;
45+
T1x4.mat[5] = 1.0;
46+
T1x4.mat[10] = 1.0;
47+
T1x4.mat[15] = 1.0;
48+
49+
T2x4.mat[0] = 1.0;
50+
T2x4.mat[5] = 1.0;
51+
T2x4.mat[10] = 1.0;
52+
T2x4.mat[15] = 1.0;
53+
54+
nonSimd(1);
55+
simd(1);
56+
57+
return equals(T1.mat, T1x4.mat) && equals(T2.mat, T2x4.mat) && (areEqual === areEqualSIMD);
58+
59+
}
60+
61+
function cleanup() {
62+
return init(); // Sanity checking before and after are the same
63+
}
64+
65+
function nonSimd(n) {
66+
for (var i = 0; i < n; i++) {
67+
areEqual = T1.equals(T2);
68+
}
69+
}
70+
71+
function simd(n) {
72+
for (var i = 0; i < n; i++) {
73+
areEqualSIMD = T1x4.equalsSIMD(T2x4);
74+
}
75+
}
76+
77+
} ());
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// kmMat4Assign
2+
3+
(function () {
4+
5+
// Kernel configuration
6+
var kernelConfig = {
7+
kernelName: "kmMat4Assign",
8+
kernelInit: init,
9+
kernelCleanup: cleanup,
10+
kernelSimd: simd,
11+
kernelNonSimd: nonSimd,
12+
kernelIterations: 10000
13+
};
14+
15+
// Hook up to the harness
16+
benchmarks.add(new Benchmark(kernelConfig));
17+
18+
// Benchmark data, initialization and kernel functions
19+
var T1 = new cc.kmMat4();
20+
var T2 = new cc.kmMat4();
21+
var T1x4 = new cc.kmMat4();
22+
var T2x4 = new cc.kmMat4();
23+
24+
function equals(A, B) {
25+
for (var i = 0; i < 16; ++i) {
26+
if (A[i] != B[i])
27+
return false;
28+
}
29+
return true;
30+
}
31+
32+
function init() {
33+
T1.mat[0] = 1.0;
34+
T1.mat[5] = 1.0;
35+
T1.mat[10] = 1.0;
36+
T1.mat[15] = 1.0;
37+
38+
T1x4.mat[0] = 1.0;
39+
T1x4.mat[5] = 1.0;
40+
T1x4.mat[10] = 1.0;
41+
T1x4.mat[15] = 1.0;
42+
43+
nonSimd(1);
44+
simd(1);
45+
46+
return equals(T1.mat, T1x4.mat) && equals(T2.mat, T2x4.mat);
47+
48+
}
49+
50+
function cleanup() {
51+
return init(); // Sanity checking before and after are the same
52+
}
53+
54+
function nonSimd(n) {
55+
for (var i = 0; i < n; i++) {
56+
//cc.kmMat4Assign(T2, T1);
57+
T2.assignFrom(T1);
58+
}
59+
}
60+
61+
function simd(n) {
62+
for (var i = 0; i < n; i++) {
63+
//cc.kmMat4AssignSIMD(T2x4, T1x4);
64+
T2x4.assignFromSIMD(T1x4);
65+
}
66+
}
67+
68+
} ());

0 commit comments

Comments
 (0)