#include #include #include #include #include #include #include "core/mainloop/throughput_logging.h" #include "lib/lock/compat_mutex.h" #include "lib/smartlist_core/smartlist_core.h" #include "lib/thread/threads.h" #include "lib/malloc/malloc.h" #include "lib/log/util_bug.h" const unsigned int timestep_ms = 500; bool throughput_logging_enabled = false; monotime_coarse_t throughput_logging_coarse_start_time; // NOTE: we don't lock these variables, so make sure they are set // before any threads have started, and that they don't change // while threads are running double throughput_logging_wall_start_time; tor_mutex_t throughput_logging_lock; smartlist_t **sent_lists = NULL; smartlist_t **recv_lists = NULL; tor_mutex_t *bytes_list_mutexes = NULL; int relay_bytes_lists_len = -1; tor_threadlocal_t thread_sent_list; tor_threadlocal_t thread_recv_list; tor_threadlocal_t thread_logging_mutex; // only call if no threads are running void init_throughput_logging(int num_threads) { tor_assert(!throughput_logging_enabled); tor_mutex_init(&throughput_logging_lock); tor_mutex_acquire(&throughput_logging_lock); relay_bytes_lists_len = num_threads; monotime_coarse_get(&throughput_logging_coarse_start_time); struct timeval ts; gettimeofday(&ts, NULL); throughput_logging_wall_start_time = ts.tv_sec+(ts.tv_usec/1000000.0); sent_lists = tor_malloc_zero(num_threads*sizeof(smartlist_t *)); recv_lists = tor_malloc_zero(num_threads*sizeof(smartlist_t *)); bytes_list_mutexes = tor_malloc_zero(num_threads*sizeof(tor_mutex_t)); for (int i=0; i= 0); tor_threadlocal_set(&thread_logging_mutex, &bytes_list_mutexes[thread_id]); tor_mutex_acquire(&bytes_list_mutexes[thread_id]); // we acquire this mutex for the lifetime of the thread, hope nobody // tries to acquire it :) tor_threadlocal_set(&thread_sent_list, sent_lists[thread_id]); tor_threadlocal_set(&thread_recv_list, recv_lists[thread_id]); tor_mutex_release(&throughput_logging_lock); } void destroy_thread_throughput_logging(void) { tor_assert(throughput_logging_enabled); tor_threadlocal_set(&thread_sent_list, NULL); tor_threadlocal_set(&thread_recv_list, NULL); tor_mutex_t *mutex = tor_threadlocal_get(&thread_logging_mutex); if (mutex != NULL) { tor_mutex_release(mutex); tor_threadlocal_set(&thread_logging_mutex, NULL); } } static void log_throughput(smartlist_t *list, uint32_t bytes, monotime_coarse_t *time) { tor_assert(throughput_logging_enabled); int64_t ms_since_start = monotime_coarse_diff_msec(&throughput_logging_coarse_start_time, time); int list_index = ms_since_start/timestep_ms; if (list_index >= smartlist_len(list)) { // need to grow the list int additional_elements = (60000-1)/timestep_ms + 1; // want an extra 60 seconds, and we want the ceil int new_size = (list_index+1)+additional_elements; // want enough room to store the current value, plus an extra 60 seconds smartlist_grow(list, new_size); } uint32_t old_bytes = (intptr_t)smartlist_get(list, list_index); uint32_t new_bytes = old_bytes+bytes; if (new_bytes < old_bytes) { new_bytes = UINT32_MAX; } smartlist_set(list, list_index, (void *)(intptr_t)new_bytes); } void log_sent_bytes(uint32_t bytes, monotime_coarse_t *now) { if (bytes > 0 && throughput_logging_enabled) { smartlist_t *sent_list = tor_threadlocal_get(&thread_sent_list); tor_assert(sent_list != NULL); log_throughput(sent_list, bytes, now); } } void log_recv_bytes(uint32_t bytes, monotime_coarse_t *now) { if (bytes > 0 && throughput_logging_enabled) { smartlist_t *recv_list = tor_threadlocal_get(&thread_recv_list); tor_assert(recv_list != NULL); log_throughput(recv_list, bytes, now); } } // only run this function when the threads have finished void write_throughput_log(char *file_name) { if (!throughput_logging_enabled) { log_warn(LD_CONFIG, "Throughput logging was not set up, so didn't write to log file"); return; } tor_mutex_acquire(&throughput_logging_lock); if (file_name == NULL || strlen(file_name) == 0) { log_warn(LD_CONFIG, "Was not given a file name for the throughput log"); tor_mutex_release(&throughput_logging_lock); return; } FILE *log_file = fopen(file_name, "w"); if (log_file == NULL) { log_warn(LD_CONFIG, "Could not open throughput log file %s", file_name); tor_mutex_release(&throughput_logging_lock); return; } for (int i=0; i