WebAssembly
Signed-off-by: Tiago Garcia <tiago.rgarcia@ua.pt>
This commit is contained in:
parent
d86863820b
commit
fa06494b59
|
|
@ -0,0 +1,268 @@
|
||||||
|
//
|
||||||
|
// Arquiteturas de Alto Desempenho 2025/2026
|
||||||
|
//
|
||||||
|
// DETI Coin Miner - WebAssembly implementation
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "aad_data_types.h"
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten.h>
|
||||||
|
#include "aad_sha1_wasm.h"
|
||||||
|
#else
|
||||||
|
#include "aad_sha1_cpu.h"
|
||||||
|
#include "aad_utilities.h"
|
||||||
|
#include "aad_vault.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Global mining state
|
||||||
|
static volatile int keep_running = 1;
|
||||||
|
static u64_t total_attempts = 0;
|
||||||
|
static u32_t coins_found = 0;
|
||||||
|
static double mining_start_time = 0;
|
||||||
|
static u32_t found_coins[1024][14]; // Store up to 1024 found coins
|
||||||
|
static u32_t found_coins_count = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if a hash starts with aad20250
|
||||||
|
//
|
||||||
|
static int is_valid_coin(u32_t *hash)
|
||||||
|
{
|
||||||
|
return hash[0] == 0xAAD20250u;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Increment coin variable part (positions 12-53)
|
||||||
|
//
|
||||||
|
static int increment_coin(u32_t coin[14])
|
||||||
|
{
|
||||||
|
int pos = 53;
|
||||||
|
while(pos >= 12)
|
||||||
|
{
|
||||||
|
u08_t *byte = &((u08_t *)coin)[pos ^ 3];
|
||||||
|
if(*byte == '\n' || *byte == 0x80)
|
||||||
|
*byte = 32;
|
||||||
|
|
||||||
|
(*byte)++;
|
||||||
|
|
||||||
|
if(*byte == '\n')
|
||||||
|
(*byte)++;
|
||||||
|
|
||||||
|
if(*byte >= 127)
|
||||||
|
{
|
||||||
|
*byte = 32;
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (pos >= 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get current time in seconds
|
||||||
|
//
|
||||||
|
static double get_time()
|
||||||
|
{
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
return emscripten_get_now() / 1000.0;
|
||||||
|
#else
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||||
|
return (double)ts.tv_sec + (double)ts.tv_nsec / 1e9;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Main mining iteration (called from JavaScript)
|
||||||
|
//
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
#endif
|
||||||
|
int mine_coins_wasm(u32_t iterations_per_call)
|
||||||
|
{
|
||||||
|
static u32_t coin[14];
|
||||||
|
static int initialized = 0;
|
||||||
|
u32_t hash[5];
|
||||||
|
|
||||||
|
// Initialize coin template on first call
|
||||||
|
if(!initialized)
|
||||||
|
{
|
||||||
|
memset(coin, 0, sizeof(coin));
|
||||||
|
((u08_t *)coin)[0x0 ^ 3] = 'D';
|
||||||
|
((u08_t *)coin)[0x1 ^ 3] = 'E';
|
||||||
|
((u08_t *)coin)[0x2 ^ 3] = 'T';
|
||||||
|
((u08_t *)coin)[0x3 ^ 3] = 'I';
|
||||||
|
((u08_t *)coin)[0x4 ^ 3] = ' ';
|
||||||
|
((u08_t *)coin)[0x5 ^ 3] = 'c';
|
||||||
|
((u08_t *)coin)[0x6 ^ 3] = 'o';
|
||||||
|
((u08_t *)coin)[0x7 ^ 3] = 'i';
|
||||||
|
((u08_t *)coin)[0x8 ^ 3] = 'n';
|
||||||
|
((u08_t *)coin)[0x9 ^ 3] = ' ';
|
||||||
|
((u08_t *)coin)[0xa ^ 3] = '2';
|
||||||
|
((u08_t *)coin)[0xb ^ 3] = ' ';
|
||||||
|
((u08_t *)coin)[0x36 ^ 3] = '\n';
|
||||||
|
((u08_t *)coin)[0x37 ^ 3] = 0x80;
|
||||||
|
|
||||||
|
for(int i = 12; i < 54; i++)
|
||||||
|
((u08_t *)coin)[i ^ 3] = 'A' + (i - 12) % 26;
|
||||||
|
|
||||||
|
mining_start_time = get_time();
|
||||||
|
initialized = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!keep_running)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Mine for the specified number of iterations
|
||||||
|
for(u32_t i = 0; i < iterations_per_call && keep_running; i++)
|
||||||
|
{
|
||||||
|
sha1(coin, hash);
|
||||||
|
total_attempts++;
|
||||||
|
|
||||||
|
if(is_valid_coin(hash))
|
||||||
|
{
|
||||||
|
if(found_coins_count < 1024)
|
||||||
|
{
|
||||||
|
memcpy(found_coins[found_coins_count], coin, sizeof(coin));
|
||||||
|
found_coins_count++;
|
||||||
|
}
|
||||||
|
coins_found++;
|
||||||
|
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
printf("COIN FOUND! (attempt %llu)\n", (unsigned long long)total_attempts);
|
||||||
|
save_coin(coin);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
increment_coin(coin);
|
||||||
|
}
|
||||||
|
|
||||||
|
return keep_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get mining statistics
|
||||||
|
//
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
#endif
|
||||||
|
void get_statistics(u64_t *attempts, u32_t *coins, double *hash_rate, double *elapsed_time)
|
||||||
|
{
|
||||||
|
*attempts = total_attempts;
|
||||||
|
*coins = coins_found;
|
||||||
|
*elapsed_time = get_time() - mining_start_time;
|
||||||
|
*hash_rate = (*elapsed_time > 0) ? (total_attempts / *elapsed_time) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stop mining
|
||||||
|
//
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
#endif
|
||||||
|
void stop_mining()
|
||||||
|
{
|
||||||
|
keep_running = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get found coin data (returns pointer to coin array)
|
||||||
|
//
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
#endif
|
||||||
|
u32_t* get_found_coin(u32_t index)
|
||||||
|
{
|
||||||
|
if(index < found_coins_count)
|
||||||
|
return found_coins[index];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get number of found coins
|
||||||
|
//
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
#endif
|
||||||
|
u32_t get_found_coins_count()
|
||||||
|
{
|
||||||
|
return found_coins_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Reset mining state
|
||||||
|
//
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
#endif
|
||||||
|
void reset_mining()
|
||||||
|
{
|
||||||
|
keep_running = 1;
|
||||||
|
total_attempts = 0;
|
||||||
|
coins_found = 0;
|
||||||
|
found_coins_count = 0;
|
||||||
|
mining_start_time = get_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Main function (for standalone compilation/testing)
|
||||||
|
//
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
u64_t max_attempts = 0;
|
||||||
|
|
||||||
|
if(argc > 1)
|
||||||
|
max_attempts = strtoull(argv[1], NULL, 10);
|
||||||
|
|
||||||
|
printf("Mining DETI coins using WebAssembly implementation (standalone mode)...\n");
|
||||||
|
printf("Press Ctrl+C to stop\n\n");
|
||||||
|
|
||||||
|
time_measurement();
|
||||||
|
time_measurement();
|
||||||
|
double start_time = wall_time_delta();
|
||||||
|
double last_report = start_time;
|
||||||
|
|
||||||
|
while(keep_running && (max_attempts == 0 || total_attempts < max_attempts))
|
||||||
|
{
|
||||||
|
mine_coins_wasm(100000);
|
||||||
|
|
||||||
|
time_measurement();
|
||||||
|
double current_time = wall_time_delta() - start_time;
|
||||||
|
|
||||||
|
if(current_time - last_report >= 1.0)
|
||||||
|
{
|
||||||
|
u64_t attempts;
|
||||||
|
u32_t coins;
|
||||||
|
double hash_rate, elapsed;
|
||||||
|
get_statistics(&attempts, &coins, &hash_rate, &elapsed);
|
||||||
|
|
||||||
|
printf("Attempts: %llu, Rate: %.2f MH/s, Coins: %u\n",
|
||||||
|
(unsigned long long)attempts, hash_rate / 1e6, coins);
|
||||||
|
|
||||||
|
last_report = current_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
time_measurement();
|
||||||
|
double total_time = wall_time_delta() - start_time;
|
||||||
|
|
||||||
|
printf("\n=== Mining Statistics ===\n");
|
||||||
|
printf("Total attempts: %llu\n", (unsigned long long)total_attempts);
|
||||||
|
printf("Total time: %.2f seconds\n", total_time);
|
||||||
|
printf("Average rate: %.2f attempts/second\n", total_attempts / total_time);
|
||||||
|
printf("Coins found: %u\n", coins_found);
|
||||||
|
|
||||||
|
save_coin(NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef AAD_SHA1_WASM
|
||||||
|
#define AAD_SHA1_WASM
|
||||||
|
|
||||||
|
#include "aad_data_types.h"
|
||||||
|
#include "aad_sha1.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// SHA1 hash computation for WebAssembly (scalar implementation)
|
||||||
|
//
|
||||||
|
|
||||||
|
static inline u32_t rotate_left(u32_t x, int n)
|
||||||
|
{
|
||||||
|
return (x << n) | (x >> (32 - n));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sha1(u32_t *coin, u32_t *hash)
|
||||||
|
{
|
||||||
|
// Define the macros needed by CUSTOM_SHA1_CODE
|
||||||
|
#define T u32_t
|
||||||
|
#define C(c) (c)
|
||||||
|
#define ROTATE(x,n) rotate_left(x,n)
|
||||||
|
#define DATA(idx) coin[idx]
|
||||||
|
#define HASH(idx) hash[idx]
|
||||||
|
|
||||||
|
// Use the standard SHA1 template from aad_sha1.h
|
||||||
|
CUSTOM_SHA1_CODE();
|
||||||
|
|
||||||
|
#undef T
|
||||||
|
#undef C
|
||||||
|
#undef ROTATE
|
||||||
|
#undef DATA
|
||||||
|
#undef HASH
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>DETI Coin Miner - WebAssembly</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: monospace;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
#stats {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
background: #f0f0f0;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.control-group {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: inline-block;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>DETI Coin Miner (WebAssembly)</h1>
|
||||||
|
<div class="control-group">
|
||||||
|
<label>Iterations per batch:</label>
|
||||||
|
<input type="number" id="batchSize" value="1000000" step="100000">
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label>Update interval (ms):</label>
|
||||||
|
<input type="number" id="updateInterval" value="100" step="50">
|
||||||
|
</div>
|
||||||
|
<button id="start">Start Mining</button>
|
||||||
|
<button id="stop">Stop Mining</button>
|
||||||
|
<button id="reset">Reset</button>
|
||||||
|
<div id="stats">
|
||||||
|
Waiting to start...
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="aad_coin_miner_wasm.js"></script>
|
||||||
|
<script>
|
||||||
|
let mining = false;
|
||||||
|
let Module;
|
||||||
|
let miningInterval;
|
||||||
|
let updateInterval;
|
||||||
|
|
||||||
|
CoinMinerModule().then(mod => {
|
||||||
|
Module = mod;
|
||||||
|
console.log('WebAssembly module loaded');
|
||||||
|
|
||||||
|
document.getElementById('start').onclick = () => {
|
||||||
|
if (!mining) {
|
||||||
|
mining = true;
|
||||||
|
console.log('Starting mining...');
|
||||||
|
startMining();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById('stop').onclick = () => {
|
||||||
|
mining = false;
|
||||||
|
Module._stop_mining();
|
||||||
|
clearInterval(miningInterval);
|
||||||
|
clearInterval(updateInterval);
|
||||||
|
console.log('Mining stopped');
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById('reset').onclick = () => {
|
||||||
|
Module._reset_mining();
|
||||||
|
mining = false;
|
||||||
|
clearInterval(miningInterval);
|
||||||
|
clearInterval(updateInterval);
|
||||||
|
document.getElementById('stats').innerHTML = 'Reset complete. Click Start to begin.';
|
||||||
|
console.log('Mining reset');
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateStats() {
|
||||||
|
const attemptsPtr = Module._malloc(8);
|
||||||
|
const coinsPtr = Module._malloc(4);
|
||||||
|
const hashRatePtr = Module._malloc(8);
|
||||||
|
const elapsedPtr = Module._malloc(8);
|
||||||
|
|
||||||
|
Module._get_statistics(attemptsPtr, coinsPtr, hashRatePtr, elapsedPtr);
|
||||||
|
|
||||||
|
const attempts = Module.getValue(attemptsPtr, 'i64');
|
||||||
|
const coins = Module.getValue(coinsPtr, 'i32');
|
||||||
|
const hashRate = Module.getValue(hashRatePtr, 'double');
|
||||||
|
const elapsed = Module.getValue(elapsedPtr, 'double');
|
||||||
|
|
||||||
|
Module._free(attemptsPtr);
|
||||||
|
Module._free(coinsPtr);
|
||||||
|
Module._free(hashRatePtr);
|
||||||
|
Module._free(elapsedPtr);
|
||||||
|
|
||||||
|
document.getElementById('stats').innerHTML = `
|
||||||
|
<strong>Mining Statistics:</strong><br>
|
||||||
|
Attempts: ${attempts.toString()}<br>
|
||||||
|
Coins Found: ${coins}<br>
|
||||||
|
Hash Rate: ${(hashRate / 1e6).toFixed(2)} MH/s<br>
|
||||||
|
Elapsed Time: ${elapsed.toFixed(2)} seconds<br>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const coinsFound = Module._get_found_coins_count();
|
||||||
|
if (coinsFound > 0) {
|
||||||
|
console.log(`Total coins found: ${coinsFound}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startMining() {
|
||||||
|
const batchSize = parseInt(document.getElementById('batchSize').value);
|
||||||
|
const updateMs = parseInt(document.getElementById('updateInterval').value);
|
||||||
|
|
||||||
|
// Mine continuously using setInterval for larger batches
|
||||||
|
miningInterval = setInterval(() => {
|
||||||
|
if (!mining) {
|
||||||
|
clearInterval(miningInterval);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Module._mine_coins_wasm(batchSize);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
// Update stats periodically
|
||||||
|
updateInterval = setInterval(updateStats, updateMs);
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Failed to load WebAssembly module:', err);
|
||||||
|
document.getElementById('stats').innerHTML = 'Error loading module: ' + err.message;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
14
makefile
14
makefile
|
|
@ -84,11 +84,21 @@ coin_miner_cuda_kernel.cubin: aad_coin_miner_cuda_kernel.cu aad_sha1.h makefile
|
||||||
coin_miner_cuda: aad_coin_miner_cuda.c coin_miner_cuda_kernel.cubin aad_sha1.h aad_sha1_cpu.h aad_data_types.h aad_utilities.h aad_vault.h aad_cuda_utilities.h makefile
|
coin_miner_cuda: aad_coin_miner_cuda.c coin_miner_cuda_kernel.cubin aad_sha1.h aad_sha1_cpu.h aad_data_types.h aad_utilities.h aad_vault.h aad_cuda_utilities.h makefile
|
||||||
cc -march=native -Wall -Wshadow -Werror -O3 -I$(CUDA_DIR)/include $< -o $@ -lcuda
|
cc -march=native -Wall -Wshadow -Werror -O3 -I$(CUDA_DIR)/include $< -o $@ -lcuda
|
||||||
|
|
||||||
|
coin_miner_wasm: aad_coin_miner_wasm.c aad_sha1.h aad_sha1_cpu.h aad_sha1_wasm.h aad_data_types.h aad_utilities.h aad_vault.h makefile
|
||||||
|
emcc -O3 -flto -o aad_coin_miner_wasm.js aad_coin_miner_wasm.c \
|
||||||
|
-s WASM=1 \
|
||||||
|
-s EXPORTED_FUNCTIONS='["_mine_coins_wasm","_get_statistics","_stop_mining","_reset_mining","_get_found_coin","_get_found_coins_count","_malloc","_free"]' \
|
||||||
|
-s EXPORTED_RUNTIME_METHODS='["cwrap","ccall","getValue","setValue"]' \
|
||||||
|
-s ALLOW_MEMORY_GROWTH=1 \
|
||||||
|
-s MODULARIZE=1 \
|
||||||
|
-s EXPORT_NAME='CoinMinerModule' \
|
||||||
|
-s INITIAL_MEMORY=67108864
|
||||||
|
|
||||||
benchmark: aad_benchmark.c aad_sha1.h aad_sha1_cpu.h aad_data_types.h aad_utilities.h makefile
|
benchmark: aad_benchmark.c aad_sha1.h aad_sha1_cpu.h aad_data_types.h aad_utilities.h makefile
|
||||||
cc -march=native -Wall -Wshadow -Werror -O3 $< -o $@
|
cc -march=native -Wall -Wshadow -Werror -O3 $< -o $@
|
||||||
|
|
||||||
miners: coin_miner_cpu coin_miner_simd coin_miner_cuda benchmark
|
miners: coin_miner_cpu coin_miner_simd coin_miner_wasm coin_miner_cuda benchmark
|
||||||
|
|
||||||
all: sha1_tests sha1_cuda_test sha1_cuda_kernel.cubin \
|
all: sha1_tests sha1_cuda_test sha1_cuda_kernel.cubin \
|
||||||
coin_miner_cpu coin_miner_simd coin_miner_cuda coin_miner_cuda_kernel.cubin \
|
coin_miner_cpu coin_miner_simd coin_miner_wasm coin_miner_cuda coin_miner_cuda_kernel.cubin \
|
||||||
benchmark
|
benchmark
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue