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
|
||||
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
|
||||
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 \
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in New Issue