[hashcash] parallel hashcash proof of concept

  • From: Hubert Chan <hubert@xxxxxxxxx>
  • To: hashcash@xxxxxxxxxxxxx
  • Date: Wed, 02 Mar 2005 13:00:10 -0500

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.

Other related posts: