/* * Copyright (C) 2011, 2013, 2015, 2016 Internet Systems Consortium, Inc. ("ISC") * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include char *progname; #define CHECK(x) RUNTIME_CHECK(ISC_R_SUCCESS == (x)) isc_mem_t *mctx = NULL; isc_taskmgr_t *task_manager = NULL; #if defined(ISC_PLATFORM_HAVEXADD) || defined(ISC_PLATFORM_HAVEXADDQ) || \ defined(ISC_PLATFORM_HAVEATOMICSTORE) || \ defined(ISC_PLATFORM_HAVEATOMICSTOREQ) static void setup(void) { /* 1 */ CHECK(isc_mem_create(0, 0, &mctx)); /* 2 */ CHECK(isc_taskmgr_create(mctx, 32, 0, &task_manager)); } static void teardown(void) { /* 2 */ isc_taskmgr_destroy(&task_manager); /* 1 */ isc_mem_destroy(&mctx); } #endif #define TASKS 32 #define ITERATIONS 10000 #define COUNTS_PER_ITERATION 1000 #define INCREMENT_64 (isc_int64_t)0x0000000010000000 #define EXPECTED_COUNT_32 (TASKS * ITERATIONS * COUNTS_PER_ITERATION) #define EXPECTED_COUNT_64 (TASKS * ITERATIONS * COUNTS_PER_ITERATION * INCREMENT_64) typedef struct { isc_uint32_t iteration; } counter_t; counter_t counters[TASKS]; #if defined(ISC_PLATFORM_HAVEXADD) static isc_int32_t counter_32; static void do_xadd(isc_task_t *task, isc_event_t *ev) { counter_t *state = (counter_t *)ev->ev_arg; int i; for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) { isc_atomic_xadd(&counter_32, 1); } state->iteration++; if (state->iteration < ITERATIONS) { isc_task_send(task, &ev); } else { isc_event_free(&ev); } } static void test_atomic_xadd() { int test_result; isc_task_t *tasks[TASKS]; isc_event_t *event; int i; t_assert("test_atomic_xadd", 1, T_REQUIRED, "%s", "ensure that isc_atomic_xadd() works."); setup(); memset(counters, 0, sizeof(counters)); counter_32 = 0; /* * Create our tasks, and allocate an event to get the counters going. */ for (i = 0 ; i < TASKS ; i++) { tasks[i] = NULL; CHECK(isc_task_create(task_manager, 0, &tasks[i])); event = isc_event_allocate(mctx, NULL, 1000, do_xadd, &counters[i], sizeof(struct isc_event)); isc_task_sendanddetach(&tasks[i], &event); } teardown(); test_result = T_PASS; t_info("32-bit counter %d, expected %d\n", counter_32, EXPECTED_COUNT_32); if (counter_32 != EXPECTED_COUNT_32) test_result = T_FAIL; t_result(test_result); counter_32 = 0; } #endif #if defined(ISC_PLATFORM_HAVEXADDQ) static isc_int64_t counter_64; static void do_xaddq(isc_task_t *task, isc_event_t *ev) { counter_t *state = (counter_t *)ev->ev_arg; int i; for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) { isc_atomic_xaddq(&counter_64, INCREMENT_64); } state->iteration++; if (state->iteration < ITERATIONS) { isc_task_send(task, &ev); } else { isc_event_free(&ev); } } static void test_atomic_xaddq() { int test_result; isc_task_t *tasks[TASKS]; isc_event_t *event; int i; t_assert("test_atomic_xaddq", 1, T_REQUIRED, "%s", "ensure that isc_atomic_xaddq() works."); setup(); memset(counters, 0, sizeof(counters)); counter_64 = 0; /* * Create our tasks, and allocate an event to get the counters going. */ for (i = 0 ; i < TASKS ; i++) { tasks[i] = NULL; CHECK(isc_task_create(task_manager, 0, &tasks[i])); event = isc_event_allocate(mctx, NULL, 1000, do_xaddq, &counters[i], sizeof(struct isc_event)); isc_task_sendanddetach(&tasks[i], &event); } teardown(); test_result = T_PASS; t_info("64-bit counter %"ISC_PRINT_QUADFORMAT"d, expected %"ISC_PRINT_QUADFORMAT"d\n", counter_64, EXPECTED_COUNT_64); if (counter_64 != EXPECTED_COUNT_64) test_result = T_FAIL; t_result(test_result); counter_64 = 0; } #endif #ifdef ISC_PLATFORM_HAVEATOMICSTORE static isc_int32_t store_32; static void do_store(isc_task_t *task, isc_event_t *ev) { counter_t *state = (counter_t *)ev->ev_arg; int i; isc_uint8_t r; isc_uint32_t val; r = random() % 256; val = (r << 24) | (r << 16) | (r << 8) | r; for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) { isc_atomic_store(&store_32, val); } state->iteration++; if (state->iteration < ITERATIONS) { isc_task_send(task, &ev); } else { isc_event_free(&ev); } } static void test_atomic_store() { int test_result; isc_task_t *tasks[TASKS]; isc_event_t *event; int i; isc_uint8_t r; isc_uint32_t val; t_assert("test_atomic_store", 1, T_REQUIRED, "%s", "ensure that isc_atomic_store() works."); setup(); memset(counters, 0, sizeof(counters)); store_32 = 0; /* * Create our tasks, and allocate an event to get the counters * going. */ for (i = 0 ; i < TASKS ; i++) { tasks[i] = NULL; CHECK(isc_task_create(task_manager, 0, &tasks[i])); event = isc_event_allocate(mctx, NULL, 1000, do_store, &counters[i], sizeof(struct isc_event)); isc_task_sendanddetach(&tasks[i], &event); } teardown(); test_result = T_PASS; r = store_32 & 0xff; val = (r << 24) | (r << 16) | (r << 8) | r; t_info("32-bit store 0x%x, expected 0x%x\n", (isc_uint32_t) store_32, val); if ((isc_uint32_t) store_32 != val) test_result = T_FAIL; t_result(test_result); store_32 = 0; } #endif #if defined(ISC_PLATFORM_HAVEATOMICSTOREQ) static isc_int64_t store_64; static void do_storeq(isc_task_t *task, isc_event_t *ev) { counter_t *state = (counter_t *)ev->ev_arg; int i; isc_uint8_t r; isc_uint64_t val; r = random() % 256; val = (((isc_uint64_t) r << 24) | ((isc_uint64_t) r << 16) | ((isc_uint64_t) r << 8) | (isc_uint64_t) r); val |= ((isc_uint64_t) val << 32); for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) { isc_atomic_storeq(&store_64, val); } state->iteration++; if (state->iteration < ITERATIONS) { isc_task_send(task, &ev); } else { isc_event_free(&ev); } } static void test_atomic_storeq() { int test_result; isc_task_t *tasks[TASKS]; isc_event_t *event; int i; isc_uint8_t r; isc_uint64_t val; t_assert("test_atomic_storeq", 1, T_REQUIRED, "%s", "ensure that isc_atomic_storeq() works."); setup(); memset(counters, 0, sizeof(counters)); store_64 = 0; /* * Create our tasks, and allocate an event to get the counters going. */ for (i = 0 ; i < TASKS ; i++) { tasks[i] = NULL; CHECK(isc_task_create(task_manager, 0, &tasks[i])); event = isc_event_allocate(mctx, NULL, 1000, do_storeq, &counters[i], sizeof(struct isc_event)); isc_task_sendanddetach(&tasks[i], &event); } teardown(); test_result = T_PASS; r = store_64 & 0xff; val = (((isc_uint64_t) r << 24) | ((isc_uint64_t) r << 16) | ((isc_uint64_t) r << 8) | (isc_uint64_t) r); val |= ((isc_uint64_t) val << 32); t_info("64-bit store 0x%"ISC_PRINT_QUADFORMAT"x, expected 0x%"ISC_PRINT_QUADFORMAT"x\n", (isc_uint64_t) store_64, val); if ((isc_uint64_t) store_64 != val) test_result = T_FAIL; t_result(test_result); store_64 = 0; } #endif /* ISC_PLATFORM_HAVEATOMICSTOREQ */ testspec_t T_testlist[] = { #if defined(ISC_PLATFORM_HAVEXADD) { (PFV) test_atomic_xadd, "test_atomic_xadd" }, #endif #if defined(ISC_PLATFORM_HAVEXADDQ) { (PFV) test_atomic_xaddq, "test_atomic_xaddq" }, #endif #ifdef ISC_PLATFORM_HAVEATOMICSTORE { (PFV) test_atomic_store, "test_atomic_store" }, #endif #if defined(ISC_PLATFORM_HAVEATOMICSTOREQ) { (PFV) test_atomic_storeq, "test_atomic_storeq" }, #endif { (PFV) 0, NULL } }; #ifdef WIN32 int main(int argc, char **argv) { t_settests(T_testlist); return (t_main(argc, argv)); } #endif