jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
test 3d javascript performance
<script>
function stdCalVector4(x, y, z, w) {
this.x = x || 0.0;
this.y = y || 0.0;
this.z = z || 0.0;
this.w = w || 0.0;
}
// 3x3 transform matrix plus a translation 3-vector (stored in the w components
// of the rows. This struct needs to be 16-byte aligned for SSE.
function stdBoneTransform() {
this.rowx_x = 0.0;
this.rowx_y = 0.0;
this.rowx_z = 0.0;
this.rowx_w = 0.0;
this.rowy_x = 0.0;
this.rowy_y = 0.0;
this.rowy_z = 0.0;
this.rowy_w = 0.0;
this.rowz_x = 0.0;
this.rowz_y = 0.0;
this.rowz_z = 0.0;
this.rowz_w = 0.0;
}
function stdInfluence() {
this.boneId = -1;
this.weight = 0;
this.lastInfluenceForThisVertex = false;
}
function stdVertex() {
this.position = new stdCalVector4;
this.normal = new stdCalVector4;
}
function stdScaleMatrix(result, mat, s) {
result.rowx_x = s * mat.rowx_x;
result.rowx_y = s * mat.rowx_y;
result.rowx_z = s * mat.rowx_z;
result.rowx_w = s * mat.rowx_w;
result.rowy_x = s * mat.rowy_x;
result.rowy_y = s * mat.rowy_y;
result.rowy_z = s * mat.rowy_z;
result.rowy_w = s * mat.rowy_w;
result.rowz_x = s * mat.rowz_x;
result.rowz_y = s * mat.rowz_y;
result.rowz_z = s * mat.rowz_z;
result.rowz_w = s * mat.rowz_w;
}
function stdAddScaledMatrix(result, mat, s) {
result.rowx_x += s * mat.rowx_x;
result.rowx_y += s * mat.rowx_y;
result.rowx_z += s * mat.rowx_z;
result.rowx_w += s * mat.rowx_w;
result.rowy_x += s * mat.rowy_x;
result.rowy_y += s * mat.rowy_y;
result.rowy_z += s * mat.rowy_z;
result.rowy_w += s * mat.rowy_w;
result.rowz_x += s * mat.rowz_x;
result.rowz_y += s * mat.rowz_y;
result.rowz_z += s * mat.rowz_z;
result.rowz_w += s * mat.rowz_w;
}
function stdTransformPoint(result, m, v) {
result.x = m.rowx_x * v.x + m.rowx_y * v.y + m.rowx_z * v.z + m.rowx_w;
result.y = m.rowy_x * v.x + m.rowy_y * v.y + m.rowy_z * v.z + m.rowy_w;
result.z = m.rowz_x * v.x + m.rowz_y * v.y + m.rowz_z * v.z + m.rowz_w;
}
function stdTransformVector(result, m, v) {
result.x = m.rowx_x * v.x + m.rowx_y * v.y + m.rowx_z * v.z;
result.y = m.rowy_x * v.x + m.rowy_y * v.y + m.rowy_z * v.z;
result.z = m.rowz_x * v.x + m.rowz_y * v.y + m.rowz_z * v.z;
}
function assert(cond) {
if (!cond) {
alert("assert failed");
throw 'assert failed';
}
}
function stdcalculateVerticesAndNormals(
boneTransforms, vertices, influences, output_vertex) {
var vertexCount = vertices.length;
assert(vertices.length == influences.length);
const total_transform = new stdBoneTransform;
var influenceId = 0;
var vertexId = 0;
var outputVertexId = 0;
// calculate all submesh vertices
while (vertexCount--) {
stdScaleMatrix(total_transform, boneTransforms[influences[influenceId].boneId], influences[influenceId].weight);
while (!influences[influenceId].lastInfluenceForThisVertex) {
++influenceId;
stdAddScaledMatrix(total_transform, boneTransforms[influences[influenceId].boneId], influences[influenceId].weight);
}
stdTransformPoint(output_vertex[outputVertexId++], total_transform, vertices[vertexId].position);
stdTransformVector(output_vertex[outputVertexId++], total_transform, vertices[vertexId].normal);
++vertexId;
}
}
const stdN = 10000;
const stdv = []; // Vertex
const stdi = []; // Influence
for (var k = 0; k < stdN; ++k) {
const stdvertex = new stdVertex;
stdvertex.position = new stdCalVector4(1.0, 2.0, 3.0);
stdvertex.normal = new stdCalVector4(0.0, 0.0, 1.0);
stdv.push(stdvertex);
const stdinfluence = new stdInfluence;
stdinfluence.boneId = 0;
stdinfluence.weight = 1.0;
stdinfluence.lastInfluenceForThisVertex = true;
stdi.push(stdinfluence);
}
var stdbt = [new stdBoneTransform];
var stdoutput = new Array(stdN * 2);
for (var k = 0; k < stdN * 2; ++k) {
stdoutput[k] = new stdCalVector4;
}
////////// Typed Array
"use strict";
function taInfluence() {
this.boneId = -1;
this.weight = 0;
this.lastInfluenceForThisVertex = false;
}
function taScaleMatrix(result, mat, s) {
result[0] = s * mat[0];
result[1] = s * mat[1];
result[2] = s * mat[2];
result[3] = s * mat[3];
result[4] = s * mat[4];
result[5] = s * mat[5];
result[6] = s * mat[6];
result[7] = s * mat[7];
result[8] = s * mat[8];
result[9] = s * mat[9];
result[10] = s * mat[10];
result[11] = s * mat[11];
}
function taAddScaledMatrix(result, mat, s) {
result[0] += s * mat[0];
result[1] += s * mat[1];
result[2] += s * mat[2];
result[3] += s * mat[3];
result[4] += s * mat[4];
result[5] += s * mat[5];
result[6] += s * mat[6];
result[7] += s * mat[7];
result[8] += s * mat[8];
result[9] += s * mat[9];
result[10] += s * mat[10];
result[11] += s * mat[11];
}
function taTransformPoint(result, m, v, offset) {
//alert(v[offset] + ',' + v[offset+1] + ',' + v[offset+2]);
result[offset] = m[0] * v[offset] + m[1] * v[offset + 1] + m[2] * v[offset + 2] + m[3];
result[offset + 1] = m[4] * v[offset] + m[5] * v[offset + 1] + m[6] * v[offset + 2] + m[7];
result[offset + 2] = m[8] * v[offset] + m[9] * v[offset + 1] + m[10] * v[offset + 2] + m[11];
}
function taTransformVector(result, m, v, offset) {
//alert(v[offset] + ',' + v[offset+1] + ',' + v[offset+2]);
result[offset] = m[0] * v[offset] + m[1] * v[offset + 1] + m[1] * v[offset + 2];
result[offset + 1] = m[4] * v[offset] + m[6] * v[offset + 1] + m[7] * v[offset + 2];
result[offset + 2] = m[8] * v[offset] + m[9] * v[offset + 1] + m[10] * v[offset + 2];
}
function tacalculateVerticesAndNormals(
boneTransforms, vertices, influences, output_vertex) {
var vertexCount = influences.length;
//assert(vertices.length == influences.length);
const total_transform = new Float32Array(12);
var influenceId = 0;
var vertexOffset = 0;
vertices = new Float32Array(vertices);
// calculate all submesh vertices
while (vertexCount--) {
taScaleMatrix(total_transform, boneTransforms[influences[influenceId].boneId], influences[influenceId].weight);
while (!influences[influenceId].lastInfluenceForThisVertex) {
++influenceId;
taAddScaledMatrix(total_transform, boneTransforms[influences[influenceId].boneId], influences[influenceId].weight);
}
taTransformPoint(output_vertex, total_transform, vertices, vertexOffset);
vertexOffset += 4;
taTransformVector(output_vertex, total_transform, vertices, vertexOffset);
vertexOffset += 4;
}
}
const taN = 10000;
const taVertexSize = 4 + 4;
const tav = new ArrayBuffer(taN * taVertexSize * 4); // floats
const tai = []; // Influence
for (var k = 0; k < taN; ++k) {
var taposition = new Float32Array(tav, k * taVertexSize * 4, 4);
taposition[0] = 1.0;
taposition[1] = 2.0;
taposition[2] = 3.0;
taposition[3] = 1.0;
var tanormal = new Float32Array(tav, k * taVertexSize * 4 + 4 * 4, 4);
tanormal[0] = 0.0;
tanormal[1] = 0.0;
tanormal[2] = 1.0;
tanormal[3] = 0.0;
const tainfluence = new taInfluence;
tainfluence.boneId = 0;
tainfluence.weight = 1.0;
tainfluence.lastInfluenceForThisVertex = true;
tai.push(tainfluence);
}
var tabt = [new Float32Array(4 * 3)];
var taoutput = new Float32Array(taN * 2 * 4);
</script>
Ready to run.
Test | Ops/sec | |
---|---|---|
standard array |
| ready |
typed Array |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.