1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3  * Copyright (c) 2014      Los Alamos National Security, LLC. All rights
4  *                         reserved.
5  * $COPYRIGHT$
6  *
7  * Additional copyrights may follow
8  *
9  * $HEADER$
10  */
11 
12 #include "opal_config.h"
13 #include <assert.h>
14 
15 #include "support.h"
16 #include "opal/class/opal_lifo.h"
17 #include "opal/runtime/opal.h"
18 #include "opal/constants.h"
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stddef.h>
23 
24 #include <sys/time.h>
25 
26 #define OPAL_LIFO_TEST_THREAD_COUNT 8
27 #define ITERATIONS 1000000
28 #define ITEM_COUNT 100
29 
30 #if !defined(timersub)
31 #define timersub(a, b, r) \
32     do {                  \
33         (r)->tv_sec = (a)->tv_sec - (b)->tv_sec;        \
34         if ((a)->tv_usec < (b)->tv_usec) {              \
35             (r)->tv_sec--;                              \
36             (a)->tv_usec += 1000000;                    \
37         }                                               \
38         (r)->tv_usec = (a)->tv_usec - (b)->tv_usec;     \
39     } while (0)
40 #endif
41 
thread_test(void * arg)42 static void *thread_test (void *arg) {
43     opal_lifo_t *lifo = (opal_lifo_t *) arg;
44     opal_list_item_t *item;
45     struct timeval start, stop, total;
46     double timing;
47 
48     gettimeofday (&start, NULL);
49     for (int i = 0 ; i < ITERATIONS ; ++i) {
50         item = opal_lifo_pop_atomic (lifo);
51         if (NULL != item) {
52             (void) opal_lifo_push_atomic (lifo, item);
53         }
54     }
55     gettimeofday (&stop, NULL);
56 
57     timersub(&stop, &start, &total);
58 
59     timing = ((double) total.tv_sec + (double) total.tv_usec * 1e-6) / (double) ITERATIONS;
60 
61     printf ("Atomics thread finished. Time: %d s %d us %d nsec/poppush\n", (int) total.tv_sec,
62             (int)total.tv_usec, (int)(timing / 1e-9));
63 
64     return NULL;
65 }
66 
check_lifo_consistency(opal_lifo_t * lifo,int expected_count)67 static bool check_lifo_consistency (opal_lifo_t *lifo, int expected_count)
68 {
69     opal_list_item_t *item;
70     int count;
71 
72     for (count = 0, item = lifo->opal_lifo_head.data.item ; item != &lifo->opal_lifo_ghost ;
73          item = opal_list_get_next(item), count++);
74 
75     return count == expected_count;
76 }
77 
main(int argc,char * argv[])78 int main (int argc, char *argv[]) {
79     pthread_t threads[OPAL_LIFO_TEST_THREAD_COUNT];
80     opal_list_item_t *item, *prev, *item2;
81     struct timeval start, stop, total;
82     opal_lifo_t lifo;
83     bool success;
84     double timing;
85     int rc;
86 
87     rc = opal_init_util (&argc, &argv);
88     test_verify_int(OPAL_SUCCESS, rc);
89     if (OPAL_SUCCESS != rc) {
90         test_finalize();
91         exit (1);
92     }
93 
94     test_init("opal_lifo_t");
95 
96     OBJ_CONSTRUCT(&lifo, opal_lifo_t);
97 
98     item = OBJ_NEW(opal_list_item_t);
99     prev = opal_lifo_push_st (&lifo, item);
100     if (&lifo.opal_lifo_ghost == prev) {
101         test_success ();
102     } else {
103         test_failure (" opal_lifo_push_st on empty lifo");
104     }
105 
106     item2 = opal_lifo_pop_st (&lifo);
107     if (item == item2) {
108         test_success ();
109     } else {
110         test_failure (" opal_lifo_pop_st");
111     }
112 
113     OBJ_RELEASE(item);
114 
115     for (int i = 0 ; i < ITEM_COUNT ; ++i) {
116         item = OBJ_NEW(opal_list_item_t);
117         item->item_free = 0;
118         opal_lifo_push_st (&lifo, item);
119     }
120 
121     if (check_lifo_consistency (&lifo, ITEM_COUNT)) {
122         test_success ();
123     } else {
124         test_failure (" opal_lifo_push_st(multiple items)");
125     }
126 
127     gettimeofday (&start, NULL);
128     for (int i = 0 ; i < ITERATIONS ; ++i) {
129         item = opal_lifo_pop_st (&lifo);
130         (void) opal_lifo_push_st (&lifo, item);
131     }
132     gettimeofday (&stop, NULL);
133 
134     timersub(&stop, &start, &total);
135 
136     timing = ((double) total.tv_sec + (double) total.tv_usec * 1e-6) / (double) ITERATIONS;
137 
138     if (check_lifo_consistency (&lifo, ITEM_COUNT)) {
139         test_success ();
140     } else {
141         test_failure (" lifo push/pop");
142     }
143 
144     printf ("Single thread test. Time: %d s %d us %d nsec/poppush\n", (int) total.tv_sec,
145             (int)total.tv_usec, (int)(timing / 1e-9));
146 
147     thread_test (&lifo);
148 
149     if (check_lifo_consistency (&lifo, ITEM_COUNT)) {
150         test_success ();
151     } else {
152         test_failure (" lifo push/pop single-threaded with atomics");
153     }
154 
155     gettimeofday (&start, NULL);
156     for (int i = 0 ; i < OPAL_LIFO_TEST_THREAD_COUNT ; ++i) {
157         pthread_create (threads + i, NULL, thread_test, &lifo);
158     }
159 
160     for (int i = 0 ; i < OPAL_LIFO_TEST_THREAD_COUNT ; ++i) {
161         void *ret;
162 
163         pthread_join (threads[i], &ret);
164     }
165     gettimeofday (&stop, NULL);
166 
167     timersub(&stop, &start, &total);
168 
169     timing = ((double) total.tv_sec + (double) total.tv_usec * 1e-6) / (double) (ITERATIONS * OPAL_LIFO_TEST_THREAD_COUNT);
170 
171     if (check_lifo_consistency (&lifo, ITEM_COUNT)) {
172         test_success ();
173     } else {
174         test_failure (" lifo push/pop multi-threaded with atomics");
175     }
176 
177     printf ("All threads finished. Thread count: %d Time: %d s %d us %d nsec/poppush\n",
178             OPAL_LIFO_TEST_THREAD_COUNT, (int) total.tv_sec, (int)total.tv_usec, (int)(timing / 1e-9));
179 
180     success = true;
181     for (int i = 0 ; i < ITEM_COUNT ; ++i) {
182         item = opal_lifo_pop_st (&lifo);
183         if (NULL == item) {
184             success = false;
185             break;
186         }
187         OBJ_RELEASE(item);
188     }
189 
190     if (success) {
191         test_success ();
192     } else {
193         test_failure (" list pop all items");
194     }
195 
196     OBJ_DESTRUCT(&lifo);
197 
198     opal_finalize_util ();
199 
200     return test_finalize ();
201 }
202