diff options
Diffstat (limited to '')
| -rwxr-xr-x | 06_storage/build.sh | 9 | ||||
| -rw-r--r-- | 06_storage/index.html | 19 | ||||
| -rw-r--r-- | 06_storage/init_idbfs.js | 16 | ||||
| -rw-r--r-- | 06_storage/mime.txt | 1 | ||||
| -rw-r--r-- | 06_storage/primes.c | 94 | ||||
| -rw-r--r-- | 06_storage/primes.h | 12 | ||||
| -rwxr-xr-x | 06_storage/run-server.sh | 6 | ||||
| -rw-r--r-- | 06_storage/script.mjs | 20 | ||||
| -rw-r--r-- | 06_storage/storage.c | 28 | ||||
| -rw-r--r-- | 06_storage/storage.h | 7 | ||||
| -rw-r--r-- | 06_storage/worker.mjs | 22 |
11 files changed, 234 insertions, 0 deletions
diff --git a/06_storage/build.sh b/06_storage/build.sh new file mode 100755 index 0000000..a477cc5 --- /dev/null +++ b/06_storage/build.sh | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | mkdir -p build | ||
| 4 | emcc -sEXPORTED_FUNCTIONS=_primes_in_range -sMODULARIZE -sEXPORT_NAME=Primes \ | ||
| 5 | -pthread -sPTHREAD_POOL_SIZE=16 \ | ||
| 6 | -sEXPORTED_RUNTIME_METHODS=addFunction,UTF8ToString \ | ||
| 7 | -sALLOW_TABLE_GROWTH \ | ||
| 8 | -lidbfs.js --pre-js init_idbfs.js -sINITIAL_MEMORY=272629760 \ | ||
| 9 | -o build/primes.mjs primes.c storage.c | ||
diff --git a/06_storage/index.html b/06_storage/index.html new file mode 100644 index 0000000..a4ba674 --- /dev/null +++ b/06_storage/index.html | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | <!doctype html> | ||
| 2 | <html lang="en-US"> | ||
| 3 | <head> | ||
| 4 | <meta charset="utf-8" /> | ||
| 5 | <meta name="viewport" content="width=device-width" /> | ||
| 6 | <title>Primes in a range</title> | ||
| 7 | <script src="./script.mjs" type="module" defer></script> | ||
| 8 | </head> | ||
| 9 | |||
| 10 | <body> | ||
| 11 | <label for="aInput">Lower bound (included)</label><br /> | ||
| 12 | <input id="aInput" name="aInput" /> x <br /> | ||
| 13 | <label for="bInput">Upper bound (excluded)</label><br /> | ||
| 14 | <input id="bInput" name="bInput" /> <br /> | ||
| 15 | <button id="goButton" disabled>Loading, please wait...</button> <br /> | ||
| 16 | <p id="resultText"></p> | ||
| 17 | </body> | ||
| 18 | |||
| 19 | </html> | ||
diff --git a/06_storage/init_idbfs.js b/06_storage/init_idbfs.js new file mode 100644 index 0000000..82483f4 --- /dev/null +++ b/06_storage/init_idbfs.js | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | Module['preRun'] = [ | ||
| 2 | async () => { | ||
| 3 | const dir = "/assets"; | ||
| 4 | |||
| 5 | FS.mkdir(dir); | ||
| 6 | FS.mount(IDBFS, { autoPersist: true }, dir); | ||
| 7 | |||
| 8 | Module.fileSystemLoaded = new Promise((resolve, reject) => { | ||
| 9 | FS.syncfs(true, (err) => { | ||
| 10 | if (err) reject(err); | ||
| 11 | else resolve(true); | ||
| 12 | }); | ||
| 13 | }); | ||
| 14 | |||
| 15 | } | ||
| 16 | ]; | ||
diff --git a/06_storage/mime.txt b/06_storage/mime.txt new file mode 100644 index 0000000..6a9a425 --- /dev/null +++ b/06_storage/mime.txt | |||
| @@ -0,0 +1 @@ | |||
| text/javascript mjs | |||
diff --git a/06_storage/primes.c b/06_storage/primes.c new file mode 100644 index 0000000..4a17e8d --- /dev/null +++ b/06_storage/primes.c | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include <stdbool.h> | ||
| 4 | #include <pthread.h> | ||
| 5 | |||
| 6 | #include "primes.h" | ||
| 7 | #include "storage.h" | ||
| 8 | |||
| 9 | #define NTHREADS 16 | ||
| 10 | #define INDEX(i) ((i) >> 3) | ||
| 11 | #define MASK(i) (unsigned char)(1 << ((i) % 8)) | ||
| 12 | |||
| 13 | unsigned char primes_table[TABLESIZE]; | ||
| 14 | struct interval { int low; int high; int count; }; | ||
| 15 | |||
| 16 | void *pthread_routine(void *); | ||
| 17 | int primes_in_range(int, int, void (*)(const char *)); | ||
| 18 | void set_nonprime(unsigned char *, int); | ||
| 19 | bool isprime(const unsigned char *, int); | ||
| 20 | |||
| 21 | int primes_in_range(int low, int high, void (*log)(const char *)) { | ||
| 22 | static bool table_is_loaded = false; | ||
| 23 | |||
| 24 | pthread_t threads[NTHREADS]; | ||
| 25 | struct interval args[NTHREADS]; | ||
| 26 | |||
| 27 | if (low < 0 || high < low) | ||
| 28 | return 0; | ||
| 29 | |||
| 30 | if (!table_is_loaded) { | ||
| 31 | if (!read_table(primes_table)) { | ||
| 32 | generate_primes(primes_table, log); | ||
| 33 | if (!store_table(primes_table)) | ||
| 34 | log("Error storing table to indexed DB"); | ||
| 35 | } | ||
| 36 | |||
| 37 | table_is_loaded = true; | ||
| 38 | } | ||
| 39 | |||
| 40 | int interval_size = (high-low)/NTHREADS + 1; | ||
| 41 | for (int i = 0; i < NTHREADS; i++) { | ||
| 42 | args[i].low = low + i*interval_size; | ||
| 43 | args[i].high = args[i].low + interval_size; | ||
| 44 | pthread_create(&threads[i], NULL, pthread_routine, &args[i]); | ||
| 45 | } | ||
| 46 | |||
| 47 | log("All threads have started, computing..."); | ||
| 48 | |||
| 49 | int result = 0; | ||
| 50 | for (int i = 0; i < NTHREADS; i++) { | ||
| 51 | pthread_join(threads[i], NULL); | ||
| 52 | result += args[i].count; | ||
| 53 | } | ||
| 54 | |||
| 55 | return result; | ||
| 56 | } | ||
| 57 | |||
| 58 | void set_nonprime(unsigned char *table, int n) { | ||
| 59 | table[INDEX(n)] &= ~MASK(n); | ||
| 60 | } | ||
| 61 | |||
| 62 | bool isprime(const unsigned char *table, int n) { | ||
| 63 | return table[INDEX(n)] & MASK(n); | ||
| 64 | } | ||
| 65 | |||
| 66 | void generate_primes(unsigned char *table, void (*log)(const char *)) { | ||
| 67 | memset(table, 0xFF, TABLESIZE); | ||
| 68 | set_nonprime(table, 0); | ||
| 69 | set_nonprime(table, 1); | ||
| 70 | for (long long i = 0; i < MAX_PRIME; i++) { | ||
| 71 | if (i % 100000000 == 0 && log != NULL) { | ||
| 72 | char msg[200]; | ||
| 73 | sprintf(msg, | ||
| 74 | "Could not read table of primes, generating it\n" | ||
| 75 | "Done %llu / %d", i, MAX_PRIME); | ||
| 76 | log(msg); | ||
| 77 | } | ||
| 78 | if (!isprime(table, i)) | ||
| 79 | continue; | ||
| 80 | for (long long int j = 2*i; j < MAX_PRIME; j += i) | ||
| 81 | set_nonprime(table, j); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | void *pthread_routine(void *arg) { | ||
| 86 | struct interval *interval = arg; | ||
| 87 | |||
| 88 | interval->count = 0; | ||
| 89 | for (int i = interval->low; i < interval->high; i++) | ||
| 90 | if (isprime(primes_table, i)) | ||
| 91 | interval->count++; | ||
| 92 | |||
| 93 | return NULL; | ||
| 94 | } | ||
diff --git a/06_storage/primes.h b/06_storage/primes.h new file mode 100644 index 0000000..d9006f7 --- /dev/null +++ b/06_storage/primes.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef PRIMES_H | ||
| 2 | #define PRIMES_H | ||
| 3 | |||
| 4 | #include <limits.h> | ||
| 5 | |||
| 6 | #define MAX_PRIME INT_MAX | ||
| 7 | #define TABLESIZE (1 << 28) | ||
| 8 | |||
| 9 | int primes_in_range(int, int, void (*)(const char *)); | ||
| 10 | void generate_primes(unsigned char *, void (*)(const char *)); | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/06_storage/run-server.sh b/06_storage/run-server.sh new file mode 100755 index 0000000..3a526f3 --- /dev/null +++ b/06_storage/run-server.sh | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | darkhttpd . \ | ||
| 4 | --mimetypes mime.txt \ | ||
| 5 | --header 'Cross-Origin-Opener-Policy: same-origin' \ | ||
| 6 | --header 'Cross-Origin-Embedder-Policy: require-corp' | ||
diff --git a/06_storage/script.mjs b/06_storage/script.mjs new file mode 100644 index 0000000..1238371 --- /dev/null +++ b/06_storage/script.mjs | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | var aInput = document.getElementById("aInput"); | ||
| 2 | var bInput = document.getElementById("bInput"); | ||
| 3 | var button = document.getElementById("goButton"); | ||
| 4 | var resultText = document.getElementById("resultText"); | ||
| 5 | |||
| 6 | var worker = new Worker("./worker.mjs", { type: "module" }); | ||
| 7 | |||
| 8 | button.addEventListener("click", () => worker.postMessage({ | ||
| 9 | a: Number(aInput.value), | ||
| 10 | b: Number(bInput.value) | ||
| 11 | })); | ||
| 12 | |||
| 13 | worker.onmessage = (e) => { | ||
| 14 | if (e.data.type == "response") | ||
| 15 | resultText.innerText = e.data.message; | ||
| 16 | else if (e.data.type == "readySignal") { | ||
| 17 | button.disabled = false; | ||
| 18 | button.innerText = "Compute" | ||
| 19 | } | ||
| 20 | }; | ||
diff --git a/06_storage/storage.c b/06_storage/storage.c new file mode 100644 index 0000000..7542022 --- /dev/null +++ b/06_storage/storage.c | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdbool.h> | ||
| 3 | |||
| 4 | #include "primes.h" | ||
| 5 | |||
| 6 | #define FILENAME "/assets/primes_table" | ||
| 7 | |||
| 8 | bool read_table(unsigned char *table) { | ||
| 9 | FILE *f = fopen(FILENAME, "rb"); | ||
| 10 | if (f == NULL) | ||
| 11 | return false; | ||
| 12 | |||
| 13 | int b = fread(table, TABLESIZE, 1, f); | ||
| 14 | fclose(f); | ||
| 15 | |||
| 16 | return b == 1; | ||
| 17 | } | ||
| 18 | |||
| 19 | bool store_table(const unsigned char *table) { | ||
| 20 | FILE *f = fopen(FILENAME, "wb"); | ||
| 21 | if (f == NULL) | ||
| 22 | return false; | ||
| 23 | |||
| 24 | int b = fwrite(table, TABLESIZE, 1, f); | ||
| 25 | fclose(f); | ||
| 26 | |||
| 27 | return b == 1; | ||
| 28 | } | ||
diff --git a/06_storage/storage.h b/06_storage/storage.h new file mode 100644 index 0000000..ff0afae --- /dev/null +++ b/06_storage/storage.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef STORAGE_H | ||
| 2 | #define STORAGE_H | ||
| 3 | |||
| 4 | bool read_table(unsigned char *); | ||
| 5 | bool store_table(const unsigned char *); | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/06_storage/worker.mjs b/06_storage/worker.mjs new file mode 100644 index 0000000..929fabc --- /dev/null +++ b/06_storage/worker.mjs | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | import Primes from "./build/primes.mjs"; | ||
| 2 | |||
| 3 | var primes = await Primes(); | ||
| 4 | |||
| 5 | const logPtr = primes.addFunction((cstr) => { | ||
| 6 | const str = primes.UTF8ToString(cstr); | ||
| 7 | console.log(str); | ||
| 8 | postMessage({ message: str }); | ||
| 9 | }, "vp"); | ||
| 10 | |||
| 11 | onmessage = (e) => { | ||
| 12 | const count = primes._primes_in_range(e.data.a, e.data.b, logPtr); | ||
| 13 | postMessage({ | ||
| 14 | type: "response", | ||
| 15 | message: "There are " + count + " primes between " + | ||
| 16 | e.data.a + " and " + e.data.b | ||
| 17 | }); | ||
| 18 | }; | ||
| 19 | |||
| 20 | primes.fileSystemLoaded.then(() => { | ||
| 21 | postMessage({ type: "readySignal" }); | ||
| 22 | }); | ||
