• Stars
    star
    1,163
  • Rank 40,128 (Top 0.8 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 8 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Massively parallel GPU programming on JavaScript, simple and clean.

WebMonkeys

Allows you to spawn thousands of parallel tasks on the GPU with the simplest, dumbest API possible. It works on the browser (with browserify) and on Node.js. It is ES5-compatible and doesn't require any WebGL extension.

Usage

On the browser, add <script src="WebMonkeys.js"><script> to your HTML. On Node.js, install it from npm:

npm install webmonkeys --save

The example below uses the GPU to square all numbers in an array in parallel:

// Creates a WebMonkeys object
const monkeys = require("WebMonkeys")(); // on the browser, call WebMonkeys() instead

// Sends an array of numbers to the GPU
monkeys.set("nums", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);

// Employs 16 monkeys to work in parallel on the task of squaring each number
monkeys.work(16, "nums(i) := nums(i) * nums(i);");

// Receives the result back
console.log(monkeys.get("nums"));

// output: [ 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256 ]

set/get allow you to send/receive data from the GPU, and work creates a number of parallel tasks (monkeys) that can read, process and rewrite that data. The language used is GLSL 1.0, extended array access (foo(index), usable anywhere on the source), setters (foo(index) := value, usable on the end only), and int i, a global variable with the index of the monkey.

More examples

More elaborate algorithms can be developed with GLSL.

  • Vector multiplication:

    monkeys.set("a", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
    monkeys.set("b", [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]);
    monkeys.set("c", 16); // use a number to just alloc an array
    
    monkeys.work(16, "c(i) := a(i) * b(i);");
    
    console.log(monkeys.get("c"));
  • Crypto-currency mining:

    monkeys.set("blockhash", [blockhash]);
    monkeys.set("monkeyNonce", monkeyNonce);
    monkeys.set("result", [0]);
    monkeys.work(totalMonkeys, `
      const float attempts = ${attemptsPerMonkey.toFixed(1)};
      float bhash = blockhash(0);
      float startNonce = monkeyNonce(i);
      float mined = 0.0;
      for (float nonce = startNonce; nonce < startNonce+attempts; ++nonce){
        // Yes, this hash function is stupid
        float hash = mod(bhash * (nonce+1.0), pow(2.0,31.0) - 1.0);
        if (hash >= 0.0 && hash <= 3000.0)
          mined = nonce;
      };
      result(mined > 0.0 ? 0 : 1) := mined;
    `);
    // Will be set if mined a block
    console.log(monkeys.get("result"));

You can also define libs, write to many indices in a single call, and work with raw Uint32 buffers if you wish to. For more details, please check the examples directory.

vs WebGL

The only reliable way to access the GPU on the browser is by using WebGL. Since it wasn't designed for general programming, doing it is very tricky. For one, the only way to upload data is as 2D textures of pixels. Even worse, your shaders (programs) can't write directly to them; you need to, instead, render the result using geometrical primitives. You're, thus, in charge of converting JS numbers (IEEE 754 floats) to pixels, projecting them to/from 2D textures and using proper geometries to render the results on the right places. You must also deal with aliasing/blurring, rounding, and loss of precision. It is a very delicate job with many small details that could go wrong and no satisfactory way of debugging. WebMonkeys takes care of all that for you, abstracting the overcomplication away and making the power of the GPU as easily accessible as possible, with a very simple API based on array reads and writes.

Performance and debugging tips

  • A single monkey can write to multiple places. If you need to fill an array of 100 numbers, you could use 100 monkeys writing to 1 index each, or 10 monkeys writing to 10 indices each. What is faster will depend on your application.

  • While CPU/GPU bandwidth is huge these days, it still takes time to communicate data between them. Whenever possible, reduce your calls to set/get, and keep things internal to the GPU. For example, if you need to move data between two arrays, this: monkeys.work(16, "target(i) := source(i);") - is much faster than this: monkeys.set("target", monkeys.get("source")).

  • The first call to monkeys.work(count, someTask) is slow due to program compilation, but every call after that is fast. That is for two reasons: 1. WebMonkeys caches shaders so that, when you call task with a repeated source code, it just recovers the previously compiled program; 2. JS engines keep strings hashed, which means that retrieval can be done in O(1). In other words, it is perfectly reasonable to call monkeys.work(n, bigSourceCode) inside your animation loop (as long as bigSourceCode doesn't change).

  • Since WebMonkeys stores numbers as WebGL textures, writing/reading to/from arrays has an encode/decode overhead. If your application spends much more time doing arithmetics than writing/reading data, that is acceptable. If not, use raw buffers and do your own packing/unpacking.

  • Remember you can't have setters (foo(i) := v;) in the middle of your program. They must be at the end. If you're having weird WebGL errors, it could be WebMonkeys's fault: its very simple parser sometimes fails to separate the program's body from the list of setters. Usually, just adding an extra line with a commented semicolon (//;) between your program and your setters solves it.

  • Use monkeys.fill("nums", 0) rather than monkeys.work(numsLength, "nums(i) := 0.0;") (and clear, its equivalent for raw Uint32s).

More Repositories

1

LJSON

JSON extended with pure functions.
JavaScript
500
star
2

Caramel

A modern syntax for the λ-calculus.
Haskell
405
star
3

PureState

The stupidest state management library that works.
JavaScript
309
star
4

forall

Expressive static types and invariant checks for JavaScript.
JavaScript
227
star
5

abstract-algorithm

Optimal evaluator of λ-calculus terms.
JavaScript
222
star
6

Cedille-Core

A minimal proof language.
JavaScript
193
star
7

optlam

An optimal function evaluator written in JavaScript.
JavaScript
115
star
8

Interaction-Type-Theory

Rust
108
star
9

calculus-of-constructions

Minimal, fast, robust implementation of the Calculus of Constructions on JavaScript.
JavaScript
94
star
10

Bitspeak

JavaScript
80
star
11

articles

Thoughts and stuff
JavaScript
65
star
12

UrnaCripto

Referendos criptograficamente incorruptíveis.
JavaScript
51
star
13

lrs

Linkable Ring Signatures on JavaScript and PureScript.
PureScript
46
star
14

lambda-calculus

A simple, clean and fast implementation of the λ-calculus on JavaScript.
JavaScript
44
star
15

heart

heart
JavaScript
41
star
16

ultimate-calculus

TypeScript
36
star
17

absal-rs

Rust
36
star
18

HOC

C
32
star
19

nano-json-stream-parser

A complete, pure JavaScript, streamed JSON parser in less than 1kb.
JavaScript
29
star
20

servify

Microservices in the simplest way conceivable.
JavaScript
28
star
21

optimul

Multiplication on optimal λ-calculus reducers
JavaScript
22
star
22

parallel_lambda_computer_tests

learning cuda
Cuda
18
star
23

nano-ipfs-store

Lightweight library to store and get data to/from IPFS
JavaScript
14
star
24

formality-agda-lib-legacy

Agda libraries relevant to Moonad
Agda
14
star
25

taemoba

13
star
26

unknown_halting_status

Small programs with unknown halting status.
JavaScript
12
star
27

lsign

Quantum-proof, 768-bit signatures for 1-bit messages
JavaScript
11
star
28

reasoning_evals

my reasoning evals
JavaScript
9
star
29

Elementary-Affine-Net-legacy

JavaScript
8
star
30

OpenLegends

An open-source MOBA in Rust
6
star
31

ethereum-offline-signer

Signs an Ethereum transaction from the command line.
JavaScript
6
star
32

coc-with-math-prims

JavaScript
5
star
33

idris-mergesort-benchmark

Benchmark of the new Idris JS backend
JavaScript
5
star
34

uwuchat2_demo

UwUChat2 demo game
TypeScript
5
star
35

LPU

JavaScript
4
star
36

Vote

3
star
37

nano-persistent-memoizer

Caches a function permanently on browser and node.
JavaScript
3
star
38

nano-sha256

Use native Sha256 on both browser and Node.js
JavaScript
3
star
39

ReflexScreenWidget

A widget for Haskell-Reflex that renders a dynamic image to a Canvas in realtime.
Haskell
3
star
40

OSX

Vim script
3
star
41

EthFP

3
star
42

VictorTaelin

3
star
43

ethereum-rpc

JavaScript
2
star
44

ethereum-publisher-dapp

JavaScript
2
star
45

shared-state-machine

JavaScript
2
star
46

Trabalho-IC-UFRJ-2

Python
2
star
47

NeoTaelin

2
star
48

eth-web-tools

Some web Ethereum tools that MyEtherWallet currently lacks
JavaScript
2
star
49

hvm2

Cuda
2
star
50

symmetric-interaction-calculus-benchmarks

SIC benchmarks
JavaScript
2
star
51

talks

C
2
star
52

gpt

2
star
53

agbook

AGDA
Agda
2
star
54

Kind2

Kind refactor based on HVM
2
star
55

kind-react-component

Renders a Kind app as a React component
1
star
56

PongFromScratch

A simple tutorial on how to create a ping-pong game from scratch
1
star
57

tsbook

TypeScript
1
star
58

sketch_bros

Super Sketch Bros!
JavaScript
1
star
59

StupidMinimalistHash

C
1
star
60

MaiaVictor.github.io

HTML
1
star
61

PotS

JavaScript
1
star
62

LamBolt

The ultimate compile target for functional languages
1
star
63

form-login

Um formulário de Login feito com HTML e CSS usando transições
CSS
1
star
64

who-loves-voxels

JavaScript
1
star
65

cuda_rewrite_tests

learning cuda
Cuda
1
star
66

luna-lang-old-abandoned-repo

Typed version of Moon-lang
JavaScript
1
star
67

posts

1
star
68

FPL

A collection of functional JavaScript modules.
JavaScript
1
star
69

PassRhyme

JavaScript
1
star
70

something_calculus

1
star
71

moon-bignum

Minimalistic bignum library compiled from Moon-lang.
JavaScript
1
star
72

see

See inside JS functions
JavaScript
1
star
73

Trabalho-IC-UFRJ

JavaScript
1
star
74

optimal_evaluation_examples

optimal evaluation examples (DUP nodes, SUP nodes)
Haskell
1
star
75

inferno-hello-world-component

JavaScript
1
star
76

inet

JavaScript
1
star