int main(int argc, char *argv[]) { unsigned int nworkers; unsigned int i; isc_thread_t workers[100]; char name[100]; void *dupname; if (argc > 1) nworkers = atoi(argv[1]); else nworkers = 2; if (nworkers > 100) nworkers = 100; printf("%d workers\n", nworkers); RUNTIME_CHECK(isc_rwlock_init(&lock, 5, 10) == ISC_R_SUCCESS); for (i = 0; i < nworkers; i++) { sprintf(name, "%02u", i); dupname = strdup(name); RUNTIME_CHECK(dupname != NULL); if (i != 0 && i % 3 == 0) RUNTIME_CHECK(isc_thread_create(run1, dupname, &workers[i]) == ISC_R_SUCCESS); else RUNTIME_CHECK(isc_thread_create(run2, dupname, &workers[i]) == ISC_R_SUCCESS); } for (i = 0; i < nworkers; i++) (void)isc_thread_join(workers[i], NULL); isc_rwlock_destroy(&lock); return (0); }
isc_result_t isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, unsigned int default_quantum, isc_taskmgr_t **managerp) { isc_result_t result; unsigned int i, started = 0; isc_taskmgr_t *manager; /* * Create a new task manager. */ REQUIRE(workers > 0); REQUIRE(managerp != NULL && *managerp == NULL); #ifndef ISC_PLATFORM_USETHREADS UNUSED(i); UNUSED(started); UNUSED(workers); if (taskmgr != NULL) { taskmgr->refs++; *managerp = taskmgr; return (ISC_R_SUCCESS); } #endif /* ISC_PLATFORM_USETHREADS */ manager = isc_mem_get(mctx, sizeof(*manager)); if (manager == NULL) return (ISC_R_NOMEMORY); manager->magic = TASK_MANAGER_MAGIC; manager->mctx = NULL; result = isc_mutex_init(&manager->lock); if (result != ISC_R_SUCCESS) goto cleanup_mgr; #ifdef ISC_PLATFORM_USETHREADS manager->workers = 0; manager->threads = isc_mem_allocate(mctx, workers * sizeof(isc_thread_t)); if (manager->threads == NULL) { result = ISC_R_NOMEMORY; goto cleanup_lock; } if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_condition_init() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); result = ISC_R_UNEXPECTED; goto cleanup_threads; } if (isc_condition_init(&manager->exclusive_granted) != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_condition_init() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); result = ISC_R_UNEXPECTED; goto cleanup_workavailable; } #endif /* ISC_PLATFORM_USETHREADS */ if (default_quantum == 0) default_quantum = DEFAULT_DEFAULT_QUANTUM; manager->default_quantum = default_quantum; INIT_LIST(manager->tasks); INIT_LIST(manager->ready_tasks); manager->tasks_running = 0; manager->exclusive_requested = ISC_FALSE; manager->exiting = ISC_FALSE; isc_mem_attach(mctx, &manager->mctx); #ifdef ISC_PLATFORM_USETHREADS LOCK(&manager->lock); /* * Start workers. */ for (i = 0; i < workers; i++) { if (isc_thread_create(run, manager, &manager->threads[manager->workers]) == ISC_R_SUCCESS) { manager->workers++; started++; } } UNLOCK(&manager->lock); if (started == 0) { manager_free(manager); return (ISC_R_NOTHREADS); } isc_thread_setconcurrency(workers); #else /* ISC_PLATFORM_USETHREADS */ manager->refs = 1; taskmgr = manager; #endif /* ISC_PLATFORM_USETHREADS */ *managerp = manager; return (ISC_R_SUCCESS); #ifdef ISC_PLATFORM_USETHREADS cleanup_workavailable: (void)isc_condition_destroy(&manager->work_available); cleanup_threads: isc_mem_free(mctx, manager->threads); cleanup_lock: DESTROYLOCK(&manager->lock); #endif cleanup_mgr: isc_mem_put(mctx, manager, sizeof(*manager)); return (result); }
ISC_TIMERFUNC_SCOPE isc_result_t isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { isc__timermgr_t *manager; isc_result_t result; /* * Create a timer manager. */ REQUIRE(managerp != NULL && *managerp == NULL); #ifdef USE_SHARED_MANAGER if (timermgr != NULL) { timermgr->refs++; *managerp = (isc_timermgr_t *)timermgr; return (ISC_R_SUCCESS); } #endif /* USE_SHARED_MANAGER */ manager = isc_mem_get(mctx, sizeof(*manager)); if (manager == NULL) return (ISC_R_NOMEMORY); manager->common.impmagic = TIMER_MANAGER_MAGIC; manager->common.magic = ISCAPI_TIMERMGR_MAGIC; manager->common.methods = (isc_timermgrmethods_t *)&timermgrmethods; manager->mctx = NULL; manager->done = ISC_FALSE; INIT_LIST(manager->timers); manager->nscheduled = 0; isc_time_settoepoch(&manager->due); manager->heap = NULL; result = isc_heap_create(mctx, sooner, set_index, 0, &manager->heap); if (result != ISC_R_SUCCESS) { INSIST(result == ISC_R_NOMEMORY); isc_mem_put(mctx, manager, sizeof(*manager)); return (ISC_R_NOMEMORY); } result = isc_mutex_init(&manager->lock); if (result != ISC_R_SUCCESS) { isc_heap_destroy(&manager->heap); isc_mem_put(mctx, manager, sizeof(*manager)); return (result); } isc_mem_attach(mctx, &manager->mctx); #ifdef USE_TIMER_THREAD if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) { isc_mem_detach(&manager->mctx); DESTROYLOCK(&manager->lock); isc_heap_destroy(&manager->heap); isc_mem_put(mctx, manager, sizeof(*manager)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_condition_init() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); return (ISC_R_UNEXPECTED); } if (isc_thread_create(run, manager, &manager->thread) != ISC_R_SUCCESS) { isc_mem_detach(&manager->mctx); (void)isc_condition_destroy(&manager->wakeup); DESTROYLOCK(&manager->lock); isc_heap_destroy(&manager->heap); isc_mem_put(mctx, manager, sizeof(*manager)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_thread_create() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); return (ISC_R_UNEXPECTED); } #endif #ifdef USE_SHARED_MANAGER manager->refs = 1; timermgr = manager; #endif /* USE_SHARED_MANAGER */ *managerp = (isc_timermgr_t *)manager; return (ISC_R_SUCCESS); }
ATF_TC_BODY(benchmark, tc) { isc_result_t result; char namestr[sizeof("name18446744073709551616.example.org.")]; unsigned int r; dns_rbt_t *mytree; dns_rbtnode_t *node; unsigned int i; unsigned int maxvalue = 1000000; isc_time_t ts1, ts2; double t; unsigned int nthreads; isc_thread_t threads[32]; UNUSED(tc); srandom(time(NULL)); debug_mem_record = ISC_FALSE; result = dns_test_begin(NULL, ISC_TRUE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); fnames = (dns_fixedname_t *) malloc(4000000 * sizeof(dns_fixedname_t)); names = (dns_name_t **) malloc(4000000 * sizeof(dns_name_t *)); values = (int *) malloc(4000000 * sizeof(int)); for (i = 0; i < 4000000; i++) { r = ((unsigned long) random()) % maxvalue; snprintf(namestr, sizeof(namestr), "name%u.example.org.", r); build_name_from_str(namestr, &fnames[i]); names[i] = dns_fixedname_name(&fnames[i]); values[i] = r; } /* Create a tree. */ mytree = NULL; result = dns_rbt_create(mctx, NULL, NULL, &mytree); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); /* Insert test data into the tree. */ for (i = 0; i < maxvalue; i++) { snprintf(namestr, sizeof(namestr), "name%u.example.org.", i); node = NULL; result = insert_helper(mytree, namestr, &node); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); node->data = (void *) (intptr_t) i; } result = isc_time_now(&ts1); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); nthreads = ISC_MIN(isc_os_ncpus(), 32); nthreads = ISC_MAX(nthreads, 1); for (i = 0; i < nthreads; i++) { result = isc_thread_create(find_thread, mytree, &threads[i]); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); } for (i = 0; i < nthreads; i++) { result = isc_thread_join(threads[i], NULL); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); } result = isc_time_now(&ts2); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); t = isc_time_microdiff(&ts2, &ts1); printf("%u findnode calls, %f seconds, %f calls/second\n", nthreads * 8 * 4000000, t / 1000000.0, (nthreads * 8 * 4000000) / (t / 1000000.0)); free(values); free(names); free(fnames); dns_rbt_destroy(&mytree); dns_test_end(); }