23 #ifdef GRPC_BASIC_PROFILER
39 typedef enum { BEGIN =
'{', END =
'}', MARK =
'.' } marker_type;
41 typedef struct gpr_timer_entry {
51 #define MAX_COUNT 1000000
53 typedef struct gpr_timer_log {
55 struct gpr_timer_log*
next;
56 struct gpr_timer_log* prev;
57 gpr_timer_entry
log[MAX_COUNT];
60 typedef struct gpr_timer_log_list {
68 static FILE* output_file;
69 static const char* output_filename_or_null = NULL;
70 static pthread_mutex_t
g_mu;
71 static pthread_cond_t
g_cv;
72 static gpr_timer_log_list g_in_progress_logs;
73 static gpr_timer_log_list g_done_logs;
75 static pthread_t g_writing_thread;
77 static int g_next_thread_id;
78 static int g_writing_enabled = 1;
81 "Output file name for latency trace")
83 static
const char* output_filename() {
84 if (output_filename_or_null == NULL) {
87 if (strlen(
value.get()) > 0) {
88 output_filename_or_null =
value.release();
90 output_filename_or_null =
"latency_trace.txt";
93 return output_filename_or_null;
96 static int timer_log_push_back(gpr_timer_log_list* list, gpr_timer_log*
log) {
97 if (list->head == NULL) {
98 list->head = list->tail =
log;
99 log->next =
log->prev = NULL;
102 log->prev = list->tail;
104 list->tail->next =
log;
110 static gpr_timer_log* timer_log_pop_front(gpr_timer_log_list* list) {
111 gpr_timer_log*
out = list->head;
113 list->head =
out->next;
114 if (list->head != NULL) {
115 list->head->prev = NULL;
123 static void timer_log_remove(gpr_timer_log_list* list, gpr_timer_log*
log) {
124 if (
log->prev == NULL) {
125 list->head =
log->next;
126 if (list->head != NULL) {
127 list->head->prev = NULL;
130 log->prev->next =
log->next;
132 if (
log->next == NULL) {
133 list->tail =
log->prev;
134 if (list->tail != NULL) {
135 list->tail->next = NULL;
138 log->next->prev =
log->prev;
142 static void write_log(gpr_timer_log*
log) {
144 if (output_file == NULL) {
145 output_file = fopen(output_filename(),
"w");
147 for (
i = 0;
i <
log->num_entries;
i++) {
148 gpr_timer_entry* entry = &(
log->log[
i]);
154 ".%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
155 "\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n",
156 entry->tm.tv_sec, entry->tm.tv_nsec, entry->thd, entry->type,
157 entry->tagstr, entry->file, entry->line, entry->important);
161 static void* writing_thread(
void* unused) {
163 pthread_mutex_lock(&
g_mu);
165 while ((
log = timer_log_pop_front(&g_done_logs)) == NULL && !
g_shutdown) {
169 pthread_mutex_unlock(&
g_mu);
172 pthread_mutex_lock(&
g_mu);
175 pthread_mutex_unlock(&
g_mu);
181 static void flush_logs(gpr_timer_log_list* list) {
183 while ((
log = timer_log_pop_front(list)) != NULL) {
189 static void finish_writing(
void) {
190 pthread_mutex_lock(&
g_mu);
192 pthread_cond_signal(&
g_cv);
193 pthread_mutex_unlock(&
g_mu);
194 pthread_join(g_writing_thread, NULL);
198 pthread_mutex_lock(&
g_mu);
199 flush_logs(&g_done_logs);
200 flush_logs(&g_in_progress_logs);
201 pthread_mutex_unlock(&
g_mu);
212 static void init_output() {
214 pthread_attr_init(&
attr);
215 pthread_attr_setdetachstate(&
attr, PTHREAD_CREATE_JOINABLE);
216 pthread_create(&g_writing_thread, &
attr, &writing_thread, NULL);
217 pthread_attr_destroy(&
attr);
219 atexit(finish_writing);
222 static void rotate_log() {
224 gpr_timer_log*
log =
static_cast<gpr_timer_log*
>(malloc(
sizeof(*
log)));
226 log->num_entries = 0;
227 pthread_mutex_lock(&
g_mu);
228 if (g_thread_log != NULL) {
229 timer_log_remove(&g_in_progress_logs, g_thread_log);
230 if (timer_log_push_back(&g_done_logs, g_thread_log)) {
231 pthread_cond_signal(&
g_cv);
234 g_thread_id = g_next_thread_id++;
236 timer_log_push_back(&g_in_progress_logs,
log);
237 pthread_mutex_unlock(&
g_mu);
241 static void gpr_timers_log_add(
const char* tagstr, marker_type
type,
242 int important,
const char*
file,
int line) {
243 gpr_timer_entry* entry;
245 if (!g_writing_enabled) {
249 if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) {
253 entry = &g_thread_log->log[g_thread_log->num_entries++];
256 entry->tagstr = tagstr;
259 entry->line = (short)
line;
260 entry->important = important != 0;
261 entry->thd = g_thread_id;
267 gpr_timers_log_add(tagstr, MARK, important,
file,
line);
272 gpr_timers_log_add(tagstr, BEGIN, important,
file,
line);
277 gpr_timers_log_add(tagstr, END, important,
file,
line);