gpu.js/test/internal/matrix-multiply-precision.js
2019-12-25 09:10:56 -05:00

203 lines
5.6 KiB
JavaScript

const { assert, skip, test, module: describe, only } = require('qunit');
const { GPU } = require('../../src');
describe('internal: matrix multiply precision');
function vanillaMatrixMultiply(a, b) {
const width = a.length;
const height = b.length;
const result = new Array(height);
for (let y = 0; y < height; y++) {
const row = new Float32Array(width);
for (let x = 0; x < width; x++) {
let sum = 0;
for (let i = 0; i < width; i++) {
sum += a[y][i] * b[i][x];
}
row[x] = sum;
}
result[y] = row;
}
return result;
}
function filledMatrix(width, height) {
const matrix = new Array(height);
for (let y = 0; y < height; y++) {
const row = matrix[y] = new Float32Array(width);
for (let x = 0; x < width; x++) {
row[x] = Math.random() * 10;
}
}
return matrix;
}
function test512x512Matrix(precision, mode) {
const width = 512;
const height = 512;
const a = filledMatrix(width, height);
const b = filledMatrix(width, height);
const gpu = new GPU({ mode });
const kernel = gpu.createKernel(function(a, b) {
let sum = 0;
for (let i = 0; i < this.constants.width; i++) {
sum += a[this.thread.y][i] * b[i][this.thread.x];
}
return sum;
}, {
output: [width, height],
precision,
constants: {
width
}
});
const cpuResult = vanillaMatrixMultiply(a, b, width, height);
const gpuResult = kernel(a, b);
let closeEnough = true;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const singleGPUResult = gpuResult[y][x];
const singleCPUResult = cpuResult[y][x];
if (Math.abs(singleGPUResult - singleCPUResult) > 1) {
closeEnough = false;
break;
}
}
}
assert.ok(closeEnough);
gpu.destroy();
}
test('512x512 unsigned precision auto', () => {
test512x512Matrix('unsigned');
});
test('512x512 unsigned precision gpu', () => {
test512x512Matrix('unsigned', 'gpu');
});
(GPU.isWebGLSupported ? test : skip)('512x512 unsigned precision webgl', () => {
test512x512Matrix('unsigned', 'webgl');
});
(GPU.isWebGL2Supported ? test : skip)('512x512 unsigned precision webgl2', () => {
test512x512Matrix('unsigned', 'webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('512x512 unsigned precision headlessgl', () => {
test512x512Matrix('unsigned', 'headlessgl');
});
test('512x512 unsigned precision cpu', () => {
test512x512Matrix('unsigned', 'cpu');
});
function test10x512Matrix(precision, mode) {
const width = 10;
const height = 512;
const a = filledMatrix(width, height);
const b = filledMatrix(width, height);
const gpu = new GPU({ mode });
const kernel = gpu.createKernel(function(a, b) {
let sum = 0;
for (let i = 0; i < this.constants.width; i++) {
sum += a[this.thread.y][i] * b[i][this.thread.x];
}
return sum;
}, {
output: [width, height],
precision,
constants: {
width
}
});
const cpuResult = vanillaMatrixMultiply(a, b, width, height);
const gpuResult = kernel(a, b);
let closeEnough = true;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const singleGPUResult = gpuResult[y][x];
const singleCPUResult = cpuResult[y][x];
if (Math.abs(singleGPUResult - singleCPUResult) > 1) {
closeEnough = false;
break;
}
}
}
assert.ok(closeEnough);
gpu.destroy();
}
test('10x512 unsigned precision auto', () => {
test10x512Matrix('unsigned');
});
test('10x512 unsigned precision gpu', () => {
test10x512Matrix('unsigned', 'gpu');
});
(GPU.isWebGLSupported ? test : skip)('10x512 unsigned precision webgl', () => {
test10x512Matrix('unsigned', 'webgl');
});
(GPU.isWebGL2Supported ? test : skip)('10x512 unsigned precision webgl2', () => {
test10x512Matrix('unsigned', 'webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('10x512 unsigned precision headlessgl', () => {
test10x512Matrix('unsigned', 'headlessgl');
});
test('10x512 unsigned precision cpu', () => {
test10x512Matrix('unsigned', 'cpu');
});
(GPU.isSinglePrecisionSupported ? test : skip)('512x512 single precision auto', () => {
test512x512Matrix('single');
});
(GPU.isSinglePrecisionSupported ? test : skip)('512x512 single precision gpu', () => {
test512x512Matrix('single', 'gpu');
});
(GPU.isWebGLSupported && GPU.isSinglePrecisionSupported ? test : skip)('512x512 single precision webgl', () => {
test512x512Matrix('single', 'webgl');
});
(GPU.isWebGL2Supported && GPU.isSinglePrecisionSupported ? test : skip)('512x512 single precision webgl2', () => {
test512x512Matrix('single', 'webgl2');
});
(GPU.isHeadlessGLSupported && GPU.isSinglePrecisionSupported ? test : skip)('512x512 single precision headlessgl', () => {
test512x512Matrix('single', 'headlessgl');
});
test('512x512 single precision cpu', () => {
test512x512Matrix('single', 'cpu');
});
(GPU.isSinglePrecisionSupported ? test : skip)('10x512 single precision auto', () => {
test10x512Matrix('single');
});
(GPU.isSinglePrecisionSupported ? test : skip)('10x512 single precision gpu', () => {
test10x512Matrix('single', 'gpu');
});
(GPU.isWebGLSupported && GPU.isSinglePrecisionSupported ? test : skip)('10x512 single precision webgl', () => {
test10x512Matrix('single', 'webgl');
});
(GPU.isWebGL2Supported && GPU.isSinglePrecisionSupported ? test : skip)('10x512 single precision webgl2', () => {
test10x512Matrix('single', 'webgl2');
});
(GPU.isHeadlessGLSupported && GPU.isSinglePrecisionSupported ? test : skip)('10x512 single precision headlessgl', () => {
test10x512Matrix('single', 'headlessgl');
});
test('10x512 single precision cpu', () => {
test10x512Matrix('precision', 'cpu');
});