aad-assignment-1/aad_coin_miner_ocl.c

226 lines
5.8 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Arquiteturas de Alto Desempenho 2025/2026
//
// DETI Coin Miner - OpenCL implementation
//
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include "aad_data_types.h"
#include "aad_utilities.h"
#include "aad_sha1_cpu.h"
#include "aad_ocl_utilities.h"
#include "aad_vault.h"
#define COINS_STORAGE_SIZE 1024u
static volatile int keep_running = 1;
void signal_handler(int signum)
{
(void)signum;
keep_running = 0;
}
// Coin reconstruction from stored data
static void reconstruct_coin(u32_t *stored_data, u32_t coin[14])
{
for(int i = 0; i < 14; i++)
coin[i] = stored_data[i];
}
// Get current wall time in seconds
static double get_wall_time(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (double)ts.tv_sec + (double)ts.tv_nsec * 1.0e-9;
}
//
// Mine DETI coins using OpenCL
//
static void mine_coins_ocl(u64_t max_attempts, double max_time)
{
ocl_data_t od;
u32_t *host_storage;
u64_t attempts = 0;
u32_t coins_found = 0;
u32_t kernel_runs = 0;
// Initialize OpenCL
od.platform_number = 0;
od.device_number = 0;
od.kernel_file_name = "aad_coin_miner_ocl_kernel.cl";
od.kernel_name = "mine_deti_coins_kernel";
od.data_size[0] = COINS_STORAGE_SIZE * sizeof(u32_t);
od.data_size[1] = 0;
initialize_ocl(&od);
host_storage = (u32_t *)od.host_data[0];
// Kernel configuration
od.local_work_size = RECOMMENDED_OCL_WORK_GROUP_SIZE;
od.global_work_size = 4096 * od.local_work_size;
u32_t n_threads = od.global_work_size;
printf("Mining DETI coins using OpenCL...\n");
printf("Device: %s\n", od.device_name);
printf("Work groups: %zu × %zu = %u total work items\n",
od.global_work_size / od.local_work_size, od.local_work_size, n_threads);
printf("Kernel: %s\n", od.kernel_name);
if(max_attempts > 0 && max_time > 0)
printf("Will stop after %llu attempts OR %.2f seconds (whichever comes first)\n",
(unsigned long long)max_attempts, max_time);
else if(max_attempts > 0)
printf("Will stop after %llu attempts\n", (unsigned long long)max_attempts);
else if(max_time > 0)
printf("Will stop after %.2f seconds\n", max_time);
else
printf("Running indefinitely until Ctrl+C...\n");
printf("Press Ctrl+C to stop\n\n");
u32_t param1 = (u32_t)time(NULL);
u32_t param2 = 0x12345678u;
double start_time = get_wall_time();
while(keep_running)
{
// Check stopping conditions
if(max_attempts > 0 && attempts >= max_attempts)
break;
double elapsed = get_wall_time() - start_time;
if(max_time > 0 && elapsed >= max_time)
break;
// Initialize storage area
host_storage[0] = 1u;
// Copy to device
host_to_device_copy(&od, 0);
// Set kernel arguments
od.n_kernel_arguments = 3;
set_kernel_arg(&od, 0, sizeof(cl_mem), &od.device_data[0]);
set_kernel_arg(&od, 1, sizeof(u32_t), &param1);
set_kernel_arg(&od, 2, sizeof(u32_t), &param2);
// Launch the OpenCL kernel
launch_kernel(&od);
// Copy results back
device_to_host_copy(&od, 0);
// Process found coins
u32_t n_stored = (host_storage[0] - 1) / 14;
if(n_stored > 0 && host_storage[0] < COINS_STORAGE_SIZE)
{
for(u32_t i = 0; i < n_stored; i++)
{
u32_t coin[14];
reconstruct_coin(&host_storage[1 + i * 14], coin);
// Verify it's actually a valid coin
u32_t hash[5];
sha1(coin, hash);
if(hash[0] == 0xAAD20250u)
{
coins_found++;
printf("COIN FOUND! (kernel %u)\n", kernel_runs);
save_coin(coin);
}
}
}
// Update counters
kernel_runs++;
attempts += n_threads;
// Update parameters for next iteration
param1++;
param2 = param2 ^ 0x9E3779B9u;
// Print progress every 10 kernel launches
if(kernel_runs % 10 == 0)
{
elapsed = get_wall_time() - start_time;
double rate = attempts / elapsed;
printf("Attempts: %llu, Rate: %.2f MH/s, Coins: %u, Kernels: %u, Elapsed: %.2fs\n",
(unsigned long long)attempts, rate / 1e6, coins_found, kernel_runs, elapsed);
}
}
double total_time = get_wall_time() - start_time;
printf("\n=== Mining Statistics ===\n");
printf("Total attempts: %llu\n", (unsigned long long)attempts);
printf("Total time: %.2f seconds\n", total_time);
printf("Average rate: %.2f attempts/second\n", attempts / total_time);
printf("Coins found: %u\n", coins_found);
printf("Kernel launches: %u\n", kernel_runs);
// Save any remaining coins
save_coin(NULL);
terminate_ocl(&od);
}
void print_usage(const char *prog_name)
{
printf("Usage: %s [OPTIONS]\n", prog_name);
printf("Options:\n");
printf(" -a <attempts> Maximum number of attempts\n");
printf(" -t <seconds> Maximum time in seconds\n");
printf(" -h Show this help message\n");
printf("\nExamples:\n");
printf(" %s -a 1000000000 # Run for 1B attempts\n", prog_name);
printf(" %s -t 60 # Run for 60 seconds\n", prog_name);
printf(" %s -a 1000000000 -t 60 # Stop at 1B attempts OR 60s (whichever first)\n", prog_name);
printf(" %s # Run indefinitely until Ctrl+C\n", prog_name);
}
int main(int argc, char *argv[])
{
u64_t max_attempts = 0;
double max_time = 0;
int opt;
signal(SIGINT, signal_handler);
// Parse command line options
while((opt = getopt(argc, argv, "a:t:h")) != -1)
{
switch(opt)
{
case 'a':
max_attempts = strtoull(optarg, NULL, 10);
break;
case 't':
max_time = atof(optarg);
break;
case 'h':
print_usage(argv[0]);
return 0;
default:
print_usage(argv[0]);
return 1;
}
}
mine_coins_ocl(max_attempts, max_time);
return 0;
}