struct dt_env * dt_create(const char *socket_path, unsigned num_workers) { fstrm_res res; struct dt_env *env; struct fstrm_iothr_options *fopt; struct fstrm_unix_writer_options *fuwopt; struct fstrm_writer *fw; struct fstrm_writer_options *fwopt; verbose(VERB_OPS, "attempting to connect to dnstap socket %s", socket_path); log_assert(socket_path != NULL); log_assert(num_workers > 0); env = (struct dt_env *) calloc(1, sizeof(struct dt_env)); if (!env) return NULL; fwopt = fstrm_writer_options_init(); res = fstrm_writer_options_add_content_type(fwopt, DNSTAP_CONTENT_TYPE, sizeof(DNSTAP_CONTENT_TYPE) - 1); log_assert(res == fstrm_res_success); fuwopt = fstrm_unix_writer_options_init(); fstrm_unix_writer_options_set_socket_path(fuwopt, socket_path); fw = fstrm_unix_writer_init(fuwopt, fwopt); log_assert(fw != NULL); fopt = fstrm_iothr_options_init(); fstrm_iothr_options_set_num_input_queues(fopt, num_workers); env->iothr = fstrm_iothr_init(fopt, &fw); if (env->iothr == NULL) { verbose(VERB_DETAIL, "dt_create: fstrm_iothr_init() failed"); fstrm_writer_destroy(&fw); free(env); env = NULL; } fstrm_iothr_options_destroy(&fopt); fstrm_unix_writer_options_destroy(&fuwopt); fstrm_writer_options_destroy(&fwopt); return env; }
int main(int argc, char **argv) { struct timespec ts_a, ts_b; double elapsed; char *file_path; char *queue_model_str; unsigned num_messages; unsigned num_threads; fstrm_iothr_queue_model queue_model; if (argc != 5) { fprintf(stderr, "Usage: %s <FILE> <QUEUE MODEL> <NUM THREADS> <NUM MESSAGES>\n", argv[0]); fprintf(stderr, "\n"); fprintf(stderr, "FILE is a filesystem path.\n"); fprintf(stderr, "QUEUE MODEL is the string 'SPSC' or 'MPSC'.\n"); fprintf(stderr, "NUM THREADS is an integer.\n"); fprintf(stderr, "NUM MESSAGES is an integer.\n"); return EXIT_FAILURE; } file_path = argv[1]; queue_model_str = argv[2]; num_threads = atoi(argv[3]); num_messages = atoi(argv[4]); if (num_threads < 1) { fprintf(stderr, "%s: Error: invalid number of threads\n", argv[0]); return EXIT_FAILURE; } if (num_messages < 1) { fprintf(stderr, "%s: Error: invalid number of messages\n", argv[0]); return EXIT_FAILURE; } if (strcasecmp(queue_model_str, "SPSC") == 0) { queue_model = FSTRM_IOTHR_QUEUE_MODEL_SPSC; } else if (strcasecmp(queue_model_str, "MPSC") == 0) { queue_model = FSTRM_IOTHR_QUEUE_MODEL_MPSC; } else { fprintf(stderr, "%s: Error: invalid queue model\n", argv[0]); return EXIT_FAILURE; } printf("testing fstrm_iothr with file= %s " "queue_model= %s " "num_threads= %u " "num_messages= %u\n", file_path, queue_model_str, num_threads, num_messages); struct fstrm_file_options *fopt; fopt = fstrm_file_options_init(); fstrm_file_options_set_file_path(fopt, file_path); struct fstrm_writer *w = fstrm_file_writer_init(fopt, NULL); assert(w != NULL); fstrm_file_options_destroy(&fopt); struct fstrm_iothr_options *iothr_opt; iothr_opt = fstrm_iothr_options_init(); if (queue_model == FSTRM_IOTHR_QUEUE_MODEL_SPSC) { fstrm_iothr_options_set_num_input_queues(iothr_opt, num_threads); } else if (queue_model == FSTRM_IOTHR_QUEUE_MODEL_MPSC) { fstrm_iothr_options_set_num_input_queues(iothr_opt, 1); } else { assert(0); /* not reached */ } fstrm_iothr_options_set_queue_model(iothr_opt, queue_model); struct fstrm_iothr *iothr = fstrm_iothr_init(iothr_opt, &w); assert(iothr != NULL); fstrm_iothr_options_destroy(&iothr_opt); struct consumer test_consumer; struct producer test_producers[num_threads]; for (unsigned i = 0; i < num_threads; i++) { test_producers[i].iothr = iothr; test_producers[i].num_messages = num_messages; } if (queue_model == FSTRM_IOTHR_QUEUE_MODEL_SPSC) { for (unsigned i = 0; i < num_threads; i++) { test_producers[i].ioq = fstrm_iothr_get_input_queue(iothr); assert(test_producers[i].ioq != NULL); } } else if (queue_model == FSTRM_IOTHR_QUEUE_MODEL_MPSC) { struct fstrm_iothr_queue *ioq = fstrm_iothr_get_input_queue(iothr); assert(ioq != NULL); for (unsigned i = 0; i < num_threads; i++) test_producers[i].ioq = ioq; } else { assert(0); /* not reached */ } my_gettime(CLOCK_MONOTONIC, &ts_a); printf("creating %u producer threads\n", num_threads); for (unsigned i = 0; i < num_threads; i++) pthread_create(&test_producers[i].thr, NULL, thr_producer, &test_producers[i]); printf("joining %u producer threads\n", num_threads); for (unsigned i = 0; i < num_threads; i++) pthread_join(test_producers[i].thr, (void **) NULL); printf("destroying fstrm_iothr object\n"); fstrm_iothr_destroy(&iothr); my_gettime(CLOCK_MONOTONIC, &ts_b); my_timespec_sub(&ts_a, &ts_b); elapsed = my_timespec_to_double(&ts_b); printf("completed in %.2f seconds\n", elapsed); int res = consume_input(&test_consumer, file_path); if (res != EXIT_SUCCESS) return res; struct producer_stats pstat_sum; memset(&pstat_sum, 0, sizeof(pstat_sum)); for (unsigned i = 0; i < num_threads; i++) { pstat_sum.count_generated += test_producers[i].pstat.count_generated; pstat_sum.count_submitted += test_producers[i].pstat.count_submitted; pstat_sum.bytes_generated += test_producers[i].pstat.bytes_generated; pstat_sum.bytes_submitted += test_producers[i].pstat.bytes_submitted; } printf("count_generated= %" PRIu64 "\n", pstat_sum.count_generated); printf("bytes_generated= %" PRIu64 "\n", pstat_sum.bytes_generated); printf("count_submitted= %" PRIu64 "\n", pstat_sum.count_submitted); printf("bytes_submitted= %" PRIu64 "\n", pstat_sum.bytes_submitted); printf("count_received= %" PRIu64 " (%.3f)\n", test_consumer.cstat.count_received, (test_consumer.cstat.count_received + 0.0) / (pstat_sum.count_generated + 0.0) ); printf("bytes_received= %" PRIu64 " (%.3f)\n", test_consumer.cstat.bytes_received, (test_consumer.cstat.bytes_received + 0.0) / (pstat_sum.bytes_generated + 0.0) ); assert(pstat_sum.count_submitted == test_consumer.cstat.count_received); assert(pstat_sum.bytes_submitted == test_consumer.cstat.bytes_received); putchar('\n'); return EXIT_SUCCESS; }