簡體   English   中英

Javascript中的GPU並行性變慢

[英]GPU Parallelism in Javascript going slower

這是一個特定的問題。 我最近測試了gpu.js。 該庫應該通過使用webgl來並行化計算來加速計算。 我做了一個快速測試:

var gpu = new GPU();

function product(v, u) {
  return gpu.createKernel(function(X, Y) {
      return X[this.thread.x] * Y[this.thread.x];
  }).dimensions([v.length])(v, u);
}


var before = new Date().getTime();
console.log(product(numeric.random([100000]), numeric.random([100000])).length);
console.log('Parallel Time: ', (new Date().getTime()) - before);

before = new Date().getTime();
v = numeric.random([100000])
u = numeric.random([100000])
for(var i = 0; i < v.length; i++){
  v[i] = v[i] * u[i];
}
console.log(v.length);
console.log('Procedural Time: ', (new Date().getTime()) - before);

得到以下輸出:

script.js:11 100000 
script.js:12 Parallel Time:  340 
script.js:20 100000 
script.js:21 Procedural Time:  15

並行時間慢了一個數量級。 有什么理由可以這樣嗎? 我在幾台具有不同GPU的機器上試過這個。 我也嘗試了一些類似的操作。 我做錯了什么或是圖書館的問題? 有什么方法可以改善嗎?

在處理GPU時,您必須了解開銷。

調用gpu.createKernel可能非常昂貴,因為它必須解析您的JavaScript代碼,創建適當的GLSL代碼,並將其發送到WebGL進行編譯和鏈接。

至少,您需要調用該命令一次,並將結果存儲在全局變量中,以便在每次調用product時重復使用。

同樣值得注意的是,將數據移入和移出GPU需要非零工作量,因此您可以通過更復雜的計算看到更多的收益。

使用:

 t0 = performance.now(); yourFunctionCall(); t1 = performance.now(); console.log("Function yourFunctionCall took " + (t1 - t0) + " ms."); 

不確定這是否是問題的核心,但我也一直遇到Date的問題。

我梳理了他們的基准測試的源代碼,我發現當你連續運行大量操作時,你只能獲得加速。 我認為這是一個開銷問題。 我創建了以下超級簡單的基准,將gpu.js與numeric.js進行比較。 如果有人對此感興趣:

var gpu = new GPU();

var size = 512;
var scale = 10;
var iterations = 100;

// Scaling up the matricies decreases the effect of precision errors
A = numeric.mul(numeric.random([size, size]), scale)
B = numeric.mul(numeric.random([size, size]), scale)

// I know eval is dangerous but I couldn't get the size in any other way
function multGen(size) {
  return eval("(function(A, B) { var sum = 0; for (var i=0; i<"+ size +"; i++) {sum += A[this.thread.y][i] * B[i][this.thread.x];} return sum;})")
}

var mat_mult = gpu.createKernel(multGen(size)).dimensions([size, size]);

var before = new Date().getTime();
var parallel = mat_mult(A, B);

// Need to do many computations to get the advantages of the GPU
for(var i = 0; i < iterations; i++) {
  parallel = mat_mult(A, B);
}
var parTime = (new Date().getTime()) - before;
console.log('Parallel Time: ', parTime);

before = new Date().getTime();
var procedural = numeric.dot(A, B);

// Need to do many computations to get the advantages of the GPU
for(var i = 0; i < iterations; i++) {
  procedural = numeric.dot(A, B);
}
var procTime = (new Date().getTime()) - before;
console.log('Procedural Time: ', procTime);

console.log((procTime / parTime) + ' times faster');

// This is for RMSD nornalization, flattening and doing min and max that way exceeded the call stack
var max = Math.max(Math.max(...A.map((function(row) {return Math.max(...row);}))), Math.max(...B.map((function(row) {return Math.max(...row);}))))

var min = Math.min(Math.min(...A.map((function(row) {return Math.min(...row);}))), Math.min(...B.map((function(row) {return Math.min(...row);}))))

// The matricies will be different due to precision issues so the Normalized RMDS can give you an idea of the difference
var nrmsd = Math.sqrt(numeric.sum(numeric.pow(numeric.sub(parallel, procedural), 2)) / size) / (max - min);

console.log('Normalized RMSD: ', nrmsd);

這給了我以下輸出:

scriptfour.js:26 Parallel Time:  20490
scriptfour.js:36 Procedural Time:  28736
scriptfour.js:38 1.402440214738897 times faster
scriptfour.js:48 Normalized RMSD:  0.009671934749138042

這些結果非常好。 eval不公平地放慢了並行速度,但仍然總是更快。 我認為這樣的設置不適合生產,但它仍然適用於此。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM