並列FizzBuzz

最近並列プログラムにハマってます。amazon:マルチコアCPUのための並列プログラミング]と[amazon:MPIプログラミングを読みながらpthreadライブラリとかCellをいじって「早っ!」とか言ってみたり。ただし勉強不足なせいで現実問題に応用可能な知識が足りないです。

ってことで並列FizzBuzz!!今更!!

pthreadを使ったデータ分割型の並列プログラムです。タスク分割型はSEGVで落ちてしまうのでデバッグ中。

// fizzbuzz_data_parallel.c
/* 2008/04/09
 * pthreadを使ったデータ並列型fizzbuzz
 * openmpだとあまりにあっけないので。
 */
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

#ifndef SIZE
 #define SIZE (100) // データの数
#endif
#ifndef TNUM
//#define TNUM (1) // スレッドの数 SIZEの約数
#define TNUM (sysconf(_SC_NPROCESSORS_CONF))
#endif

enum Type {
  FIZZ,
  BUZZ,
  FIZZBUZZ,
  NONE
};


char *fb[3] = {
  "fizz",
  "buzz",
  "fizzbuzz"
};

typedef struct _targ {
  int id;
  int *data;
} targ_t;

int f(int n)
{
  int ret;
  if (n % 15 ==0)
    ret = FIZZBUZZ;
  else if (n % 3 ==0)
    ret = FIZZ;
  else if (n % 5 ==0)
    ret = BUZZ;
  else
    ret = NONE;
  return ret;
}

void calc_segment(void *ptr)
{
  int i;
  targ_t *arg = (targ_t*)ptr;
  int id = arg->id;
  int *data = arg->data;
  int start = SIZE/TNUM *id +1;
  int end = start + SIZE/TNUM;

  printf("[rank %d] from %d to %d\n", id, start, end);
  for (i = start; i < end; i++)
    data[i] = f(i);
}
  
int main()
{
  int i, j;
  int data[SIZE +1];
  pthread_t handle[TNUM]; //0番目の要素は使わない
  targ_t args[TNUM];

  for (i = 1; i <= SIZE; i++)
    data[i] = i;

  for (i = 0; i < TNUM; i++){
    args[i].id = i;
    args[i].data = data;
    
    pthread_create(&handle[i], NULL, (void*)calc_segment, (void*)&args[i]);
  }
  
  // join
  for (i = 0; i < TNUM; i++)
    pthread_join(handle[i], NULL);
  
  // 結果の出力
  for (i = 1; i <= SIZE; i++){
    if (data[i] == NONE)
      printf("%d\n", i);
    else
      printf("%s\n", fb[data[i]]);
  }
  return 0;
}

コンパイル・実行

$ cc -lpthread fizzbuzz_data_parallel.c -DN=16000 -DTNUM=4
$ ./a.out
~(結果)

残念な事に、fizzbuzz問題を並列化しても各々の計算量がとても少なく、しかもプログラム実行時間におけるI/Oが占める時間が大きいために並列化の恩恵はあまり得られないのであった (´・ω・`)