Skip to content

Commit a5ccbdc

Browse files
Add example and bump version
1 parent ab8b441 commit a5ccbdc

File tree

3 files changed

+150
-1
lines changed

3 files changed

+150
-1
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ GPU Problem: Sometimes you'd like to convert your CPU code to GPU code.
1212
By strategically using MatrixLog as a logger in your CPU algorithms, you can see which points are dependent from your source arrays to your target arrays.
1313
This makes converting CPU code to run on GPU, using a utility like [GPU.js](http://gpu.rocks), much easier.
1414

15+
Don't understand?
16+
1. Watch this video: https://www.youtube.com/watch?v=-P28LKWTzrI .
17+
2. Think of the Leonardo 2's cannons talking with each other to build up their values and how this violates the laws of physics.
18+
3. Have eureka moment.
19+
1520
## API
1621
```js
1722
import * as MatrixLog from 'matrix-log';

example.js

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
const assert = require('assert');
2+
const MatrixLog = require('./index');
3+
4+
const weights = [
5+
[1,2,3,4],
6+
[5,6,7,8],
7+
[9,10,11,12],
8+
[13,14,15,16]
9+
];
10+
11+
const targetValue = step1CPU();
12+
assert.deepStrictEqual(step2GPUStyleLoops(), targetValue);
13+
assert.deepStrictEqual(step3GPUStyleKernel(), targetValue);
14+
assert.deepStrictEqual(step4GPUKernel(), targetValue);
15+
16+
function step1CPU() {
17+
const filters = [
18+
[0,0],
19+
[0,0]
20+
];
21+
const matrixLog = new MatrixLog('filters', 2, 2);
22+
for (let y = 0; y < 4; y++) {
23+
let filterY = y < 2 ? 0 : 1;
24+
for (let x = 0; x < 4; x++) {
25+
let filterX = x < 2 ? 0 : 1;
26+
// IMPORTANT: GPU violation, we are reading (+) and writing (=) multiple times to a point in the filter matrix, CPU works fine, GPU explodes
27+
// Don't understand?
28+
// * Watch this video: https://www.youtube.com/watch?v=-P28LKWTzrI and think of the
29+
// * Think of the Leonardo 2's cannons talking with each other
30+
filters[filterY][filterX] += weights[y][x];
31+
32+
// IMPORTANT: We added the following code to show us the shape of the algorithm
33+
matrixLog
34+
.at({
35+
x: filterX,
36+
y: filterY
37+
})
38+
.add({
39+
name: 'weights',
40+
x,
41+
y,
42+
width: weights[0].length,
43+
height: weights.length
44+
});
45+
}
46+
}
47+
48+
console.log(filters);
49+
console.log(matrixLog.toString('weights'));
50+
return filters;
51+
}
52+
53+
function step2GPUStyleLoops() {
54+
const filters = [
55+
[0,0],
56+
[0,0]
57+
];
58+
const filterHeight = 2;
59+
const filterWidth = 2;
60+
61+
for (let filterY = 0; filterY < filterHeight; filterY++) {
62+
for (let filterX = 0; filterX < filterWidth; filterX++) {
63+
// NOTE: += filters!
64+
let sum = filters[filterY][filterX];
65+
66+
const yMin = filterHeight * filterY;
67+
const yMax = yMin + filterHeight;
68+
const xMin = filterWidth * filterX;
69+
const xMax = xMin + filterWidth;
70+
71+
for (let y = yMin; y < yMax; y++) {
72+
for (let x = xMin; x < xMax; x++) {
73+
sum += weights[y][x];
74+
}
75+
}
76+
77+
// IMPORTANT: single assignment
78+
filters[filterY][filterX] = sum;
79+
}
80+
}
81+
82+
return filters;
83+
}
84+
85+
function step3GPUStyleKernel() {
86+
const filters = [
87+
[0,0],
88+
[0,0]
89+
];
90+
filters[0][0] = filterKernel(filters, 0, 0, 2, 2, weights);
91+
filters[0][1] = filterKernel(filters, 1, 0, 2, 2, weights);
92+
filters[1][0] = filterKernel(filters, 0, 1, 2, 2, weights);
93+
filters[1][1] = filterKernel(filters, 1, 1, 2, 2, weights);
94+
95+
function filterKernel(filters, filterX, filterY, filterWidth, filterHeight, weights) {
96+
// NOTE: += filters!
97+
let sum = filters[filterY][filterX];
98+
99+
const yMin = filterHeight * filterY;
100+
const yMax = yMin + filterHeight;
101+
const xMin = filterWidth * filterX;
102+
const xMax = xMin + filterWidth;
103+
104+
for (let y = yMin; y < yMax; y++) {
105+
for (let x = xMin; x < xMax; x++) {
106+
sum += weights[y][x];
107+
}
108+
}
109+
110+
// IMPORTANT: single assignment
111+
return sum;
112+
}
113+
return filters;
114+
}
115+
116+
function step4GPUKernel() {
117+
const filters = [
118+
[0,0],
119+
[0,0]
120+
];
121+
const GPU = require('gpu.js');
122+
const gpu = new GPU();
123+
124+
const filterKernel = gpu.createKernel(function (filters, weights) {
125+
let sum = filters[this.thread.y][this.thread.x];
126+
127+
const yMin = this.output.y * this.thread.y;
128+
const yMax = yMin + this.output.y;
129+
const xMin = this.output.x * this.thread.x;
130+
const xMax = xMin + this.output.x;
131+
132+
for (let y = yMin; y < yMax; y++) {
133+
for (let x = xMin; x < xMax; x++) {
134+
sum += weights[y][x];
135+
}
136+
}
137+
// IMPORTANT: single assignment
138+
return sum;
139+
}, {
140+
output: [2, 2]
141+
});
142+
143+
return filterKernel(filters, weights);
144+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "matrix-log.js",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"description": "A matrix log dependency utility. Useful for converting and testing algorithm behavior of CPU code to GPU code.",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)