queryperf.c

来自「非常好的dns解析软件」· C语言 代码 · 共 2,111 行 · 第 1/4 页

C
2,111
字号
	}}/* * process_single_response: *   Receive from the given socket & process an invididual response packet. *   Remove it from the list of open queries (status[]) and decrement the *   number of outstanding queries if it matches an open query. */voidprocess_single_response(int sockfd) {	struct sockaddr_storage from_addr_ss;	struct sockaddr *from_addr;	static unsigned char in_buf[MAX_BUFFER_LEN];	int numbytes, addr_len, resp_id;	int flags;	memset(&from_addr_ss, 0, sizeof(from_addr_ss));	from_addr = (struct sockaddr *)&from_addr_ss;	addr_len = sizeof(from_addr_ss);	if ((numbytes = recvfrom(sockfd, in_buf, MAX_BUFFER_LEN,	     0, from_addr, &addr_len)) == -1) {		fprintf(stderr, "Error receiving datagram\n");		return;	}	resp_id = get_uint16(in_buf);	flags = get_uint16(in_buf + 2);	register_response(resp_id, flags & 0xF);}/* * data_available: *   Is there data available on the given file descriptor? * *   Return TRUE if there is *   Return FALSE otherwise */intdata_available(double wait) {	fd_set read_fds;	struct timeval tv;	int retval;	int available = FALSE;	int maxfd = -1;	/* Set list of file descriptors */	FD_ZERO(&read_fds);	if (socket4 != -1) {		FD_SET(socket4, &read_fds);		maxfd = socket4;	}	if (socket6 != -1) {		FD_SET(socket6, &read_fds);		if (maxfd == -1 || maxfd < socket6)			maxfd = socket6;	}	if ((wait > 0.0) && (wait < (double)LONG_MAX)) {		tv.tv_sec = (long)floor(wait);		tv.tv_usec = (long)(1000000.0 * (wait - floor(wait)));	} else {		tv.tv_sec = 0;		tv.tv_usec = 0;	}	retval = select(maxfd + 1, &read_fds, NULL, NULL, &tv);	if (socket4 != -1 && FD_ISSET(socket4, &read_fds)) {		available = TRUE;		process_single_response(socket4);	}	if (socket6 != -1 && FD_ISSET(socket6, &read_fds)) {		available = TRUE;		process_single_response(socket6);	}	return (available);}/* * process_responses: *   Go through any/all received responses and remove them from the list of *   open queries (set in_use = FALSE for their entry in status[]), also *   decrementing the number of outstanding queries. */voidprocess_responses(int adjust_rate) {	double wait;	struct timeval now, waituntil;	double first_packet_wait = RESPONSE_BLOCKING_WAIT_TIME;	unsigned int outstanding = queries_outstanding();	if (adjust_rate == TRUE) {		double u;		u = time_of_first_query_sec +			query_interval * num_queries_sent;		waituntil.tv_sec = (long)floor(u);		waituntil.tv_usec = (long)(1000000.0 * (u - waituntil.tv_sec));		/*		 * Wait until a response arrives or the specified limit is		 * reached.		 */		while (1) {			set_timenow(&now);			wait = difftv(waituntil, now);			if (wait <= 0)				wait = 0.0;			if (data_available(wait) != TRUE)				break;			/*			 * We have reached the limit.  Read as many responses			 * as possible without waiting, and exit.			 */			if (wait == 0) {				while (data_available(0.0) == TRUE)					;				break;			}		}	} else {		/*		 * Don't block waiting for packets at all if we aren't		 * looking for any responses or if we are now able to send new		 * queries.		 */		if ((outstanding == 0) ||		    (outstanding < max_queries_outstanding)) {			first_packet_wait = 0.0;		}		if (data_available(first_packet_wait) == TRUE) {			while (data_available(0.0) == TRUE)				;		}	}}/* * retire_old_queries: *   Go through the list of open queries (status[]) and remove any queries *   (i.e. set in_use = FALSE) which are older than the timeout, decrementing *   the number of queries outstanding for each one removed. */voidretire_old_queries(int sending) {	unsigned int count = 0;	struct timeval curr_time;	double timeout = query_timeout;	int timeout_reduced = FALSE;	/*	 * If we have target qps and would not be able to send any packets	 * due to buffer full, check whether we are behind the schedule.	 * If we are, purge some queries more aggressively.	 */	if (target_qps > 0 && sending == TRUE && count == 0 &&	    queries_outstanding() == max_queries_outstanding) {		struct timeval next, now;		double n;		n = time_of_first_query_sec +			query_interval * num_queries_sent;		next.tv_sec = (long)floor(n);		next.tv_usec = (long)(1000000.0 * (n - next.tv_sec));		set_timenow(&now);		if (difftv(next, now) <= 0) {			timeout_reduced = TRUE;			timeout = 0.001; /* XXX: ad-hoc value */		}	}	set_timenow(&curr_time);	for (; count < query_status_allocated; count++) {		if ((status[count].in_use == TRUE)		    && (difftv(curr_time, status[count].sent_timestamp)		    >= (double)timeout)) {			status[count].in_use = FALSE;			num_queries_outstanding--;			num_queries_timed_out++;			num_queries_timed_out_interval++;			if (timeout_reduced == FALSE) {				if (status[count].desc) {					printf("> T %s\n", status[count].desc);					free(status[count].desc);				} else {					printf("[Timeout] Query timed out: "					       "msg id %u\n",					       status[count].id);				}			}		}	}}/* * print_histogram *   Print RTT histogram to the specified file in the gnuplot format */voidprint_histogram(unsigned int total) {	int i;	double ratio;	FILE *fp;	if (rtt_histogram_file == NULL || rttarray == NULL)		return;	fp = fopen((const char *)rtt_histogram_file, "w+");	if (fp == NULL) {		fprintf(stderr, "Error opening RTT histogram file: %s\n",			rtt_histogram_file);		return;	}	for (i = 0; i < rttarray_size; i++) {		ratio = ((double)rttarray[i] / (double)total) * 100;		fprintf(fp, "%.6lf %.3lf\n",			(double)(i * rttarray_unit) +			(double)rttarray_unit / 2,			ratio);	}	(void)fclose(fp);}/* * print_statistics: *   Print out statistics based on the results of the test */voidprint_statistics(int intermediate, unsigned int sent, unsigned int timed_out,		 unsigned int possibly_delayed,		 struct timeval *first_query,		 struct timeval *program_start,		 struct timeval *end_perf, struct timeval *end_query,		 double rmax, double rmin, double rtotal,		 unsigned int roverflows, unsigned int *rarray){	unsigned int num_queries_completed;	double per_lost, per_completed, per_lost2, per_completed2; 	double run_time, queries_per_sec, queries_per_sec2;	double queries_per_sec_total;	double rtt_average, rtt_stddev;	struct timeval start_time;	num_queries_completed = sent - timed_out;	if (num_queries_completed == 0) {		per_lost = 0.0;		per_completed = 0.0;		per_lost2 = 0.0;		per_completed2 = 0.0;	} else {		per_lost = (100.0 * (double)timed_out) / (double)sent;		per_completed = 100.0 - per_lost;		per_lost2 = (100.0 * (double)(timed_out - possibly_delayed))			/ (double)sent;		per_completed2 = 100 - per_lost2;	}	if (sent == 0) {		start_time.tv_sec = program_start->tv_sec;		start_time.tv_usec = program_start->tv_usec;		run_time = 0.0;		queries_per_sec = 0.0;		queries_per_sec2 = 0.0;		queries_per_sec_total = 0.0;	} else {		start_time.tv_sec = first_query->tv_sec;		start_time.tv_usec = first_query->tv_usec;		run_time = difftv(*end_perf, *first_query);		queries_per_sec = (double)num_queries_completed / run_time;		queries_per_sec2 = (double)(num_queries_completed +					    possibly_delayed) / run_time;		queries_per_sec_total = (double)sent /			difftv(*end_query, *first_query);	}	if (num_queries_completed > 0) {		int i;		double sum = 0;		rtt_average = rtt_total / (double)num_queries_completed;		for (i = 0; i < rttarray_size; i++) {			if (rarray[i] != 0) {				double mean, diff;				mean = (double)(i * rttarray_unit) +				(double)rttarray_unit / 2;				diff = rtt_average - (mean / 1000000.0);				sum += (diff * diff) * rarray[i];			}		}		rtt_stddev = sqrt(sum / (double)num_queries_completed);	} else {		rtt_average = 0.0;		rtt_stddev = 0.0;	}	printf("\n");	printf("%sStatistics:\n", intermediate ? "Intermediate " : "");	printf("\n");	if (!intermediate) {		printf("  Parse input file:     %s\n",		       ((run_only_once == TRUE) ? "once" : "multiple times"));		if (use_timelimit)			printf("  Run time limit:       %u seconds\n",			       run_timelimit);		if (run_only_once == FALSE)			printf("  Ran through file:     %u times\n",			       runs_through_file);		else			printf("  Ended due to:         reaching %s\n",			       ((runs_through_file == 0) ? "time limit"				: "end of file"));		printf("\n");	}	printf("  Queries sent:         %u queries\n", sent);	printf("  Queries completed:    %u queries\n", num_queries_completed);	printf("  Queries lost:         %u queries\n", timed_out);	printf("  Queries delayed(?):   %u queries\n", possibly_delayed);	printf("\n");	printf("  RTT max:         	%3.6lf sec\n", rmax);	printf("  RTT min:              %3.6lf sec\n", rmin);	printf("  RTT average:          %3.6lf sec\n", rtt_average);	printf("  RTT std deviation:    %3.6lf sec\n", rtt_stddev);	printf("  RTT out of range:     %u queries\n", roverflows);	if (!intermediate)	/* XXX should we print this case also? */		print_histogram(num_queries_completed);	printf("\n");	if (countrcodes) {		unsigned int i;		for (i = 0; i < 16; i++) {			if (rcodecounts[i] == 0)				continue;			printf("  Returned %8s:    %u queries\n",			       rcode_strings[i], rcodecounts[i]);		}		printf("\n");	}	printf("  Percentage completed: %6.2lf%%\n", per_completed);	if (possibly_delayed > 0)		printf("     (w/ delayed qrys): %6.2lf%%\n", per_completed2);	printf("  Percentage lost:      %6.2lf%%\n", per_lost);	if (possibly_delayed > 0)		printf("    (w/o delayed qrys): %6.2lf%%\n", per_lost2);	printf("\n");	printf("  Started at:           %s",	       ctime((const time_t *)&start_time.tv_sec));	printf("  Finished at:          %s",	       ctime((const time_t *)&end_perf->tv_sec));	printf("  Ran for:              %.6lf seconds\n", run_time);	printf("\n");	printf("  Queries per second:   %.6lf qps\n", queries_per_sec);	if (possibly_delayed > 0) {		printf("   (w/ delayed qrys):   %.6lf qps\n",		       queries_per_sec2);	}	if (target_qps > 0) {		printf("  Total QPS/target:     %.6lf/%d qps\n",		       queries_per_sec_total, target_qps);			}	printf("\n");}voidprint_interval_statistics() {	struct timeval time_now;	if (use_timelimit == FALSE)		return;	if (setup_phase == TRUE)		return;	if (print_interval == 0)		return;	if (timelimit_reached() == TRUE)		return;	set_timenow(&time_now);	if (difftv(time_now, time_of_first_query_interval)	    <= (double)print_interval)		return;	/* Don't count currently outstanding queries */	num_queries_sent_interval -= queries_outstanding();	print_statistics(TRUE, num_queries_sent_interval,			 num_queries_timed_out_interval,			 num_queries_possiblydelayed_interval,			 &time_of_first_query_interval,			 &time_of_first_query_interval, &time_now, &time_now,			 rtt_max_interval, rtt_min_interval,			 rtt_total_interval, rtt_overflows_interval,			 rttarray_interval);	/* Reset intermediate counters */	num_queries_sent_interval = 0;	num_queries_timed_out_interval = 0;	num_queries_possiblydelayed_interval = 0;	rtt_max_interval = -1;	rtt_min_interval = -1;	rtt_total_interval = 0.0;	rtt_overflows_interval = 0;	if (rttarray_interval != NULL) {		memset(rttarray_interval, 0,		       sizeof(rttarray_interval[0]) * rttarray_size);	}}/* * queryperf Program Mainline */intmain(int argc, char **argv) {	int adjust_rate;	int sending = FALSE;	int got_eof = FALSE;	int input_length = MAX_INPUT_LEN;	char input_line[MAX_INPUT_LEN + 1];	set_timenow(&time_of_program_start);	time_of_first_query.tv_sec = 0;	time_of_first_query.tv_usec = 0;	time_of_first_query_interval.tv_sec = 0;	time_of_first_query_interval.tv_usec = 0;	time_of_end_of_run.tv_sec = 0;	time_of_end_of_run.tv_usec = 0;	input_line[0] = '\0';	show_startup_info();	if (setup(argc, argv) == -1)		return (-1);	printf("[Status] Processing input data\n");	while ((sending = keep_sending(&got_eof)) == TRUE ||	       queries_outstanding() > 0) {		print_interval_statistics();		adjust_rate = FALSE;		while ((sending = keep_sending(&got_eof)) == TRUE &&		       queries_outstanding() < max_queries_outstanding) {			int len = next_input_line(input_line, input_length);			if (len == 0) {				got_eof = TRUE;			} else {				/* Zap the trailing newline */				if (input_line[len - 1] == '\n')					input_line[len - 1] = '\0';				/*				 * TODO: Should test if we got a whole line				 * and flush to the next \n in input if not				 * here... Add this later. Only do the next				 * few lines if we got a whole line, else				 * print a warning. Alternative: Make the				 * max line size really big. BAD! :)				 */				if (input_line[0] == CONFIG_CHAR)					update_config(input_line);				else {					send_query(input_line);					if (target_qps > 0 &&					    (num_queries_sent %					     max_queries_outstanding) == 0) {						adjust_rate = TRUE;					}				}			}		}		process_responses(adjust_rate);		retire_old_queries(sending);	}	set_timenow(&time_of_end_of_run);	printf("[Status] Testing complete\n");	close_socket();	close_datafile();	print_statistics(FALSE, num_queries_sent, num_queries_timed_out,			 num_queries_possiblydelayed,			 &time_of_first_query, &time_of_program_start,			 &time_of_end_of_run, &time_of_stop_sending,			 rtt_max, rtt_min, rtt_total, rtt_overflows, rttarray);	return (0);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?