/* * Copyright (C) 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/. * * See the COPYRIGHT file distributed with this work for additional * information regarding copyright ownership. */ #include #include #include #include #include #include #include #include "isctest.h" #define TASKS 32 #define ITERATIONS 1000 #define COUNTS_PER_ITERATION 1000 #define INCREMENT_64 (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 { uint32_t iteration; } counter_t; counter_t counters[TASKS]; #if defined(ISC_PLATFORM_HAVEXADD) static 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); } } ATF_TC(atomic_xadd); ATF_TC_HEAD(atomic_xadd, tc) { atf_tc_set_md_var(tc, "descr", "atomic XADD"); } ATF_TC_BODY(atomic_xadd, tc) { isc_result_t result; isc_task_t *tasks[TASKS]; isc_event_t *event = NULL; int i; UNUSED(tc); result = isc_test_begin(NULL, true, 0); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 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; ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]), ISC_R_SUCCESS); event = isc_event_allocate(mctx, NULL, 1000, do_xadd, &counters[i], sizeof(struct isc_event)); ATF_REQUIRE(event != NULL); isc_task_sendanddetach(&tasks[i], &event); } isc_test_end(); printf("32-bit counter %d, expected %d\n", counter_32, EXPECTED_COUNT_32); ATF_CHECK_EQ(counter_32, EXPECTED_COUNT_32); counter_32 = 0; } #endif #if defined(ISC_PLATFORM_HAVEXADDQ) static 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); } } ATF_TC(atomic_xaddq); ATF_TC_HEAD(atomic_xaddq, tc) { atf_tc_set_md_var(tc, "descr", "atomic XADDQ"); } ATF_TC_BODY(atomic_xaddq, tc) { isc_result_t result; isc_task_t *tasks[TASKS]; isc_event_t *event = NULL; int i; UNUSED(tc); result = isc_test_begin(NULL, true, 0); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 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; ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]), ISC_R_SUCCESS); event = isc_event_allocate(mctx, NULL, 1000, do_xaddq, &counters[i], sizeof(struct isc_event)); ATF_REQUIRE(event != NULL); isc_task_sendanddetach(&tasks[i], &event); } isc_test_end(); printf("64-bit counter %" PRId64 ", " "expected %" PRId64 "\n", counter_64, EXPECTED_COUNT_64); ATF_CHECK_EQ(counter_64, EXPECTED_COUNT_64); counter_32 = 0; } #endif #if defined(ISC_PLATFORM_HAVEATOMICSTORE) static 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; uint32_t r; 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); } } ATF_TC(atomic_store); ATF_TC_HEAD(atomic_store, tc) { atf_tc_set_md_var(tc, "descr", "atomic STORE"); } ATF_TC_BODY(atomic_store, tc) { isc_result_t result; isc_task_t *tasks[TASKS]; isc_event_t *event = NULL; uint32_t val; uint32_t r; int i; UNUSED(tc); result = isc_test_begin(NULL, true, 0); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 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; ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]), ISC_R_SUCCESS); event = isc_event_allocate(mctx, NULL, 1000, do_store, &counters[i], sizeof(struct isc_event)); ATF_REQUIRE(event != NULL); isc_task_sendanddetach(&tasks[i], &event); } isc_test_end(); r = store_32 & 0xff; val = (r << 24) | (r << 16) | (r << 8) | r; printf("32-bit store 0x%x, expected 0x%x\n", (uint32_t) store_32, val); ATF_CHECK_EQ((uint32_t) store_32, val); store_32 = 0; } #endif #if defined(ISC_PLATFORM_HAVEATOMICSTOREQ) static 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; uint8_t r; uint64_t val; r = random() % 256; val = (((uint64_t) r << 24) | ((uint64_t) r << 16) | ((uint64_t) r << 8) | (uint64_t) r); val |= ((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); } } ATF_TC(atomic_storeq); ATF_TC_HEAD(atomic_storeq, tc) { atf_tc_set_md_var(tc, "descr", "atomic STOREQ"); } ATF_TC_BODY(atomic_storeq, tc) { isc_result_t result; isc_task_t *tasks[TASKS]; isc_event_t *event = NULL; uint64_t val; uint32_t r; int i; UNUSED(tc); result = isc_test_begin(NULL, true, 0); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 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; ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]), ISC_R_SUCCESS); event = isc_event_allocate(mctx, NULL, 1000, do_storeq, &counters[i], sizeof(struct isc_event)); ATF_REQUIRE(event != NULL); isc_task_sendanddetach(&tasks[i], &event); } isc_test_end(); r = store_64 & 0xff; val = (((uint64_t) r << 24) | ((uint64_t) r << 16) | ((uint64_t) r << 8) | (uint64_t) r); val |= ((uint64_t) val << 32); printf("64-bit store 0x%" PRIx64 ", " "expected 0x%" PRIx64 "\n", (uint64_t) store_64, val); ATF_CHECK_EQ((uint64_t) store_64, val); store_64 = 0; } #endif #if !defined(ISC_PLATFORM_HAVEXADD) && \ !defined(ISC_PLATFORM_HAVEXADDQ) && \ !defined(ISC_PLATFORM_HAVEATOMICSTOREQ) ATF_TC(untested); ATF_TC_HEAD(untested, tc) { atf_tc_set_md_var(tc, "descr", "skipping aes test"); } ATF_TC_BODY(untested, tc) { UNUSED(tc); atf_tc_skip("AES not available"); } #endif /* !HAVEXADD, !HAVEXADDQ, !HAVEATOMICSTOREQ */ /* * Main */ ATF_TP_ADD_TCS(tp) { #if defined(ISC_PLATFORM_HAVEXADD) ATF_TP_ADD_TC(tp, atomic_xadd); #endif #if defined(ISC_PLATFORM_HAVEXADDQ) ATF_TP_ADD_TC(tp, atomic_xaddq); #endif #ifdef ISC_PLATFORM_HAVEATOMICSTORE ATF_TP_ADD_TC(tp, atomic_store); #endif #if defined(ISC_PLATFORM_HAVEATOMICSTOREQ) ATF_TP_ADD_TC(tp, atomic_storeq); #endif #if !defined(ISC_PLATFORM_HAVEXADD) && \ !defined(ISC_PLATFORM_HAVEXADDQ) && \ !defined(ISC_PLATFORM_HAVEATOMICSTOREQ) ATF_TP_ADD_TC(tp, untested); #endif return (atf_no_error()); }