Example #1
0
File: rate.c Project: edmonds/mtbl
void
rate_sleep(struct rate *r)
{
	struct timespec now, til;

	/* what clock to use depends on whether clock_nanosleep() is available */
#if HAVE_CLOCK_NANOSLEEP
	static const clockid_t rate_clock = CLOCK_MONOTONIC;
#else
	static const clockid_t rate_clock = CLOCK_REALTIME;
#endif

	if (r == NULL)
		return;

	/* update the event counter */
	r->count += 1;

	/* fetch the current time */
	clock_gettime(rate_clock, &now);

	/* special case: if this is the first call to rate_sleep(),
	 * calculate when the next tick will be. this is a little bit more
	 * accurate than calculating it in rate_init().
	 */
	if (r->count == 1) {
		r->start = now;
		r->next_tick = calc_next_tick(&now, &r->period);
	}

	/* adjust the rate and period every 'freq' events.
	 * skip the first window of 'freq' events.
	 * disabled if 'freq' is 0.
	 */
	if (r->freq != 0 && (r->count % r->freq) == 0 && r->count > r->freq)
		adjust_rate(r, &now);

	/* 'til', amount of time remaining until the next tick */
	til = r->next_tick;
	my_timespec_sub(&now, &til);

	/* if 'til' is in the past, don't bother sleeping */
	if (ts_nanos(&til) > 0) {
		/* do the sleep */
#if HAVE_CLOCK_NANOSLEEP
		clock_nanosleep(rate_clock, TIMER_ABSTIME, &r->next_tick, NULL);
#else
		struct timespec rel;
		rel = r->next_tick;
		my_timespec_sub(&now, &rel);
		my_nanosleep(&rel);
#endif

		/* re-fetch the current time */
		clock_gettime(rate_clock, &now);
	}

	/* calculate the next tick */
	r->next_tick = calc_next_tick(&now, &r->period);
}
Example #2
0
File: rate.c Project: edmonds/mtbl
static inline void
adjust_rate(struct rate *r, struct timespec *now)
{
	struct timespec elapsed;
	double ratio;
	unsigned actual_rate;

	/* amount of time elapsed since first sleep */
	elapsed = *now;
	my_timespec_sub(&r->start, &elapsed);

	/* the average event rate that has been maintained over the
	 * lifespan of this rate-limiter.
	 */
	actual_rate = r->count / (ts_nanos(&elapsed) / (1000000000 + 0.0));

	/* simple ratio of nominal event rate and average event rate */
	ratio = r->rate / (actual_rate + 0.0);

	/* clamp this ratio to a small interval */
	if (ratio < 0.99)
		ratio = 0.99;
	if (ratio > 1.01)
		ratio = 1.01;

	/* calculate a new, adjusted rate based on this ratio */
	r->adj_rate *= ratio;

	/* calculate a new tick period based on the adjusted rate */
	const double period = 1.0 / (r->adj_rate + 0.0);
	my_timespec_from_double(period, &r->period);
}
Example #3
0
static void
print_stats(void)
{
	struct timespec dur;
	double t_dur;

	my_timespec_get(&dur);
	my_timespec_sub(&start_time, &dur);
	t_dur = my_timespec_to_double(&dur);

	fprintf(stderr,
		"%s: wrote %'" PRIu64 " entries (%'" PRIu64 " merged) "
		"in %'.2f sec, %'d ent/sec, %'d merge/sec\n",
		program_name,
		count,
		count_merged,
		t_dur,
		(int) (count / t_dur),
		(int) (count_merged / t_dur)
	);
}
Example #4
0
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;
}