• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ivmai / libatomic_ops / 601

23 May 2023 09:39AM UTC coverage: 96.391% (-0.04%) from 96.426%
601

push

travis-ci-com

ivmai
DRAFT 210 - test all on dist jammy

2724 of 2826 relevant lines covered (96.39%)

1001868.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.57
/tests/test_stack.c
1
/*
2
 * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 2 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License along
15
 * with this program; if not, write to the Free Software Foundation, Inc.,
16
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
 */
18

19
#if defined(HAVE_CONFIG_H)
20
# include "config.h"
21
#endif
22

23
#include <stdio.h>
24

25
#if defined(__vxworks)
26

27
  int main(void)
28
  {
29
    printf("test skipped\n");
30
    return 0;
31
  }
32

33
#else
34

35
#if ((defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)) \
36
     || defined(_MSC_VER) || defined(_WIN32_WINCE)) \
37
    && !defined(AO_USE_WIN32_PTHREADS)
38
# define USE_WINTHREADS
39
#endif
40

41
#ifdef USE_WINTHREADS
42
# include <windows.h>
43
#else
44
# include <pthread.h>
45
#endif
46

47
#include <assert.h>
48
#include <stdlib.h>
49

50
#include "atomic_ops_stack.h" /* includes atomic_ops.h as well */
51

52
#if (defined(_WIN32_WCE) || defined(__MINGW32CE__)) && !defined(AO_HAVE_abort)
53
# define abort() _exit(-1) /* there is no abort() in WinCE */
54
#endif
55

56
#ifndef MAX_NTHREADS
57
# define MAX_NTHREADS 100
58
#endif
59

60
#ifndef DEFAULT_NTHREADS
61
# define DEFAULT_NTHREADS 16 /* must be <= MAX_NTHREADS */
62
#endif
63

64
#ifdef NO_TIMES
65
# define get_msecs() 0
66
#elif (defined(USE_WINTHREADS) || defined(AO_USE_WIN32_PTHREADS)) \
67
      && !defined(CPPCHECK)
68
# include <sys/timeb.h>
69
  unsigned long get_msecs(void)
70
  {
71
    struct timeb tb;
72

73
    ftime(&tb);
74
    return (unsigned long)tb.time * 1000 + tb.millitm;
75
  }
76
#else /* Unix */
77
# include <time.h>
78
# include <sys/time.h>
79
  unsigned long get_msecs(void)
32✔
80
  {
81
    struct timeval tv;
82

83
    gettimeofday(&tv, 0);
32✔
84
    return (unsigned long)tv.tv_sec * 1000 + tv.tv_usec/1000;
32✔
85
  }
86
#endif /* !NO_TIMES */
87

88
struct le {
89
  AO_t next; /* must be the first field */
90
  int data;
91
};
92

93
typedef union le_u {
94
  AO_t next;
95
  struct le e;
96
} list_element;
97

98
#if defined(CPPCHECK)
99
  AO_stack_t the_list; /* to test AO_stack_init() */
100
#else
101
  AO_stack_t the_list = AO_STACK_INITIALIZER;
102
#endif
103

104
/* Add elements from 1 to n to the list (1 is pushed first).    */
105
/* This is called from a single thread only.                    */
106
void add_elements(int n)
832✔
107
{
108
  list_element * le;
109
  if (n == 0) return;
832✔
110
  add_elements(n-1);
816✔
111
  le = (list_element *)malloc(sizeof(list_element));
816✔
112
  if (le == 0)
816✔
113
    {
114
      fprintf(stderr, "Out of memory\n");
×
115
      exit(2);
×
116
    }
117
# if defined(CPPCHECK)
118
    le->e.next = 0; /* mark field as used */
119
# endif
120
  le->e.data = n;
816✔
121
  AO_stack_push(&the_list, &le->next);
816✔
122
}
123

124
#ifdef VERBOSE_STACK
125
void print_list(void)
32✔
126
{
127
  AO_t *p;
128

129
  for (p = AO_REAL_HEAD_PTR(the_list);
32✔
130
       p != 0; p = AO_REAL_NEXT_PTR(*p))
1,664✔
131
    printf("%d\n", ((list_element*)p)->e.data);
1,632✔
132
}
32✔
133
#endif /* VERBOSE_STACK */
134

