学写个gpu核函数

以前也跑过gpu.js的demo,每次搞来搞去都只是做个随机数的矩阵相乘,没试过真的自己写一个核函数。最近手术后眼睛恢复的不错,又想学点儿新东西了,就学写一个核函数吧,看看比起CPU是不是有优势。问题场景就设定为求一个大数列的移动平均数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
const { GPU } = require('gpu.js');
const gpu = new GPU();
const generateData = (days) => {
const data = [];
for (let y = 0; y < days; y++)
data.push(Math.random());
return data;
}
const data = generateData(1000000);

const GPUMA = gpu.createKernel(function (a,windowSize) {
let sum = 0;
for (let i = 0; i < windowSize; i++) {
sum += a[this.thread.x+i];
}
return sum/windowSize;
}).setOutput([data.length])
//setOutput需要在createKernel之后立刻调用,
//而此时还没有调用核函数因此也不知道将会使用的窗口大小,所以只能按照最大窗口大小来设置输出,调用方在接受到结果后需要自行截取

function calculateMA(data,windowSize) {
const outputLength = data.length - windowSize + 1;
const ma = new Array(outputLength);

for (let i = 0; i < outputLength; i++) {
let sum = 0;
for (let j = 0; j < windowSize; j++) {
sum += data[i + j];
}
ma[i] = sum / windowSize;
}

return ma;
}

// 示例用法
winSize = 500;
const t0=Date.now();
const maResult = calculateMA(data,winSize);
const t1=Date.now();
const gpuResult = GPUMA(data,winSize).subarray(0, data.length-winSize+1)
console.log("cpu time:",t1-t0,"ms vs gpu time:",Date.now()-t1,"ms");
const idx = Math.floor(Math.random()*(data.length-winSize+1))
console.log(idx,":",maResult[idx] ,"vs" , gpuResult[idx]);

移动窗口如果不足够大,计算不够复杂,gpu并不能体现优势,反而会因为需要频繁的内存读写而拖慢速度。