| ナビゲーションリンクをスキップ | |
| 印刷ビューの終了 | |
|   | Oracle Solaris Studio 12.3: スレッドアナライザユーザーズガイド Oracle Solaris Studio 12.3 Information Library (日本語) | 
2.2.3.1 スレッドアナライザを使用したデータの競合実験の表示
2.2.3.2 er_print を使用したデータの競合実験の表示
2.4.1 データの競合が誤検知であるかどうかをチェックする
このチュートリアルでは、データの競合を含んだ 2 つのプログラムを使用します。
最初のプログラムは素数を見つけます。このプログラムは C 言語で作成され、OpenMP 指令で並列化されています。ソースファイルは prime_omp.c と呼ばれます。
2 番目のプログラムも素数を見つけるもので、やはり C 言語で作成されます。ただし、これは OpenMP 指令でなく POSIX スレッドで並列化されます。ソースファイルは prime_pthr.c と呼ばれます。
このチュートリアルで使用するソースファイルは、Oracle Solaris Studio 開発者ポータルのサンプルのダウンロードエリアからダウンロードできます。
サンプルファイルをダウンロードして展開したあと、SolarisStudioSampleApplications/ThreadAnalyzer ディレクトリからサンプルを見つけることができます。サンプルは、prime_omp および prime_pthr サブディレクトリにあります。各サンプルディレクトリには、手順に関する DEMO ファイルと Makefile ファイルが 1 つずつ含まれていますが、このチュートリアルではそれらの手順に従わず、Makefile も使用しません。代わりに、コマンドを個別に実行していきます。
このチュートリアルに従うには、サンプルディレクトリから prime_omp.c と prime_pthr.c ファイルを別のディレクトリにコピーするか、独自のファイルを作成し、次のコードリストからコードをコピーしてください。
prime_omp.c のソースコードは次に示すとおりです。
  1  /*
  2   * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All Rights Reserved.
  3   * @(#)prime_omp.c 1.3 (Oracle) 10/03/26
  4   */
  5
  6  #include <stdio.h>
  7  #include <math.h>
  8  #include <omp.h>
  9
 10  #define THREADS 4
 11  #define N 10000
 12
 13  int primes[N];
 14  int pflag[N];
 15
 16  int is_prime(int v)
 17  {
 18   int i;
 19   int bound = floor(sqrt(v)) + 1;
 20
 21   for (i = 2; i < bound; i++) {
 22          /* no need to check against known composites */
 23          if (!pflag[i])
 24              continue;
 25          if (v % i == 0) {
 26              pflag[v] = 0;
 27              return 0;
 28          }
 29      }
 30      return (v > 1);
 31  }
 32
 33  int main(int argn, char **argv)
 34  {
 35      int i;
 36      int total = 0;
 37
 38  #ifdef _OPENMP
 39      omp_set_dynamic(0);
 40      omp_set_num_threads(THREADS);
 41  #endif
 42
 43      for (i = 0; i < N; i++) {
 44          pflag[i] = 1;
 45      }
 46
 47      #pragma omp parallel for
 48      for (i = 2; i < N; i++) {
 49          if ( is_prime(i) ) {
 50              primes[total] = i;
 51              total++;
 52          }
 53      }
 54
 55      printf("Number of prime numbers between 2 and %d: %d\n",
 56             N, total);
 57
 58      return 0;
 59  }
prime_pthr.c のソースコードは次に示すとおりです。
  1  /*
  2   * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All Rights Reserved.
  3   * @(#)prime_pthr.c 1.4 (Oracle) 10/03/26
  4   */
  5
  6  #include <stdio.h>
  7  #include <math.h>
  8  #include <pthread.h>
  9
 10  #define THREADS 4
 11  #define N 10000
 12
 13  int primes[N];
 14  int pflag[N];
 15  int total = 0;
 16
 17  int is_prime(int v)
 18  {
 19      int i;
 20      int bound = floor(sqrt(v)) + 1;
 21
 22      for (i = 2; i < bound; i++) {
 23          /* no need to check against known composites */
 24          if (!pflag[i])
 25              continue;
 26          if (v % i == 0) {
 27              pflag[v] = 0;
 28              return 0;
 29          }
 30      }
 31      return (v > 1);
 32  }
 33
 34  void *work(void *arg)
 35  {
 36      int start;
 37      int end;
 38      int i;
 39
 40      start = (N/THREADS) * (*(int *)arg);
 41      end = start + N/THREADS;
 42      for (i = start; i < end; i++) {
 43          if ( is_prime(i) ) {
 44              primes[total] = i;
 45              total++;
 46          }
 47      }
 48      return NULL;
 49  }
 50
 51  int main(int argn, char **argv)
 52  {
 53      int i;
 54      pthread_t tids[THREADS-1];
 55
 56      for (i = 0; i < N; i++) {
 57          pflag[i] = 1;
 58      }
 59
 60      for (i = 0; i < THREADS-1; i++) {
 61          pthread_create(&tids[i], NULL, work, (void *)&i);
 62      }
 63
 64      i = THREADS-1;
 65      work((void *)&i);
 66
 67      for (i = 0; i < THREADS-1; i++) {
 68          pthread_join(tids[i], NULL);
 69      }
 70
 71      printf("Number of prime numbers between 2 and %d: %d\n",
 72             N, total);
 73
 74      return 0;
 75  }
コードに競合状態が含まれ、実行するごとに別々の計算結果が得られる場合、メモリーアクセスの順序は決まっていません。prime_omp および prime_pthr プログラムの正しい答えは 1229 です。
例をコンパイルして実行できるので、prime_omp または prime_pthr を実行するごとに、コード内のデータの競合によって誤ったまたは矛盾した結果が生じることがわかります。
次の例で、太字のコマンドを入力して、prime_omp プログラムをコンパイルし実行します。
% cc -xopenmp=noopt -o prime_omp prime_omp.c -lm % % ./prime_omp Number of prime numbers between 2 and 10000: 1229 % ./prime_omp Number of prime numbers between 2 and 10000: 1228 % ./prime_omp Number of prime numbers between 2 and 10000: 1180
次の例で、太字のコマンドを入力して、prime_pthr プログラムをコンパイルし実行します。
% cc -mt -o prime_pthr prime_pthr.c -lm % % ./prime_pthr Number of prime numbers between 2 and 10000: 1140 % ./prime_pthr Number of prime numbers between 2 and 10000: 1122 % ./prime_pthr Number of prime numbers between 2 and 10000: 1141
各プログラムを 3 回実行した結果が矛盾していることに注意してください。矛盾した結果が表示されるまで、4 回以上プログラムを実行する必要がある場合もあります。
次に、データの競合が生じている位置を特定できるように、コードを計測し、実験を作成します。