135
/* Check that the list contains only values from 1 to n, in any order,  */
136
/* w/o duplications.  Executed when the list mutation is finished.      */
137
void check_list(int n)
16✔
138
{
139
  AO_t *p;
140
  int i;
141
  int err_cnt = 0;
16✔
142
  char *marks = (char*)calloc(n + 1, 1);
16✔
143

144
  if (0 == marks)
16✔
145
    {
146
      fprintf(stderr, "Out of memory (marks)\n");
×
147
      exit(2);
×
148
    }
149

150
  for (p = AO_REAL_HEAD_PTR(the_list);
16✔
151
       p != 0; p = AO_REAL_NEXT_PTR(*p))
832✔
152
    {
153
      i = ((list_element*)p)->e.data;
816✔
154
      if (i > n || i <= 0)
816✔
155
        {
156
          fprintf(stderr, "Found erroneous list element %d\n", i);
×
157
          err_cnt++;
×
158
        }
159
      else if (marks[i] != 0)
816✔
160
        {
161
          fprintf(stderr, "Found duplicate list element %d\n", i);
×
162
          abort();
×
163
        }
164
      else marks[i] = 1;
816✔
165
    }
166

167
  for (i = 1; i <= n; ++i)
832✔
168
    if (marks[i] != 1)
816✔
169
      {
170
        fprintf(stderr, "Missing list element %d\n", i);
×
171
        err_cnt++;
×
172
      }
173

174
  free(marks);
16✔
175
  if (err_cnt > 0) abort();
16✔
176
}
16✔
177

178
volatile AO_t ops_performed = 0;
179

180
#ifndef LIMIT
181
        /* Total number of push/pop ops in all threads per test.    */
182
# ifdef AO_USE_PTHREAD_DEFS
183
#   define LIMIT 20000
184
# else
185
#   define LIMIT 1000000
186
# endif
187
#endif
188

189
#ifdef AO_HAVE_fetch_and_add
190
# define fetch_then_add(addr, val) AO_fetch_and_add(addr, val)
191
#else
192
  /* OK to perform it in two atomic steps, but really quite     */
193
  /* unacceptable for timing purposes.                          */
194
  AO_INLINE AO_t fetch_then_add(volatile AO_t * addr, AO_t val)
195
  {
196
    AO_t result = AO_load(addr);
197
    AO_store(addr, result + val);
198
    return result;
199
  }
200
#endif
201

202
#ifdef USE_WINTHREADS
203
  DWORD WINAPI run_one_test(LPVOID arg)
204
#else
205
  void * run_one_test(void * arg)
136✔
206
#endif
207
{
208
  AO_t *t[MAX_NTHREADS + 1];
209
  unsigned index = (unsigned)(size_t)arg;
136✔
210
  unsigned i;
211
# ifdef VERBOSE_STACK
212
    unsigned j = 0;
136✔
213

214
    printf("starting thread %u\n", index);
136✔
215
# endif
216
  assert(index <= MAX_NTHREADS);
217
  while (fetch_then_add(&ops_performed, index + 1) + index + 1 < LIMIT)
7,133,515✔
218
    {
219
      /* Pop index+1 elements (where index is the thread one), then     */
220
      /* push them back (in the same order of operations).              */
221
      /* Note that this is done in parallel by many threads.            */
222
      for (i = 0; i <= index; ++i)
23,060,375✔
223
        {
224
          t[i] = AO_stack_pop(&the_list);
15,981,228✔
225
          if (0 == t[i])
15,694,336✔
226
            {
227
              /* This should not happen as at most n*(n+1)/2 elements   */
228
              /* could be popped off at a time.                         */
229
              fprintf(stderr, "Failed - nothing to pop\n");
×
230
              abort();
×
231
            }
232
        }
233
      for (i = 0; i <= index; ++i)
22,952,446✔
234
        {
235
          AO_stack_push(&the_list, t[i]);
15,819,067✔
236
        }
237
#     ifdef VERBOSE_STACK
238
        j += index + 1;
7,133,379✔
239
#     endif
240
    }
241
    /* Repeat until LIMIT push/pop operations are performed (by all     */
242
    /* the threads simultaneously).                                     */
243
# ifdef VERBOSE_STACK
244
    printf("finished thread %u: %u total ops\n", index, j);
×
245
# endif
246
  return 0;
136✔
247
}
248

249
#ifndef N_EXPERIMENTS
250
# define N_EXPERIMENTS 1
251
#endif
252

253
unsigned long times[MAX_NTHREADS + 1][N_EXPERIMENTS];
254

