|
@@ -2576,3 +2576,174 @@ hs_usage_write_statistics_to_file(time_t now)
|
|
|
tor_free(fname);
|
|
|
}
|
|
|
|
|
|
+/*** cell statistics ***/
|
|
|
+
|
|
|
+#ifdef ENABLE_BUFFER_STATS
|
|
|
+/** Start of the current buffer stats interval. */
|
|
|
+time_t start_of_buffer_stats_interval;
|
|
|
+
|
|
|
+typedef struct circ_buffer_stats_t {
|
|
|
+ uint32_t processed_cells;
|
|
|
+ double mean_num_cells_in_queue;
|
|
|
+ double mean_time_cells_in_queue;
|
|
|
+ uint32_t local_circ_id;
|
|
|
+} circ_buffer_stats_t;
|
|
|
+
|
|
|
+/** Holds stats. */
|
|
|
+smartlist_t *circuits_for_buffer_stats = NULL;
|
|
|
+
|
|
|
+/** Remember cell statistics for circuit <b>circ</b> at time
|
|
|
+ * <b>end_of_interval</b> and reset cell counters in case the circuit
|
|
|
+ * remains open in the next measurement interval. */
|
|
|
+void
|
|
|
+add_circ_to_buffer_stats(circuit_t *circ, time_t end_of_interval)
|
|
|
+{
|
|
|
+ circ_buffer_stats_t *stat;
|
|
|
+ time_t start_of_interval;
|
|
|
+ int interval_length;
|
|
|
+ or_circuit_t *orcirc;
|
|
|
+ if (CIRCUIT_IS_ORIGIN(circ))
|
|
|
+ return;
|
|
|
+ orcirc = TO_OR_CIRCUIT(circ);
|
|
|
+ if (!orcirc->processed_cells)
|
|
|
+ return;
|
|
|
+ if (!circuits_for_buffer_stats)
|
|
|
+ circuits_for_buffer_stats = smartlist_create();
|
|
|
+ start_of_interval = circ->timestamp_created >
|
|
|
+ start_of_buffer_stats_interval ?
|
|
|
+ circ->timestamp_created :
|
|
|
+ start_of_buffer_stats_interval;
|
|
|
+ interval_length = (int) (end_of_interval - start_of_interval);
|
|
|
+ stat = tor_malloc_zero(sizeof(circ_buffer_stats_t));
|
|
|
+ stat->processed_cells = orcirc->processed_cells;
|
|
|
+ /* 1000.0 for s -> ms; 2.0 because of app-ward and exit-ward queues */
|
|
|
+ stat->mean_num_cells_in_queue = interval_length == 0 ? 0.0 :
|
|
|
+ (double) orcirc->total_cell_waiting_time /
|
|
|
+ (double) interval_length / 1000.0 / 2.0;
|
|
|
+ stat->mean_time_cells_in_queue =
|
|
|
+ (double) orcirc->total_cell_waiting_time /
|
|
|
+ (double) orcirc->processed_cells;
|
|
|
+ smartlist_add(circuits_for_buffer_stats, stat);
|
|
|
+ orcirc->total_cell_waiting_time = 0;
|
|
|
+ orcirc->processed_cells = 0;
|
|
|
+}
|
|
|
+
|
|
|
+/** Sorting helper: return -1, 1, or 0 based on comparison of two
|
|
|
+ * circ_buffer_stats_t */
|
|
|
+static int
|
|
|
+_buffer_stats_compare_entries(const void **_a, const void **_b)
|
|
|
+{
|
|
|
+ const circ_buffer_stats_t *a = *_a, *b = *_b;
|
|
|
+ if (a->processed_cells < b->processed_cells)
|
|
|
+ return 1;
|
|
|
+ else if (a->processed_cells > b->processed_cells)
|
|
|
+ return -1;
|
|
|
+ else
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/** Append buffer statistics to local file. */
|
|
|
+void
|
|
|
+dump_buffer_stats(void)
|
|
|
+{
|
|
|
+ time_t now = time(NULL);
|
|
|
+ char *filename;
|
|
|
+ char written[ISO_TIME_LEN+1];
|
|
|
+ open_file_t *open_file = NULL;
|
|
|
+ FILE *out;
|
|
|
+#define SHARES 10
|
|
|
+ int processed_cells[SHARES], circs_in_share[SHARES],
|
|
|
+ number_of_circuits, i;
|
|
|
+ double queued_cells[SHARES], time_in_queue[SHARES];
|
|
|
+ smartlist_t *str_build = smartlist_create();
|
|
|
+ char *str = NULL;
|
|
|
+ char buf[32];
|
|
|
+ circuit_t *circ;
|
|
|
+ /* add current circuits to stats */
|
|
|
+ for (circ = _circuit_get_global_list(); circ; circ = circ->next)
|
|
|
+ add_circ_to_buffer_stats(circ, now);
|
|
|
+ /* calculate deciles */
|
|
|
+ memset(processed_cells, 0, SHARES * sizeof(int));
|
|
|
+ memset(circs_in_share, 0, SHARES * sizeof(int));
|
|
|
+ memset(queued_cells, 0, SHARES * sizeof(double));
|
|
|
+ memset(time_in_queue, 0, SHARES * sizeof(double));
|
|
|
+ smartlist_sort(circuits_for_buffer_stats,
|
|
|
+ _buffer_stats_compare_entries);
|
|
|
+ number_of_circuits = smartlist_len(circuits_for_buffer_stats);
|
|
|
+ i = 0;
|
|
|
+ SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats,
|
|
|
+ circ_buffer_stats_t *, stat)
|
|
|
+ {
|
|
|
+ int share = i++ * SHARES / number_of_circuits;
|
|
|
+ processed_cells[share] += stat->processed_cells;
|
|
|
+ queued_cells[share] += stat->mean_num_cells_in_queue;
|
|
|
+ time_in_queue[share] += stat->mean_time_cells_in_queue;
|
|
|
+ circs_in_share[share]++;
|
|
|
+ }
|
|
|
+ SMARTLIST_FOREACH_END(stat);
|
|
|
+ /* clear buffer stats history */
|
|
|
+ SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *,
|
|
|
+ stat, tor_free(stat));
|
|
|
+ smartlist_clear(circuits_for_buffer_stats);
|
|
|
+ /* write to file */
|
|
|
+ filename = get_datadir_fname("buffer-stats");
|
|
|
+ out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND,
|
|
|
+ 0600, &open_file);
|
|
|
+ if (!out)
|
|
|
+ goto done;
|
|
|
+ format_iso_time(written, now);
|
|
|
+ if (fprintf(out, "written %s (%d s)\n", written,
|
|
|
+ DUMP_BUFFER_STATS_INTERVAL) < 0)
|
|
|
+ goto done;
|
|
|
+ for (i = 0; i < SHARES; i++) {
|
|
|
+ tor_snprintf(buf, sizeof(buf), "%d", !circs_in_share[i] ? 0 :
|
|
|
+ processed_cells[i] / circs_in_share[i]);
|
|
|
+ smartlist_add(str_build, tor_strdup(buf));
|
|
|
+ }
|
|
|
+ str = smartlist_join_strings(str_build, ",", 0, NULL);
|
|
|
+ if (fprintf(out, "processed-cells %s\n", str) < 0)
|
|
|
+ goto done;
|
|
|
+ tor_free(str);
|
|
|
+ SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
|
|
|
+ smartlist_clear(str_build);
|
|
|
+ for (i = 0; i < SHARES; i++) {
|
|
|
+ tor_snprintf(buf, sizeof(buf), "%.2f", circs_in_share[i] == 0 ? 0.0 :
|
|
|
+ queued_cells[i] / (double) circs_in_share[i]);
|
|
|
+ smartlist_add(str_build, tor_strdup(buf));
|
|
|
+ }
|
|
|
+ str = smartlist_join_strings(str_build, ",", 0, NULL);
|
|
|
+ if (fprintf(out, "queued-cells %s\n", str) < 0)
|
|
|
+ goto done;
|
|
|
+ tor_free(str);
|
|
|
+ SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
|
|
|
+ smartlist_clear(str_build);
|
|
|
+ for (i = 0; i < SHARES; i++) {
|
|
|
+ tor_snprintf(buf, sizeof(buf), "%.0f", circs_in_share[i] == 0 ? 0.0 :
|
|
|
+ time_in_queue[i] / (double) circs_in_share[i]);
|
|
|
+ smartlist_add(str_build, tor_strdup(buf));
|
|
|
+ }
|
|
|
+ str = smartlist_join_strings(str_build, ",", 0, NULL);
|
|
|
+ if (fprintf(out, "time-in-queue %s\n", str) < 0)
|
|
|
+ goto done;
|
|
|
+ tor_free(str);
|
|
|
+ SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
|
|
|
+ smartlist_free(str_build);
|
|
|
+ str_build = NULL;
|
|
|
+ if (fprintf(out, "number-of-circuits-per-share %d\n",
|
|
|
+ (number_of_circuits + SHARES - 1) / SHARES) < 0)
|
|
|
+ goto done;
|
|
|
+ finish_writing_to_file(open_file);
|
|
|
+ open_file = NULL;
|
|
|
+ done:
|
|
|
+ if (open_file)
|
|
|
+ abort_writing_to_file(open_file);
|
|
|
+ tor_free(filename);
|
|
|
+ if (str_build) {
|
|
|
+ SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
|
|
|
+ smartlist_free(str_build);
|
|
|
+ }
|
|
|
+ tor_free(str);
|
|
|
+#undef SHARES
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|