ram_reply_t ramtest_join(ramtest_test_t *test_arg) { size_t i = 0; ram_reply_t myreply = RAM_REPLY_OK; size_t unused = 0; RAM_FAIL_NOTNULL(test_arg); RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "[0] i am waiting for my threads to finish...\n")); for (i = 0; i < test_arg->ramtestt_params.ramtestp_threadcount; ++i) { ram_reply_t e = RAM_REPLY_INSANE; RAM_FAIL_TRAP(ramthread_join(&e, test_arg->ramtestt_threads[i])); if (RAM_REPLY_OK != e) { RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "[0] thread %zu replied with an unexpected failure (%d).\n", i + 1, (int)e)); /* if i haven't yet recorded an error as my reply, do so now. this * ensures that the primary symptom is recorded and not any echoes * of the problem. */ RAM_FAIL_TRAP(ram_fail_accumulate(&myreply, e)); } } return myreply; }
ram_reply_t ramtest_test(const ramtest_params_t *params_arg) { ram_reply_t e = RAM_REPLY_INSANE; ramtest_test_t test = {0}; size_t unused = 0; RAM_FAIL_NOTNULL(params_arg); RAM_FAIL_TRAP(ramtest_describe(stderr, params_arg)); /* if a dry run has been specified, i'll quit now. */ if (params_arg->ramtestp_dryrun) return RAM_REPLY_OK; RAM_FAIL_TRAP(ramtest_inittest(&test, params_arg)); e = ramtest_test2(&test); RAM_FAIL_TRAP(ram_fail_accumulate(&e, ramtest_fintest(&test))); if (RAM_REPLY_OK == e) { RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "[0] the test succeeded.\n")); return RAM_REPLY_OK; } else { RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "[0] the test failed (reply code %d).\n", e)); RAM_FAIL_TRAP(e); return RAM_REPLY_INSANE; } }
ram_reply_t ramtest_start(ramtest_test_t *test_arg) { size_t i = 0; size_t unused = 0; RAM_FAIL_NOTNULL(test_arg); for (i = 0; i < test_arg->ramtestt_params.ramtestp_threadcount; ++i) { ramtest_start_t *start = NULL; const size_t threadid = i + 1; RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "[0] starting thread %zu...\n", threadid)); /* i'm the sole producer of this memory; *ramtest_start()* is the sole * consumer. */ start = (ramtest_start_t *)calloc(sizeof(*start), 1); RAM_FAIL_EXPECT(RAM_REPLY_RESOURCEFAIL, NULL != start); start->ramtests_test = test_arg; start->ramtests_threadidx = i; RAM_FAIL_TRAP(ramthread_mkthread(&test_arg->ramtestt_threads[i], &ramtest_thread, start)); RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "[0] started thread %zu.\n", threadid)); } return RAM_REPLY_OK; }
ram_reply_t ramtest_test2(ramtest_test_t *test_arg) { size_t unused = 0; RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "[0] beginning test...\n")); RAM_FAIL_TRAP(ramtest_start(test_arg)); RAM_FAIL_TRAP(ramtest_join(test_arg)); return RAM_REPLY_OK; }
ram_reply_t runtest2(const ramtest_params_t *params_arg, extra_t *extra_arg) { ramtest_params_t testparams = {0}; size_t unused = 0; testparams = *params_arg; /* i am responsible for policing the minimum and maximum allocation * size here. */ if (testparams.ramtestp_minsize < sizeof(void *) || testparams.ramtestp_maxsize < sizeof(void *)) { RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "you cannot specify a size smaller than %zu bytes.\n", sizeof(void *))); return RAM_REPLY_INPUTFAIL; } /* TODO: shouldn't this test be moved into the framework? */ if (testparams.ramtestp_minsize > testparams.ramtestp_maxsize) { RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "please specify a minimum size (%zu bytes) that is smaller than " "or equal to the maximum (%zu bytes).\n", testparams.ramtestp_minsize, testparams.ramtestp_maxsize)); return RAM_REPLY_INPUTFAIL; } /* TODO: how do i determine the maximum allocation size ahead of time? */ testparams.ramtestp_extra = extra_arg; testparams.ramtestp_acquire = &acquire; testparams.ramtestp_release = &release; testparams.ramtestp_query = &query; testparams.ramtestp_flush = &flush; testparams.ramtestp_check = ✓ RAM_FAIL_TRAP(ramtest_test(&testparams)); return RAM_REPLY_OK; }
ram_reply_t ramtest_thread(void *arg) { ramtest_start_t *start = (ramtest_start_t *)arg; ramtest_test_t *test = NULL; size_t threadidx = 0, threadid = 0; ram_reply_t e = RAM_REPLY_INSANE; size_t unused = 0; RAM_FAIL_NOTNULL(arg); test = start->ramtests_test; threadidx = start->ramtests_threadidx; /* i'm the sole consumer of this memory; *ramtest_start()* is the sole * producer. */ free(start); threadid = threadidx + 1; RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "[%zu] testing...\n", threadid)); e = ramtest_thread2(test, threadidx); RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "[%zu] finished.\n", threadid)); return e; }
int main(int argc, char *argv[]) { ram_reply_t e = RAM_REPLY_INSANE; size_t unused = 0; e = main2(argc, argv); if (RAM_REPLY_OK != e) RAM_FAIL_TRAP(ramtest_fprintf(&unused,stderr, "fail (%d).", e)); if (RAM_REPLY_INPUTFAIL == e) { usage(e, argc, argv); ram_fail_panic("unreachable code."); return RAM_REPLY_INSANE; } else return e; }
ram_reply_t ramtest_describe(FILE *out_arg, const ramtest_params_t *params_arg) { size_t unused = 0; RAM_FAIL_NOTNULL(out_arg); RAM_FAIL_NOTNULL(params_arg); if (params_arg->ramtestp_dryrun) { RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "you have specified the following test:\n\n")); } else { RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "i will run the following test:\n\n")); } RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "%zu allocation(s) (and corresponding deallocations).\n", params_arg->ramtestp_alloccount)); if (1 == params_arg->ramtestp_threadcount) { RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "this test will not be parallelized.\n")); } else { RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "%zu parallel operation(s) allowed.\n", params_arg->ramtestp_threadcount)); } RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "%d%% of the allocations will be managed by malloc() " "and free().\n", params_arg->ramtestp_mallocchance)); RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "allocations will not be smaller than %zu bytes.\n", params_arg->ramtestp_minsize)); RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "allocations will not be larger than %zu bytes.\n", params_arg->ramtestp_maxsize)); if (params_arg->ramtestp_userngseed) { RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "the random number generator will use seed %u.\n", params_arg->ramtestp_rngseed)); } else { RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "the random number generator will use a randomly " "selected seed.\n")); } #if RAM_WANT_OVERCONFIDENT RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "warning: this is an overconfident build, so the results cannot " "be trusted. rebuild with RAMOPT_UNSUPPORTED_OVERCONFIDENT " "#define'd as 0 if you wish to have reliable results.\n"); #endif if (params_arg->ramtestp_dryrun) { RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "\nto run this test, omit the --dry-run option.\n")); } else RAM_FAIL_TRAP(ramtest_fprintf(&unused, out_arg, "-----\n")); return RAM_REPLY_OK; }
ram_reply_t ramtest_inittest2(ramtest_test_t *test_arg, const ramtest_params_t *params_arg) { size_t i = 0; size_t seqlen = 0; size_t maxthreads = 0; size_t unused = 0; RAM_FAIL_NOTNULL(params_arg); RAM_FAIL_NOTZERO(params_arg->ramtestp_alloccount); RAM_FAIL_EXPECT(RAM_REPLY_RANGEFAIL, params_arg->ramtestp_minsize > 0); RAM_FAIL_EXPECT(RAM_REPLY_RANGEFAIL, params_arg->ramtestp_minsize <= params_arg->ramtestp_maxsize); RAM_FAIL_EXPECT(RAM_REPLY_RANGEFAIL, params_arg->ramtestp_mallocchance >= 0); RAM_FAIL_EXPECT(RAM_REPLY_RANGEFAIL, params_arg->ramtestp_mallocchance <= 100); RAM_FAIL_NOTNULL(params_arg->ramtestp_acquire); RAM_FAIL_NOTNULL(params_arg->ramtestp_release); RAM_FAIL_NOTNULL(params_arg->ramtestp_query); /* *params_arg->ramtestp_flush* is allowed to be NULL. */ RAM_FAIL_NOTNULL(params_arg->ramtestp_check); RAM_FAIL_TRAP(ramtest_maxthreadcount(&maxthreads)); RAM_FAIL_EXPECT(RAM_REPLY_DISALLOWED, params_arg->ramtestp_threadcount <= maxthreads); test_arg->ramtestt_params = *params_arg; if (0 == test_arg->ramtestt_params.ramtestp_threadcount) { RAM_FAIL_TRAP(ramtest_defaultthreadcount( &test_arg->ramtestt_params.ramtestp_threadcount)); } test_arg->ramtestt_records = calloc(test_arg->ramtestt_params.ramtestp_alloccount, sizeof(*test_arg->ramtestt_records)); RAM_FAIL_EXPECT(RAM_REPLY_RESOURCEFAIL, NULL != test_arg->ramtestt_records); test_arg->ramtestt_threads = calloc(test_arg->ramtestt_params.ramtestp_threadcount, sizeof(*test_arg->ramtestt_threads)); RAM_FAIL_EXPECT(RAM_REPLY_RESOURCEFAIL, NULL != test_arg->ramtestt_threads); seqlen = test_arg->ramtestt_params.ramtestp_alloccount * 2; test_arg->ramtestt_sequence = calloc(seqlen, sizeof(*test_arg->ramtestt_sequence)); RAM_FAIL_EXPECT(RAM_REPLY_RESOURCEFAIL, NULL != test_arg->ramtestt_sequence); RAM_FAIL_TRAP(rammtx_mkmutex(&test_arg->ramtestt_mtx)); for (i = 0; i < test_arg->ramtestt_params.ramtestp_alloccount; ++i) { RAM_FAIL_TRAP(rammtx_mkmutex( &test_arg->ramtestt_records[i].ramtestar_mtx)); } /* the sequence array must contain two copies of each index into * *test_arg->ramtestt_records*. the first represents an allocation. * the second, a deallocation. */ for (i = 0; i < seqlen; ++i) test_arg->ramtestt_sequence[i] = (i / 2); /* i shuffle the sequence array to ensure a randomized order of * operations. */ RAM_FAIL_TRAP(ramtest_shuffle(test_arg->ramtestt_sequence, sizeof(test_arg->ramtestt_sequence[0]), seqlen)); if (!test_arg->ramtestt_params.ramtestp_userngseed) test_arg->ramtestt_params.ramtestp_rngseed = (unsigned int)time(NULL); srand(test_arg->ramtestt_params.ramtestp_rngseed); RAM_FAIL_TRAP(ramtest_fprintf(&unused, stderr, "[0] i seeded the random generator with the value %u.\n", test_arg->ramtestt_params.ramtestp_rngseed)); test_arg->ramtestt_nextrec = 0; return RAM_REPLY_OK; }