2 * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
3 * Original Author: Hans Boehm
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.
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.
15 #if defined(HAVE_CONFIG_H)
19 #if defined(__vxworks) || defined(_MSC_VER) || defined(_WIN32_WINCE) \
20 || (defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__))
22 /* Skip the test if no pthreads. */
33 #include "atomic_ops.h"
34 #include "atomic_ops_stack.h"
37 # define MAX_NTHREADS 100
42 # include <sys/time.h>
43 /* Need 64-bit long long support */
44 long long get_msecs(void)
49 return (long long)tv.tv_sec * 1000 + tv.tv_usec/1000;
52 # define get_msecs() 0
60 AO_stack_t the_list = AO_STACK_INITIALIZER;
62 void add_elements(int n)
67 le = malloc(sizeof(list_element));
70 fprintf(stderr, "Out of memory\n");
74 AO_stack_push(&the_list, (AO_t *)le);
81 for (p = (list_element *)AO_REAL_HEAD_PTR(the_list);
83 p = (list_element *)AO_REAL_NEXT_PTR(p -> next))
84 printf("%d\n", p -> data);
87 static char marks[MAX_NTHREADS * MAX_NTHREADS];
89 void check_list(int n)
94 for (i = 1; i <= n; ++i) marks[i] = 0;
95 for (p = (list_element *)AO_REAL_HEAD_PTR(the_list);
97 p = (list_element *)AO_REAL_NEXT_PTR(p -> next))
99 if (p -> data > n || p -> data <= 0)
100 fprintf(stderr, "Found erroneous list element %d\n", p -> data);
101 if (marks[p -> data] != 0)
102 fprintf(stderr, "Found duplicate list element %d\n", p -> data);
103 marks[p -> data] = 1;
105 for (i = 1; i <= n; ++i)
107 fprintf(stderr, "Missing list element %d\n", i);
110 volatile AO_t ops_performed = 0;
112 #define LIMIT 1000000
113 /* Total number of push/pop ops in all threads per test. */
115 #ifdef AO_HAVE_fetch_and_add
116 # define fetch_and_add(addr, val) AO_fetch_and_add(addr, val)
118 /* Fake it. This is really quite unacceptable for timing */
119 /* purposes. But as a correctness test, it should be OK. */
120 AO_INLINE AO_t fetch_and_add(volatile AO_t * addr, AO_t val)
122 AO_t result = AO_load(addr);
123 AO_store(addr, result + val);
128 void * run_one_test(void * arg)
130 list_element * t[MAX_NTHREADS + 1];
131 long index = (long)arg;
136 printf("starting thread %d\n", index);
138 while (fetch_and_add(&ops_performed, index + 1) + index + 1 < LIMIT)
140 for (i = 0; i < index + 1; ++i)
142 t[i] = (list_element *)AO_stack_pop(&the_list);
145 fprintf(stderr, "FAILED\n");
149 for (i = 0; i < index + 1; ++i)
151 AO_stack_push(&the_list, (AO_t *)t[i]);
156 printf("finished thread %d: %d total ops\n", index, j);
161 #ifndef N_EXPERIMENTS
162 # define N_EXPERIMENTS 1
165 unsigned long times[MAX_NTHREADS + 1][N_EXPERIMENTS];
167 int main(int argc, char **argv)
177 max_nthreads = atoi(argv[1]);
178 if (max_nthreads < 1 || max_nthreads > MAX_NTHREADS)
180 fprintf(stderr, "Invalid max # of threads argument\n");
186 fprintf(stderr, "Usage: %s [max # of threads]\n", argv[0]);
189 for (exper_n = 0; exper_n < N_EXPERIMENTS; ++ exper_n)
190 for (nthreads = 1; nthreads <= max_nthreads; ++nthreads)
193 pthread_t thread[MAX_NTHREADS];
194 int list_length = nthreads*(nthreads+1)/2;
195 long long start_time;
198 add_elements(list_length);
200 printf("Initial list (nthreads = %d):\n", nthreads);
204 start_time = get_msecs();
205 for (i = 1; i < nthreads; ++i) {
208 if ((code = pthread_create(thread+i, 0, run_one_test,
209 (void *)(long)i)) != 0) {
210 fprintf(stderr, "Thread creation failed %u\n", code);
214 /* We use the main thread to run one test. This allows gprof */
215 /* profiling to work, for example. */
217 for (i = 1; i < nthreads; ++i) {
219 if ((code = pthread_join(thread[i], 0)) != 0) {
220 fprintf(stderr, "Thread join failed %u\n", code);
223 times[nthreads][exper_n] = (unsigned long)(get_msecs() - start_time);
225 printf("%d %lu\n", nthreads,
226 (unsigned long)(get_msecs() - start_time));
227 printf("final list (should be reordered initial list):\n");
230 check_list(list_length);
231 while ((le = (list_element *)AO_stack_pop(&the_list)) != 0)
235 for (nthreads = 1; nthreads <= max_nthreads; ++nthreads)
237 unsigned long sum = 0;
239 printf("About %d pushes + %d pops in %d threads:",
240 LIMIT, LIMIT, nthreads);
241 for (exper_n = 0; exper_n < N_EXPERIMENTS; ++exper_n)
243 # if defined(VERBOSE)
244 printf("[%lu] ", times[nthreads][exper_n]);
246 sum += times[nthreads][exper_n];
248 printf(" %lu msecs\n", (sum + N_EXPERIMENTS/2)/N_EXPERIMENTS);
250 # endif /* !NO_TIMES */
254 #endif /* !_MSC_VER */