1 /* $NetBSD: t_atomic.c,v 1.5 2014/12/10 04:37:53 christos Exp $ */
2
3 /*
4 * Copyright (C) 2011, 2013 Internet Systems Consortium, Inc. ("ISC")
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /* Id: t_atomic.c,v 1.2 2011/01/11 23:47:12 tbox Exp */
20
21 #include <config.h>
22
23 #include <ctype.h>
24 #include <stdlib.h>
25
26 #include <isc/atomic.h>
27 #include <isc/mem.h>
28 #include <isc/util.h>
29 #include <isc/string.h>
30 #include <isc/print.h>
31 #include <isc/event.h>
32 #include <isc/task.h>
33
34 #include <tests/t_api.h>
35
36 char *progname;
37
38 #define CHECK(x) RUNTIME_CHECK(ISC_R_SUCCESS == (x))
39
40 isc_mem_t *mctx = NULL;
41 isc_taskmgr_t *task_manager = NULL;
42
43 #if defined(ISC_PLATFORM_HAVEXADD) || defined(ISC_PLATFORM_HAVEXADDQ)
44 static void
setup(void)45 setup(void) {
46 /* 1 */ CHECK(isc_mem_create(0, 0, &mctx));
47 /* 2 */ CHECK(isc_taskmgr_create(mctx, 32, 0, &task_manager));
48 }
49
50 static void
teardown(void)51 teardown(void) {
52 /* 2 */ isc_taskmgr_destroy(&task_manager);
53 /* 1 */ isc_mem_destroy(&mctx);
54 }
55 #endif
56
57 #define TASKS 32
58 #define ITERATIONS 10000
59 #define COUNTS_PER_ITERATION 1000
60 #define INCREMENT_64 (isc_int64_t)0x0000000010000000
61 #define EXPECTED_COUNT_32 (TASKS * ITERATIONS * COUNTS_PER_ITERATION)
62 #define EXPECTED_COUNT_64 (TASKS * ITERATIONS * COUNTS_PER_ITERATION * INCREMENT_64)
63
64 typedef struct {
65 isc_uint32_t iteration;
66 } counter_t;
67
68 counter_t counters[TASKS];
69
70 void do_xaddq(isc_task_t *task, isc_event_t *ev);
71
72 #if defined(ISC_PLATFORM_HAVEXADD)
73 isc_int32_t counter_32;
74
75 void do_xadd(isc_task_t *task, isc_event_t *ev);
76
77 void
do_xadd(isc_task_t * task,isc_event_t * ev)78 do_xadd(isc_task_t *task, isc_event_t *ev) {
79 counter_t *state = (counter_t *)ev->ev_arg;
80 int i;
81
82 for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
83 isc_atomic_xadd(&counter_32, 1);
84 }
85
86 state->iteration++;
87 if (state->iteration < ITERATIONS) {
88 isc_task_send(task, &ev);
89 } else {
90 isc_event_free(&ev);
91 }
92 }
93
94 static void
test_atomic_xadd()95 test_atomic_xadd() {
96 int test_result;
97 isc_task_t *tasks[TASKS];
98 isc_event_t *event;
99 int i;
100
101 t_assert("test_atomic_xadd", 1, T_REQUIRED, "%s",
102 "ensure that isc_atomic_xadd() works.");
103
104 setup();
105
106 memset(counters, 0, sizeof(counters));
107 counter_32 = 0;
108
109 /*
110 * Create our tasks, and allocate an event to get the counters going.
111 */
112 for (i = 0 ; i < TASKS ; i++) {
113 tasks[i] = NULL;
114 CHECK(isc_task_create(task_manager, 0, &tasks[i]));
115 event = isc_event_allocate(mctx, NULL, 1000, do_xadd,
116 &counters[i], sizeof(struct isc_event));
117 isc_task_sendanddetach(&tasks[i], &event);
118 }
119
120 teardown();
121
122 test_result = T_PASS;
123 t_info("32-bit counter %d, expected %d\n", counter_32, EXPECTED_COUNT_32);
124 if (counter_32 != EXPECTED_COUNT_32)
125 test_result = T_FAIL;
126 t_result(test_result);
127
128 counter_32 = 0;
129 }
130 #endif
131
132 #if defined(ISC_PLATFORM_HAVEXADDQ)
133 isc_int64_t counter_64;
134
135 void do_xaddq(isc_task_t *task, isc_event_t *ev);
136
137 void
do_xaddq(isc_task_t * task,isc_event_t * ev)138 do_xaddq(isc_task_t *task, isc_event_t *ev) {
139 counter_t *state = (counter_t *)ev->ev_arg;
140 int i;
141
142 for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
143 isc_atomic_xaddq(&counter_64, INCREMENT_64);
144 }
145
146 state->iteration++;
147 if (state->iteration < ITERATIONS) {
148 isc_task_send(task, &ev);
149 } else {
150 isc_event_free(&ev);
151 }
152 }
153
154 static void
test_atomic_xaddq()155 test_atomic_xaddq() {
156 int test_result;
157 isc_task_t *tasks[TASKS];
158 isc_event_t *event;
159 int i;
160
161 t_assert("test_atomic_xaddq", 1, T_REQUIRED, "%s",
162 "ensure that isc_atomic_xaddq() works.");
163
164 setup();
165
166 memset(counters, 0, sizeof(counters));
167 counter_64 = 0;
168
169 /*
170 * Create our tasks, and allocate an event to get the counters going.
171 */
172 for (i = 0 ; i < TASKS ; i++) {
173 tasks[i] = NULL;
174 CHECK(isc_task_create(task_manager, 0, &tasks[i]));
175 event = isc_event_allocate(mctx, NULL, 1000, do_xaddq,
176 &counters[i], sizeof(struct isc_event));
177 isc_task_sendanddetach(&tasks[i], &event);
178 }
179
180 teardown();
181
182 test_result = T_PASS;
183 t_info("64-bit counter %"ISC_PRINT_QUADFORMAT"d, expected %"ISC_PRINT_QUADFORMAT"d\n",
184 counter_64, EXPECTED_COUNT_64);
185 if (counter_64 != EXPECTED_COUNT_64)
186 test_result = T_FAIL;
187 t_result(test_result);
188
189 counter_64 = 0;
190 }
191 #endif
192
193
194 testspec_t T_testlist[] = {
195 #if defined(ISC_PLATFORM_HAVEXADD)
196 { (PFV) test_atomic_xadd, "test_atomic_xadd" },
197 #endif
198 #if defined(ISC_PLATFORM_HAVEXADDQ)
199 { (PFV) test_atomic_xaddq, "test_atomic_xaddq" },
200 #endif
201 { (PFV) 0, NULL }
202 };
203
204 #ifdef WIN32
205 int
main(int argc,char ** argv)206 main(int argc, char **argv) {
207 t_settests(T_testlist);
208 return (t_main(argc, argv));
209 }
210 #endif
211