|
@@ -1943,9 +1943,8 @@ dump_pk_ops(int severity)
|
|
|
#define EXIT_STATS_ROUND_UP_STREAMS 4
|
|
|
|
|
|
#define EXIT_STATS_NUM_PORTS 65536
|
|
|
-
|
|
|
- * see in order to be included in exit stats. */
|
|
|
-#define EXIT_STATS_THRESHOLD_RECIPROCAL 10000
|
|
|
+
|
|
|
+#define EXIT_STATS_TOP_N_PORTS 10
|
|
|
|
|
|
|
|
|
* so that all write operations can be done in constant time. This comes at
|
|
@@ -1995,15 +1994,23 @@ rep_hist_exit_stats_term(void)
|
|
|
tor_free(exit_streams);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+static int
|
|
|
+_compare_int(const void *x, const void *y) {
|
|
|
+ return (*(int*)x - *(int*)y);
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
* until <b>now</b>, or NULL if we're not collecting exit stats. */
|
|
|
char *
|
|
|
rep_hist_format_exit_stats(time_t now)
|
|
|
{
|
|
|
- int i;
|
|
|
- uint64_t total_bytes = 0, threshold_bytes, other_read = 0,
|
|
|
- other_written = 0;
|
|
|
- uint32_t other_streams = 0;
|
|
|
+ int i, j, top_elements = 0, cur_min_idx = 0, cur_port;
|
|
|
+ uint64_t top_bytes[EXIT_STATS_TOP_N_PORTS];
|
|
|
+ int top_ports[EXIT_STATS_TOP_N_PORTS];
|
|
|
+ uint64_t cur_bytes = 0, other_read = 0, other_written = 0,
|
|
|
+ total_read = 0, total_written = 0;
|
|
|
+ uint32_t total_streams = 0, other_streams = 0;
|
|
|
char *buf;
|
|
|
smartlist_t *written_strings, *read_strings, *streams_strings;
|
|
|
char *written_string, *read_string, *streams_string;
|
|
@@ -2013,52 +2020,75 @@ rep_hist_format_exit_stats(time_t now)
|
|
|
if (!start_of_exit_stats_interval)
|
|
|
return NULL;
|
|
|
|
|
|
-
|
|
|
- * below or equal to a threshold of 1 / EXIT_STATS_THRESHOLD_RECIPROCAL
|
|
|
- * of all bytes to a special port 'other'. */
|
|
|
+
|
|
|
+ * read bytes. */
|
|
|
for (i = 1; i < EXIT_STATS_NUM_PORTS; i++) {
|
|
|
- total_bytes += exit_bytes_read[i];
|
|
|
- total_bytes += exit_bytes_written[i];
|
|
|
+ total_read += exit_bytes_read[i];
|
|
|
+ total_written += exit_bytes_written[i];
|
|
|
+ total_streams += exit_streams[i];
|
|
|
+ cur_bytes = exit_bytes_read[i] + exit_bytes_written[i];
|
|
|
+ if (cur_bytes == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (top_elements < EXIT_STATS_TOP_N_PORTS) {
|
|
|
+ top_bytes[top_elements] = cur_bytes;
|
|
|
+ top_ports[top_elements++] = i;
|
|
|
+ } else if (cur_bytes > top_bytes[cur_min_idx]) {
|
|
|
+ top_bytes[cur_min_idx] = cur_bytes;
|
|
|
+ top_ports[cur_min_idx] = i;
|
|
|
+ } else {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ cur_min_idx = 0;
|
|
|
+ for (j = 1; j < top_elements; j++) {
|
|
|
+ if (top_bytes[j] < top_bytes[cur_min_idx]) {
|
|
|
+ cur_min_idx = j;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- threshold_bytes = total_bytes / EXIT_STATS_THRESHOLD_RECIPROCAL;
|
|
|
|
|
|
-
|
|
|
- * join them to single strings. Also count bytes and streams of ports
|
|
|
- * below or equal to the threshold. */
|
|
|
+
|
|
|
written_strings = smartlist_create();
|
|
|
read_strings = smartlist_create();
|
|
|
streams_strings = smartlist_create();
|
|
|
- for (i = 1; i < EXIT_STATS_NUM_PORTS; i++) {
|
|
|
- if (exit_bytes_read[i] + exit_bytes_written[i] > threshold_bytes) {
|
|
|
- if (exit_bytes_written[i] > 0) {
|
|
|
- uint64_t num = round_uint64_to_next_multiple_of(
|
|
|
- exit_bytes_written[i], EXIT_STATS_ROUND_UP_BYTES);
|
|
|
- num /= 1024;
|
|
|
- buf = NULL;
|
|
|
- tor_asprintf(&buf, "%d="U64_FORMAT, i, U64_PRINTF_ARG(num));
|
|
|
- smartlist_add(written_strings, buf);
|
|
|
- }
|
|
|
- if (exit_bytes_read[i] > 0) {
|
|
|
- uint64_t num = round_uint64_to_next_multiple_of(
|
|
|
- exit_bytes_read[i], EXIT_STATS_ROUND_UP_BYTES);
|
|
|
- num /= 1024;
|
|
|
- buf = NULL;
|
|
|
- tor_asprintf(&buf, "%d="U64_FORMAT, i, U64_PRINTF_ARG(num));
|
|
|
- smartlist_add(read_strings, buf);
|
|
|
- }
|
|
|
- if (exit_streams[i] > 0) {
|
|
|
- uint32_t num = round_uint32_to_next_multiple_of(exit_streams[i],
|
|
|
- EXIT_STATS_ROUND_UP_STREAMS);
|
|
|
- buf = NULL;
|
|
|
- tor_asprintf(&buf, "%d=%u", i, num);
|
|
|
- smartlist_add(streams_strings, buf);
|
|
|
- }
|
|
|
- } else {
|
|
|
- other_read += exit_bytes_read[i];
|
|
|
- other_written += exit_bytes_written[i];
|
|
|
- other_streams += exit_streams[i];
|
|
|
+ other_read = total_read;
|
|
|
+ other_written = total_written;
|
|
|
+ other_streams = total_streams;
|
|
|
+ qsort(top_ports, top_elements, sizeof(int), _compare_int);
|
|
|
+ for (j = 0; j < top_elements; j++) {
|
|
|
+ cur_port = top_ports[j];
|
|
|
+ if (exit_bytes_written[cur_port] > 0) {
|
|
|
+ uint64_t num = round_uint64_to_next_multiple_of(
|
|
|
+ exit_bytes_written[cur_port],
|
|
|
+ EXIT_STATS_ROUND_UP_BYTES);
|
|
|
+ num /= 1024;
|
|
|
+ buf = NULL;
|
|
|
+ tor_asprintf(&buf, "%d="U64_FORMAT, cur_port, U64_PRINTF_ARG(num));
|
|
|
+ smartlist_add(written_strings, buf);
|
|
|
+ other_written -= exit_bytes_written[cur_port];
|
|
|
+ }
|
|
|
+ if (exit_bytes_read[cur_port] > 0) {
|
|
|
+ uint64_t num = round_uint64_to_next_multiple_of(
|
|
|
+ exit_bytes_read[cur_port],
|
|
|
+ EXIT_STATS_ROUND_UP_BYTES);
|
|
|
+ num /= 1024;
|
|
|
+ buf = NULL;
|
|
|
+ tor_asprintf(&buf, "%d="U64_FORMAT, cur_port, U64_PRINTF_ARG(num));
|
|
|
+ smartlist_add(read_strings, buf);
|
|
|
+ other_read -= exit_bytes_read[cur_port];
|
|
|
+ }
|
|
|
+ if (exit_streams[cur_port] > 0) {
|
|
|
+ uint32_t num = round_uint32_to_next_multiple_of(
|
|
|
+ exit_streams[cur_port],
|
|
|
+ EXIT_STATS_ROUND_UP_STREAMS);
|
|
|
+ buf = NULL;
|
|
|
+ tor_asprintf(&buf, "%d=%u", cur_port, num);
|
|
|
+ smartlist_add(streams_strings, buf);
|
|
|
+ other_streams -= exit_streams[cur_port];
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
other_written = round_uint64_to_next_multiple_of(other_written,
|
|
|
EXIT_STATS_ROUND_UP_BYTES);
|
|
|
other_written /= 1024;
|
|
@@ -2076,6 +2106,8 @@ rep_hist_format_exit_stats(time_t now)
|
|
|
buf = NULL;
|
|
|
tor_asprintf(&buf, "other=%u", other_streams);
|
|
|
smartlist_add(streams_strings, buf);
|
|
|
+
|
|
|
+
|
|
|
written_string = smartlist_join_strings(written_strings, ",", 0, NULL);
|
|
|
read_string = smartlist_join_strings(read_strings, ",", 0, NULL);
|
|
|
streams_string = smartlist_join_strings(streams_strings, ",", 0, NULL);
|