Sorry for the lateness of this. I know I had promised this last month, but my computer died, and I got busy when my new machine arrived. Here is a *proof of concept* for parallel hashcash using Adam's idea of forking multiple copies and killing them when the first one completes. This version does several things wrong (not the least of which is hard coding the hashcash command line). For example, it does not guarantee that if two instances finish at (roughly) the same time, that they won't clobber each others' output. (The final version will use pipes to get the result from the children.) So using the output of this program is done at your own risk. This is meant only for testing purposes, to see the performance characteristics of this type of parallel execution. I've tried it on a cluster (openMosix) of 15 nodes (but only executing 8 parallel processes). The load distributes over the nodes. Running some informal tests, generating a 25-bit stamp in parallel *can* take about the same time as generating a 22-bit stamp with just one process (as would be expected), but sometimes generating the 22-bit stamp is much faster. But my number of runs is far too small so far to say anything meaningful. I suspect that the variance in generation time should decrease too. (It's been a while since I took stats.) Someone with an SMP/hyperthreading machine should test it out.
/* hashfork.c * * by Hubert Chan * * This file is hereby placed in the public domain. * */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <time.h> #include <signal.h> #include <sys/wait.h> const int NUM_PROCS=15; int main (int argc, char *argv[]) { int i; pid_t children[NUM_PROCS]; pid_t pid; int status; for (i = 0; i < NUM_PROCS; i++) { pid = fork (); if (pid) { /* parent */ children[i] = pid; } else { int wait_time = 0; pid = getpid (); printf ("process %d started.\n", pid); /* this should be a function call to calculate the hashcash instead of * an execl */ execl ("/usr/bin/hashcash", "/usr/bin/hashcash", "-mb25", "foo", NULL); exit(0); /* --- ignore this --- */ srand (time (NULL) + pid); wait_time = rand () % 20; printf ("%d: waiting %d seconds.\n", pid, wait_time); sleep (wait_time); printf ("%d: exiting.\n", pid); exit (0); } } pid = wait (&status); printf("process %d exited.\nkilling all children.\n", pid); for (i = 0; i < NUM_PROCS; i++) { printf ("%d\n", children[i]); kill (children[i], SIGKILL); } return 0; }
Adam, do you think it would be better to have this integrated into hashcash? Or should it be kept as an external wrapper? I was initially leaning toward the former, but now I'm leaning toward the latter since it would prevent hashcash itself from becoming too complex. -- Hubert Chan <hubert@xxxxxxxxx> - http://www.uhoreg.ca/ PGP/GnuPG key: 1024D/124B61FA Fingerprint: 96C5 012F 5F74 A5F7 1FF7 5291 AF29 C719 124B 61FA Key available at wwwkeys.pgp.net. Encrypted e-mail preferred.