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 + -
显示快捷键?