/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2018 IBM Corporation. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "opal_config.h" #include #include "support.h" #include "opal/class/opal_fifo.h" #include "opal/runtime/opal.h" #include "opal/constants.h" #include "opal/mca/threads/threads.h" #include #include #include #include #define OPAL_FIFO_TEST_THREAD_COUNT 8 #define ITERATIONS 1000000 #define ITEM_COUNT 100 #define ITEMS_PER_LOOP 30 #if !defined(timersub) #define timersub(a, b, r) \ do { \ (r)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ if ((a)->tv_usec < (b)->tv_usec) { \ (r)->tv_sec--; \ (a)->tv_usec += 1000000; \ } \ (r)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ } while (0) #endif static void *thread_test (opal_object_t *arg) { opal_thread_t *t = (opal_thread_t *) arg; opal_fifo_t *fifo = (opal_fifo_t *) t->t_arg; opal_list_item_t *item; struct timeval start, stop, total; double timing; gettimeofday (&start, NULL); for (int i = 0 ; i < ITERATIONS ; ++i) { item = opal_fifo_pop_atomic (fifo); if (NULL != item) { (void) opal_fifo_push_atomic (fifo, item); } } gettimeofday (&stop, NULL); timersub(&stop, &start, &total); timing = ((double) total.tv_sec + (double) total.tv_usec * 1e-6) / (double) ITERATIONS; printf ("Atomics thread finished. Time: %d s %d us %d nsec/poppush\n", (int) total.tv_sec, (int)total.tv_usec, (int)(timing / 1e-9)); pthread_exit(NULL); } static void *thread_test_exhaust (opal_object_t *arg) { opal_thread_t *t = (opal_thread_t *) arg; opal_fifo_t *fifo = (opal_fifo_t *) t->t_arg; opal_list_item_t *items[ITEMS_PER_LOOP]; struct timeval start, stop, total; int item_count = 0; double timing; gettimeofday (&start, NULL); for (int i = 0 ; i < ITERATIONS ; i += ITEMS_PER_LOOP) { for (int j = 0 ; j < ITEMS_PER_LOOP ; ++j) { items[j] = opal_fifo_pop_atomic (fifo); if (items[j]) { ++item_count; } } for (int j = 0 ; j < ITEMS_PER_LOOP ; ++j) { if (items[j]) { (void) opal_fifo_push_atomic (fifo, items[j]); } } } gettimeofday (&stop, NULL); timersub(&stop, &start, &total); timing = ((double) total.tv_sec + (double) total.tv_usec * 1e-6) / (double) item_count; fprintf (stderr, "Exhaustive atomics thread finished. Popped %d items. Time: %d s %d us %d nsec/poppush\n", item_count, (int) total.tv_sec, (int)total.tv_usec, (int)(timing / 1e-9)); return NULL; } static bool check_fifo_consistency (opal_fifo_t *fifo, int expected_count) { opal_list_item_t * item; int count; for (count = 0, item = (opal_list_item_t *) fifo->opal_fifo_head.data.item ; item != &fifo->opal_fifo_ghost ; item = opal_list_get_next(item), count++); return count == expected_count; } int main (int argc, char *argv[]) { opal_thread_t threads[OPAL_FIFO_TEST_THREAD_COUNT]; opal_list_item_t *item, *prev, *item2; struct timeval start, stop, total; opal_fifo_t fifo; bool success; double timing; int rc; rc = opal_init_util (&argc, &argv); test_verify_int(OPAL_SUCCESS, rc); if (OPAL_SUCCESS != rc) { test_finalize(); exit (1); } test_init("opal_fifo_t"); OBJ_CONSTRUCT(&fifo, opal_fifo_t); item = OBJ_NEW(opal_list_item_t); prev = opal_fifo_push_st (&fifo, item); if (&fifo.opal_fifo_ghost == prev) { test_success (); } else { test_failure (" opal_fifo_push_st on empty fifo"); } item2 = opal_fifo_pop_st (&fifo); if (item == item2) { test_success (); } else { test_failure (" opal_fifo_pop_st"); } OBJ_RELEASE(item); for (int i = 0 ; i < ITEM_COUNT ; ++i) { item = OBJ_NEW(opal_list_item_t); item->item_free = 0; opal_fifo_push_st (&fifo, item); } if (check_fifo_consistency (&fifo, ITEM_COUNT)) { test_success (); } else { test_failure (" opal_fifo_push_st(multiple items)"); } gettimeofday (&start, NULL); for (int i = 0 ; i < ITERATIONS ; ++i) { item = opal_fifo_pop_st (&fifo); (void) opal_fifo_push_st (&fifo, item); } gettimeofday (&stop, NULL); timersub(&stop, &start, &total); timing = ((double) total.tv_sec + (double) total.tv_usec * 1e-6) / (double) ITERATIONS; if (check_fifo_consistency (&fifo, ITEM_COUNT)) { test_success (); } else { test_failure (" fifo push/pop"); } printf ("Single thread test. Time: %d s %d us %d nsec/poppush\n", (int) total.tv_sec, (int)total.tv_usec, (int)(timing / 1e-9)); threads[0].t_arg = &fifo; thread_test ((opal_object_t *) &threads[0]); if (check_fifo_consistency (&fifo, ITEM_COUNT)) { test_success (); } else { test_failure (" fifo push/pop single-threaded with atomics"); } gettimeofday (&start, NULL); for (int i = 0 ; i < OPAL_FIFO_TEST_THREAD_COUNT ; ++i) { OBJ_CONSTRUCT(&threads[i], opal_thread_t); threads[i].t_run = thread_test; threads[i].t_arg = &fifo; opal_thread_start (threads + i); } for (int i = 0 ; i < OPAL_FIFO_TEST_THREAD_COUNT ; ++i) { void *ret; opal_thread_join (threads + i, &ret); } gettimeofday (&stop, NULL); timersub(&stop, &start, &total); timing = ((double) total.tv_sec + (double) total.tv_usec * 1e-6) / (double) (ITERATIONS * OPAL_FIFO_TEST_THREAD_COUNT); if (check_fifo_consistency (&fifo, ITEM_COUNT)) { test_success (); } else { test_failure (" fifo push/pop multi-threaded with atomics"); } printf ("All threads finished. Thread count: %d Time: %d s %d us %d nsec/poppush\n", OPAL_FIFO_TEST_THREAD_COUNT, (int) total.tv_sec, (int)total.tv_usec, (int)(timing / 1e-9)); gettimeofday (&start, NULL); for (int i = 0 ; i < OPAL_FIFO_TEST_THREAD_COUNT ; ++i) { OBJ_CONSTRUCT(&threads[i], opal_thread_t); threads[i].t_run = thread_test_exhaust; threads[i].t_arg = &fifo; opal_thread_start (threads + i); } for (int i = 0 ; i < OPAL_FIFO_TEST_THREAD_COUNT ; ++i) { void *ret; opal_thread_join (threads + i, &ret); } gettimeofday (&stop, NULL); timersub(&stop, &start, &total); timing = ((double) total.tv_sec + (double) total.tv_usec * 1e-6) / (double) (ITERATIONS * OPAL_FIFO_TEST_THREAD_COUNT); if (check_fifo_consistency (&fifo, ITEM_COUNT)) { test_success (); } else { test_failure (" fifo push/pop multi-threaded with atomics when there are insufficient items"); } printf ("All threads finished. Thread count: %d Time: %d s %d us %d nsec/poppush\n", OPAL_FIFO_TEST_THREAD_COUNT, (int) total.tv_sec, (int)total.tv_usec, (int)(timing / 1e-9)); success = true; for (int i = 0 ; i < ITEM_COUNT ; ++i) { item = opal_fifo_pop_st (&fifo); if (NULL == item) { success = false; break; } OBJ_RELEASE(item); } if (success) { test_success (); } else { test_failure (" fifo pop all items"); } OBJ_DESTRUCT(&fifo); opal_finalize_util (); return test_finalize (); }