255
void run_one_experiment(int max_nthreads, int exper_n)
1✔
256
{
257
  int nthreads;
258

259
  assert(max_nthreads <= MAX_NTHREADS);
260
  assert(exper_n < N_EXPERIMENTS);
261
  for (nthreads = 1; nthreads <= max_nthreads; ++nthreads) {
17✔
262
    unsigned i;
263
#   ifdef USE_WINTHREADS
264
      DWORD thread_id;
265
      HANDLE thread[MAX_NTHREADS];
266
#   else
267
      pthread_t thread[MAX_NTHREADS];
268
#   endif
269
    int list_length = nthreads*(nthreads+1)/2;
16✔
270
    unsigned long start_time;
271
    AO_t *le;
272

273
#   ifdef VERBOSE_STACK
274
      printf("Before add_elements: exper_n=%d, nthreads=%d,"
16✔
275
             " max_nthreads=%d, list_length=%d\n",
276
             exper_n, nthreads, max_nthreads, list_length);
277
#   endif
278
    /* Create a list with n*(n+1)/2 elements.   */
279
    assert(0 == AO_REAL_HEAD_PTR(the_list));
280
    add_elements(list_length);
16✔
281
#   ifdef VERBOSE_STACK
282
      printf("Initial list (nthreads = %d):\n", nthreads);
16✔
283
      print_list();
16✔
284
#   endif
285
    ops_performed = 0;
16✔
286
    start_time = get_msecs();
16✔
287
    /* Start n-1 threads to run_one_test in parallel.   */
288
    for (i = 1; (int)i < nthreads; ++i) {
136✔
289
      int code;
290

291
#     ifdef USE_WINTHREADS
292
        thread[i] = CreateThread(NULL, 0, run_one_test, (LPVOID)(size_t)i,
293
                                 0, &thread_id);
294
        code = thread[i] != NULL ? 0 : (int)GetLastError();
295
#     else
296
        code = pthread_create(&thread[i], 0, run_one_test,
120✔
297
                              (void *)(size_t)i);
120✔
298
#     endif
299
      if (code != 0) {
120✔
300
        fprintf(stderr, "Thread creation failed %u\n", (unsigned)code);
×
301
        exit(3);
×
302
      }
303
    }
304
    /* We use the main thread to run one test.  This allows     */
305
    /* gprof profiling to work, for example.                    */
306
    run_one_test(0);
16✔
307
    /* Wait for all the threads to complete.    */
308
    for (i = 1; (int)i < nthreads; ++i) {
136✔
309
      int code;
310

311
#     ifdef USE_WINTHREADS
312
        code = WaitForSingleObject(thread[i], INFINITE) == WAIT_OBJECT_0 ?
313
                    0 : (int)GetLastError();
314
#     else
315
        code = pthread_join(thread[i], 0);
120✔
316
#     endif
317
      if (code != 0) {
120✔
318
        fprintf(stderr, "Thread join failed %u\n", (unsigned)code);
×
319
        abort();
×
320
      }
321
    }
322
    times[nthreads][exper_n] = get_msecs() - start_time;
16✔
323
#   ifdef VERBOSE_STACK
324
      printf("nthreads=%d, time_ms=%lu\n",
16✔
325
             nthreads, times[nthreads][exper_n]);
326
      printf("final list (should be reordered initial list):\n");
16✔
327
      print_list();
16✔
328
#   endif
329
    /* Ensure that no element is lost or duplicated.    */
330
    check_list(list_length);
16✔
331
    /* And, free the entire list.   */
332
    while ((le = AO_stack_pop(&the_list)) != 0)
832✔
333
      free(le);
816✔
334
    /* Retry with larger n values.      */
335
  }
336
}
1✔
337

338
void run_all_experiments(int max_nthreads)
1✔
339
{
340
  int exper_n;
341

342
  for (exper_n = 0; exper_n < N_EXPERIMENTS; ++exper_n)
2✔
343
    run_one_experiment(max_nthreads, exper_n);
1✔
344
}
1✔
345

346
/* Output the performance statistic.    */
347
void output_stat(int max_nthreads)
1✔
348
{
349
  int nthreads;
350

351
  assert(max_nthreads <= MAX_NTHREADS);
352
  for (nthreads = 1; nthreads <= max_nthreads; ++nthreads) {
17✔
353
#   ifndef NO_TIMES
354
      int exper_n;
355
      unsigned long sum = 0;
16✔
356
#   endif
357

358
    printf("About %d pushes + %d pops in %d threads:",
16✔
359
           LIMIT, LIMIT, nthreads);
360
#   ifndef NO_TIMES
361
      for (exper_n = 0; exper_n < N_EXPERIMENTS; ++exper_n) {
32✔
362
#       ifdef VERBOSE_STACK
363
          printf(" [%lums]", times[nthreads][exper_n]);
16✔
364
#       endif
365
        sum += times[nthreads][exper_n];
16✔
366
      }
367
      printf(" %lu msecs\n", (sum + N_EXPERIMENTS/2)/N_EXPERIMENTS);
16✔
368
#   else
369
      printf(" completed\n");
370
#   endif
371
  }
372
}
1✔
373

374
int main(int argc, char **argv)
1✔
375
{
376
  int max_nthreads = DEFAULT_NTHREADS;
1✔
377

378
  if (2 == argc)
1✔
379
    {
380
      max_nthreads = atoi(argv[1]);
×
381
      if (max_nthreads < 1 || max_nthreads > MAX_NTHREADS)
×
382
        {
383
          fprintf(stderr, "Invalid max # of threads argument\n");
×
384
          exit(1);
×
385
        }
386
    }
387
  else if (argc > 2)
1✔
388
    {
389
      fprintf(stderr, "Usage: %s [max # of threads]\n", argv[0]);
×
390
      exit(1);
×
391
    }
392
  if (!AO_stack_is_lock_free())
1✔
393
    printf("Use almost-lock-free implementation\n");
×
394
# if defined(CPPCHECK)
395
    AO_stack_init(&the_list);
396
# endif
397
  run_all_experiments(max_nthreads);
1✔
398
  output_stat(max_nthreads);
1✔
399
  return 0;
1✔
400
}
401

402
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc