2
0

test_stack.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
  3. * Original Author: Hans Boehm
  4. *
  5. * This file may be redistributed and/or modified under the
  6. * terms of the GNU General Public License as published by the Free Software
  7. * Foundation; either version 2, or (at your option) any later version.
  8. *
  9. * It is distributed in the hope that it will be useful, but WITHOUT ANY
  10. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. * FOR A PARTICULAR PURPOSE. See the GNU General Public License in the
  12. * file doc/COPYING for more details.
  13. */
  14. #if defined(HAVE_CONFIG_H)
  15. # include "config.h"
  16. #endif
  17. #include <pthread.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include "atomic_ops.h"
  21. #include "atomic_ops_stack.h"
  22. #define MAX_NTHREADS 100
  23. #ifndef NO_TIMES
  24. #include <time.h>
  25. #include <sys/time.h>
  26. /* Need 64-bit long long support */
  27. long long
  28. get_msecs(void)
  29. {
  30. struct timeval tv;
  31. gettimeofday(&tv, 0);
  32. return (long long)tv.tv_sec * 1000 + tv.tv_usec/1000;
  33. }
  34. #else
  35. # define get_msecs() 0
  36. #endif
  37. typedef struct le {
  38. AO_t next;
  39. int data;
  40. } list_element;
  41. AO_stack_t the_list = AO_STACK_INITIALIZER;
  42. void add_elements(int n)
  43. {
  44. list_element * le;
  45. if (n == 0) return;
  46. add_elements(n-1);
  47. le = malloc(sizeof(list_element));
  48. le -> data = n;
  49. AO_stack_push(&the_list, (AO_t *)le);
  50. }
  51. void print_list()
  52. {
  53. list_element *p;
  54. for (p = (list_element *)AO_REAL_HEAD_PTR(the_list);
  55. p != 0;
  56. p = (list_element *)AO_REAL_NEXT_PTR(p -> next))
  57. printf("%d\n", p -> data);
  58. }
  59. static char marks[MAX_NTHREADS * MAX_NTHREADS];
  60. void check_list(int n)
  61. {
  62. list_element *p;
  63. int i;
  64. for (i = 1; i <= n; ++i) marks[i] = 0;
  65. for (p = (list_element *)AO_REAL_HEAD_PTR(the_list);
  66. p != 0;
  67. p = (list_element *)AO_REAL_NEXT_PTR(p -> next))
  68. {
  69. if (p -> data > n || p -> data <= 0)
  70. fprintf(stderr, "Found erroneous list element %d\n", p -> data);
  71. if (marks[p -> data] != 0)
  72. fprintf(stderr, "Found duplicate list element %d\n", p -> data);
  73. marks[p -> data] = 1;
  74. }
  75. for (i = 1; i <= n; ++i)
  76. if (marks[i] != 1)
  77. fprintf(stderr, "Missing list element %d\n", i);
  78. }
  79. volatile AO_t ops_performed = 0;
  80. #define LIMIT 1000000
  81. /* Total number of push/pop ops in all threads per test. */
  82. #ifdef AO_HAVE_fetch_and_add
  83. # define fetch_and_add(addr, val) AO_fetch_and_add(addr, val)
  84. #else
  85. /* Fake it. This is really quite unacceptable for timing */
  86. /* purposes. But as a correctness test, it should be OK. */
  87. AO_INLINE AO_t fetch_and_add(volatile AO_t * addr, AO_t val)
  88. {
  89. AO_t result = AO_load(addr);
  90. AO_store(addr, result + val);
  91. return result;
  92. }
  93. #endif
  94. void * run_one_test(void * arg)
  95. {
  96. list_element * t[MAX_NTHREADS + 1];
  97. list_element * aux;
  98. long index = (long)arg;
  99. int i;
  100. int j = 0;
  101. # ifdef VERBOSE
  102. printf("starting thread %d\n", index);
  103. # endif
  104. while (fetch_and_add(&ops_performed, index + 1) + index + 1 < LIMIT)
  105. {
  106. for (i = 0; i < index + 1; ++i)
  107. {
  108. t[i] = (list_element *)AO_stack_pop(&the_list);
  109. if (0 == t[i])
  110. {
  111. fprintf(stderr, "FAILED\n");
  112. abort();
  113. }
  114. }
  115. for (i = 0; i < index + 1; ++i)
  116. {
  117. AO_stack_push(&the_list, (AO_t *)t[i]);
  118. }
  119. j += (index + 1);
  120. }
  121. # ifdef VERBOSE
  122. printf("finished thread %d: %d total ops\n", index, j);
  123. # endif
  124. return 0;
  125. }
  126. #define N_EXPERIMENTS 1
  127. unsigned long times[MAX_NTHREADS + 1][N_EXPERIMENTS];
  128. int main(int argc, char **argv)
  129. {
  130. int nthreads;
  131. int max_nthreads;
  132. int exper_n;
  133. if (1 == argc)
  134. max_nthreads = 4;
  135. else if (2 == argc)
  136. {
  137. max_nthreads = atoi(argv[1]);
  138. if (max_nthreads < 1 || max_nthreads > MAX_NTHREADS)
  139. {
  140. fprintf(stderr, "Invalid max # of threads argument\n");
  141. exit(1);
  142. }
  143. }
  144. else
  145. {
  146. fprintf(stderr, "Usage: %s [max # of threads]\n");
  147. exit(1);
  148. }
  149. for (exper_n = 0; exper_n < N_EXPERIMENTS; ++ exper_n)
  150. for (nthreads = 1; nthreads <= max_nthreads; ++nthreads)
  151. {
  152. int i;
  153. pthread_t thread[MAX_NTHREADS];
  154. int list_length = nthreads*(nthreads+1)/2;
  155. long long start_time;
  156. add_elements(list_length);
  157. # ifdef VERBOSE
  158. printf("Initial list (nthreads = %d):\n", nthreads);
  159. print_list();
  160. # endif
  161. ops_performed = 0;
  162. start_time = get_msecs();
  163. for (i = 1; i < nthreads; ++i) {
  164. int code;
  165. if ((code = pthread_create(thread+i, 0, run_one_test,
  166. (void *)(long)i)) != 0) {
  167. fprintf(stderr, "Thread creation failed %u\n", code);
  168. exit(1);
  169. }
  170. }
  171. /* We use the main thread to run one test. This allows gprof */
  172. /* profiling to work, for example. */
  173. run_one_test(0);
  174. for (i = 1; i < nthreads; ++i) {
  175. int code;
  176. if ((code = pthread_join(thread[i], 0)) != 0) {
  177. fprintf(stderr, "Thread join failed %u\n", code);
  178. }
  179. }
  180. times[nthreads][exper_n] = (unsigned long)(get_msecs() - start_time);
  181. # ifdef VERBOSE
  182. printf("%d %lu\n", nthreads,
  183. (unsigned long)(get_msecs() - start_time));
  184. printf("final list (should be reordered initial list):\n");
  185. print_list();
  186. # endif
  187. check_list(list_length);
  188. while ((list_element *)AO_stack_pop(&the_list));
  189. }
  190. # ifndef NO_TIMES
  191. for (nthreads = 1; nthreads <= max_nthreads; ++nthreads)
  192. {
  193. unsigned long sum = 0;
  194. printf("About %d pushes + %d pops in %d threads:",
  195. LIMIT, LIMIT, nthreads);
  196. for (exper_n = 0; exper_n < N_EXPERIMENTS; ++exper_n)
  197. {
  198. # if defined(VERBOSE)
  199. printf("[%lu] ", times[nthreads][exper_n]);
  200. # endif
  201. sum += times[nthreads][exper_n];
  202. }
  203. printf(" %lu msecs\n", (sum + N_EXPERIMENTS/2)/N_EXPERIMENTS);
  204. }
  205. # endif /* NO_TIMES */
  206. return 0;
  207. }