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)
22
#include "atomic_ops.h"
23
#include "atomic_ops_stack.h"
24
#define MAX_NTHREADS 100
29
/* Need 64-bit long long support */
36
return (long long)tv.tv_sec * 1000 + tv.tv_usec/1000;
39
# define get_msecs() 0
47
AO_stack_t the_list = AO_STACK_INITIALIZER;
49
void add_elements(int n)
54
le = malloc(sizeof(list_element));
56
AO_stack_push(&the_list, (AO_t *)le);
63
for (p = (list_element *)AO_REAL_HEAD_PTR(the_list);
65
p = (list_element *)AO_REAL_NEXT_PTR(p -> next))
66
printf("%d\n", p -> data);
69
static char marks[MAX_NTHREADS * MAX_NTHREADS];
71
void check_list(int n)
76
for (i = 1; i <= n; ++i) marks[i] = 0;
77
for (p = (list_element *)AO_REAL_HEAD_PTR(the_list);
79
p = (list_element *)AO_REAL_NEXT_PTR(p -> next))
81
if (p -> data > n || p -> data <= 0)
82
fprintf(stderr, "Found erroneous list element %d\n", p -> data);
83
if (marks[p -> data] != 0)
84
fprintf(stderr, "Found duplicate list element %d\n", p -> data);
87
for (i = 1; i <= n; ++i)
89
fprintf(stderr, "Missing list element %d\n", i);
92
volatile AO_t ops_performed = 0;
95
/* Total number of push/pop ops in all threads per test. */
97
#ifdef AO_HAVE_fetch_and_add
98
# define fetch_and_add(addr, val) AO_fetch_and_add(addr, val)
100
/* Fake it. This is really quite unacceptable for timing */
101
/* purposes. But as a correctness test, it should be OK. */
102
AO_INLINE AO_t fetch_and_add(volatile AO_t * addr, AO_t val)
104
AO_t result = AO_load(addr);
105
AO_store(addr, result + val);
110
void * run_one_test(void * arg)
112
list_element * t[MAX_NTHREADS + 1];
114
long index = (long)arg;
119
printf("starting thread %d\n", index);
121
while (fetch_and_add(&ops_performed, index + 1) + index + 1 < LIMIT)
123
for (i = 0; i < index + 1; ++i)
125
t[i] = (list_element *)AO_stack_pop(&the_list);
128
fprintf(stderr, "FAILED\n");
132
for (i = 0; i < index + 1; ++i)
134
AO_stack_push(&the_list, (AO_t *)t[i]);
139
printf("finished thread %d: %d total ops\n", index, j);
144
#define N_EXPERIMENTS 1
146
unsigned long times[MAX_NTHREADS + 1][N_EXPERIMENTS];
148
int main(int argc, char **argv)
158
max_nthreads = atoi(argv[1]);
159
if (max_nthreads < 1 || max_nthreads > MAX_NTHREADS)
161
fprintf(stderr, "Invalid max # of threads argument\n");
167
fprintf(stderr, "Usage: %s [max # of threads]\n", argv[0]);
170
for (exper_n = 0; exper_n < N_EXPERIMENTS; ++ exper_n)
171
for (nthreads = 1; nthreads <= max_nthreads; ++nthreads)
174
pthread_t thread[MAX_NTHREADS];
175
int list_length = nthreads*(nthreads+1)/2;
176
long long start_time;
178
add_elements(list_length);
180
printf("Initial list (nthreads = %d):\n", nthreads);
184
start_time = get_msecs();
185
for (i = 1; i < nthreads; ++i) {
188
if ((code = pthread_create(thread+i, 0, run_one_test,
189
(void *)(long)i)) != 0) {
190
fprintf(stderr, "Thread creation failed %u\n", code);
194
/* We use the main thread to run one test. This allows gprof */
195
/* profiling to work, for example. */
197
for (i = 1; i < nthreads; ++i) {
199
if ((code = pthread_join(thread[i], 0)) != 0) {
200
fprintf(stderr, "Thread join failed %u\n", code);
203
times[nthreads][exper_n] = (unsigned long)(get_msecs() - start_time);
205
printf("%d %lu\n", nthreads,
206
(unsigned long)(get_msecs() - start_time));
207
printf("final list (should be reordered initial list):\n");
210
check_list(list_length);
211
while ((list_element *)AO_stack_pop(&the_list));
214
for (nthreads = 1; nthreads <= max_nthreads; ++nthreads)
216
unsigned long sum = 0;
218
printf("About %d pushes + %d pops in %d threads:",
219
LIMIT, LIMIT, nthreads);
220
for (exper_n = 0; exper_n < N_EXPERIMENTS; ++exper_n)
222
# if defined(VERBOSE)
223
printf("[%lu] ", times[nthreads][exper_n]);
225
sum += times[nthreads][exper_n];
227
printf(" %lu msecs\n", (sum + N_EXPERIMENTS/2)/N_EXPERIMENTS);
229
# endif /* NO_TIMES */