gpujs / gpu.js

GPU Accelerated JavaScript
https://gpu.rocks
MIT License
15.14k stars 658 forks source link

Unexpected output indexing arrays with array values #617

Open TomWyllie opened 4 years ago

TomWyllie commented 4 years ago

A GIF or MEME to give some spice of the internet

What is wrong?

As part of a project that I'm trying to integrate GPU.js into to enhance performance, I've encountered some bizarre output when running a kernel. If indexing an array with another, the output appears to have been taken from the values of the inner array. This is best explained with an example.

Where does it happen?

See the following for a minimal reproducible example.

const gpu = new GPU({ mode: 'gpu' });
const arr1 = [0, 1, 3, 4];
const arr2 = [10, 11, 12, 13, 14];

const arrKernel = gpu.createKernel(function(arr1, arr2) {
    return arr2[arr1[this.thread.x]];
}).setOutput([4]);
const result = arrKernel(arr1, arr2);

// Expected output: "10,11,13,14"
// jsfiddle output with mode: 'gpu': "0,1,4,0"
// jsfiddle output with mode: 'cpu': "10,11,13,14" (as expected)
console.log(result.toString());
  1. Create two arrays
  2. Use this.thread.x to index the first, and use the values of that to index the second
  3. Observe unexpected output

I have a JS fiddle that can recreate this issue at jsfiddle.net/TomWyllie/c5khtu9g/. The source of the seemingly arbitrary output seems to be the values in the inner array as I mentioned above. That is, if I had written return arr1[arr1[this.thread.x]]; instead of return arr2[arr1[this.thread.x]]; all would be as expected.

This was tested using:

I couldn't replicate the issue on my phone (Samsung Galaxy S9) and haven't tried any other devices.

How important is this (1-5)?

Probably a ~3~ 4, it's pretty annoying but is probably possible to work around in my use case. But it'd make things unnecessarily complicated and other people might spend time debugging not suspecting this has happened - it's a very strange result.

Other Comments

I am very new to GPU.js (like, < 1 week) so am not 100% sure if this is a genuine bug, or if I have somehow ventured into unsupported territory, but given that the expected result is returned in mode: cpu, and also in mode: gpu on my phone in the JS Fiddle I thought it'd be worth flagging up. If I've missed something stupid please do let me know!

Finally, although not relevant to this issue in case anybody is wondering about the context, my use-case is traversing a matrix in diagonals, as only the diagonals can be computed in parallel due to the recursive nature of each entry. This is part of a string alignment algorithm. I am using (or trying to) this.thread.x to parameterise the position along each diagonal, the indices of which are computed outside the kernel.

Any comments or thoughts much appreciated! 😊

TomWyllie commented 4 years ago

I have found a workaround which enables the problem to be easily avoided for now. If instead of using;

return arr2[arr1[this.thread.x]];

We use

let i = arr1[this.thread.x];
return arr2[i];

The expected result is returned. This is rather odd!

harshkhandeparkar commented 4 years ago

Works fine for me :) Ubuntu 20.04 Proprietary Nvidia Drivers FF Browser

This is most likely a driver issue. Have you installed the latest drivers from Nvidia?

TomWyllie commented 4 years ago

I've upgrade to the "GeForce Game Ready Driver" version 446.14 which is the most up to date version, released two weeks ago and the issue persists. I was on 445.87 before upgrading to the latest one so it doesn't seem to be an out-of-date driver problem. Given it works on Ubuntu with an Nvidia card it might be something specific to the Windows drivers...