basic_timers.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
20 
22 
23 #ifdef GRPC_BASIC_PROFILER
24 
25 #include <inttypes.h>
26 #include <pthread.h>
27 #include <stdio.h>
28 #include <string.h>
29 
30 #include <grpc/support/alloc.h>
31 #include <grpc/support/log.h>
32 #include <grpc/support/sync.h>
33 #include <grpc/support/time.h>
34 
35 #include "src/core/lib/gpr/tls.h"
38 
39 typedef enum { BEGIN = '{', END = '}', MARK = '.' } marker_type;
40 
41 typedef struct gpr_timer_entry {
43  const char* tagstr;
44  const char* file;
45  short line;
46  char type;
47  uint8_t important;
48  int thd;
49 } gpr_timer_entry;
50 
51 #define MAX_COUNT 1000000
52 
53 typedef struct gpr_timer_log {
54  size_t num_entries;
55  struct gpr_timer_log* next;
56  struct gpr_timer_log* prev;
57  gpr_timer_entry log[MAX_COUNT];
58 } gpr_timer_log;
59 
60 typedef struct gpr_timer_log_list {
61  gpr_timer_log* head;
62  /* valid iff head!=NULL */
63  gpr_timer_log* tail;
64 } gpr_timer_log_list;
65 
66 static GPR_THREAD_LOCAL(gpr_timer_log*) g_thread_log;
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;
74 static int g_shutdown;
75 static pthread_t g_writing_thread;
76 static GPR_THREAD_LOCAL(int) g_thread_id;
77 static int g_next_thread_id;
78 static int g_writing_enabled = 1;
79 
80 GPR_GLOBAL_CONFIG_DEFINE_STRING(grpc_latency_trace, "latency_trace.txt",
81  "Output file name for latency trace")
82 
83 static const char* output_filename() {
84  if (output_filename_or_null == NULL) {
86  GPR_GLOBAL_CONFIG_GET(grpc_latency_trace);
87  if (strlen(value.get()) > 0) {
88  output_filename_or_null = value.release();
89  } else {
90  output_filename_or_null = "latency_trace.txt";
91  }
92  }
93  return output_filename_or_null;
94 }
95 
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;
100  return 1;
101  } else {
102  log->prev = list->tail;
103  log->next = NULL;
104  list->tail->next = log;
105  list->tail = log;
106  return 0;
107  }
108 }
109 
110 static gpr_timer_log* timer_log_pop_front(gpr_timer_log_list* list) {
111  gpr_timer_log* out = list->head;
112  if (out != NULL) {
113  list->head = out->next;
114  if (list->head != NULL) {
115  list->head->prev = NULL;
116  } else {
117  list->tail = NULL;
118  }
119  }
120  return out;
121 }
122 
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;
128  }
129  } else {
130  log->prev->next = log->next;
131  }
132  if (log->next == NULL) {
133  list->tail = log->prev;
134  if (list->tail != NULL) {
135  list->tail->next = NULL;
136  }
137  } else {
138  log->next->prev = log->prev;
139  }
140 }
141 
142 static void write_log(gpr_timer_log* log) {
143  size_t i;
144  if (output_file == NULL) {
145  output_file = fopen(output_filename(), "w");
146  }
147  for (i = 0; i < log->num_entries; i++) {
148  gpr_timer_entry* entry = &(log->log[i]);
149  if (gpr_time_cmp(entry->tm, gpr_time_0(entry->tm.clock_type)) < 0) {
150  entry->tm = gpr_time_0(entry->tm.clock_type);
151  }
152  fprintf(output_file,
153  "{\"t\": %" PRId64
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);
158  }
159 }
160 
161 static void* writing_thread(void* unused) {
162  gpr_timer_log* log;
163  pthread_mutex_lock(&g_mu);
164  for (;;) {
165  while ((log = timer_log_pop_front(&g_done_logs)) == NULL && !g_shutdown) {
166  pthread_cond_wait(&g_cv, &g_mu);
167  }
168  if (log != NULL) {
169  pthread_mutex_unlock(&g_mu);
170  write_log(log);
171  free(log);
172  pthread_mutex_lock(&g_mu);
173  }
174  if (g_shutdown) {
175  pthread_mutex_unlock(&g_mu);
176  return NULL;
177  }
178  }
179 }
180 
181 static void flush_logs(gpr_timer_log_list* list) {
182  gpr_timer_log* log;
183  while ((log = timer_log_pop_front(list)) != NULL) {
184  write_log(log);
185  free(log);
186  }
187 }
188 
189 static void finish_writing(void) {
190  pthread_mutex_lock(&g_mu);
191  g_shutdown = 1;
192  pthread_cond_signal(&g_cv);
193  pthread_mutex_unlock(&g_mu);
194  pthread_join(g_writing_thread, NULL);
195 
196  gpr_log(GPR_INFO, "flushing logs");
197 
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);
202 
203  if (output_file) {
204  fclose(output_file);
205  }
206 }
207 
208 void gpr_timers_set_log_filename(const char* filename) {
209  output_filename_or_null = filename;
210 }
211 
212 static void init_output() {
213  pthread_attr_t attr;
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);
218 
219  atexit(finish_writing);
220 }
221 
222 static void rotate_log() {
223  /* Using malloc here, as this code could end up being called by gpr_malloc */
224  gpr_timer_log* log = static_cast<gpr_timer_log*>(malloc(sizeof(*log)));
225  gpr_once_init(&g_once_init, init_output);
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);
232  }
233  } else {
234  g_thread_id = g_next_thread_id++;
235  }
236  timer_log_push_back(&g_in_progress_logs, log);
237  pthread_mutex_unlock(&g_mu);
238  g_thread_log = log;
239 }
240 
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;
244 
245  if (!g_writing_enabled) {
246  return;
247  }
248 
249  if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) {
250  rotate_log();
251  }
252 
253  entry = &g_thread_log->log[g_thread_log->num_entries++];
254 
255  entry->tm = gpr_now(GPR_CLOCK_PRECISE);
256  entry->tagstr = tagstr;
257  entry->type = type;
258  entry->file = file;
259  entry->line = (short)line;
260  entry->important = important != 0;
261  entry->thd = g_thread_id;
262 }
263 
264 /* Latency profiler API implementation. */
265 void gpr_timer_add_mark(const char* tagstr, int important, const char* file,
266  int line) {
267  gpr_timers_log_add(tagstr, MARK, important, file, line);
268 }
269 
270 void gpr_timer_begin(const char* tagstr, int important, const char* file,
271  int line) {
272  gpr_timers_log_add(tagstr, BEGIN, important, file, line);
273 }
274 
275 void gpr_timer_end(const char* tagstr, int important, const char* file,
276  int line) {
277  gpr_timers_log_add(tagstr, END, important, file, line);
278 }
279 
280 void gpr_timer_set_enabled(int enabled) { g_writing_enabled = enabled; }
281 
282 /* Basic profiler specific API functions. */
283 void gpr_timers_global_init(void) {}
284 
285 void gpr_timers_global_destroy(void) {}
286 
287 #else /* !GRPC_BASIC_PROFILER */
289 
291 
292 void gpr_timers_set_log_filename(const char* /*filename*/) {}
293 
294 void gpr_timer_set_enabled(int /*enabled*/) {}
295 #endif /* GRPC_BASIC_PROFILER */
GPR_INFO
#define GPR_INFO
Definition: include/grpc/impl/codegen/log.h:56
filename
const char * filename
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
log.h
const
#define const
Definition: bloaty/third_party/zlib/zconf.h:230
file
const grpc_generator::File * file
Definition: python_private_generator.h:38
timers.h
gpr_once
pthread_once_t gpr_once
Definition: impl/codegen/sync_posix.h:50
GPR_GLOBAL_CONFIG_GET
#define GPR_GLOBAL_CONFIG_GET(name)
Definition: global_config_generic.h:24
gpr_timers_global_destroy
void gpr_timers_global_destroy(void)
Definition: basic_timers.cc:290
gpr_time_0
GPRAPI gpr_timespec gpr_time_0(gpr_clock_type type)
Definition: src/core/lib/gpr/time.cc:47
string.h
file
Definition: bloaty/third_party/zlib/examples/gzappend.c:170
GPR_ONCE_INIT
#define GPR_ONCE_INIT
Definition: impl/codegen/sync_posix.h:52
time.h
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
g_cv
static gpr_cv g_cv
Definition: bm_cq_multiple_threads.cc:42
gpr_once_init
GPRAPI void gpr_once_init(gpr_once *once, void(*init_function)(void))
g_shutdown
static int g_shutdown
Definition: iomgr.cc:57
gpr_timers_set_log_filename
void gpr_timers_set_log_filename(const char *)
Definition: basic_timers.cc:292
gpr_time_cmp
GPRAPI int gpr_time_cmp(gpr_timespec a, gpr_timespec b)
Definition: src/core/lib/gpr/time.cc:30
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
gpr_timer_set_enabled
void gpr_timer_set_enabled(int)
Definition: basic_timers.cc:294
GPR_THREAD_LOCAL
#define GPR_THREAD_LOCAL(type)
Definition: tls.h:151
log
Definition: bloaty/third_party/zlib/examples/gzlog.c:289
gpr_now
GPRAPI gpr_timespec gpr_now(gpr_clock_type clock)
grpc_core::UniquePtr
std::unique_ptr< T, DefaultDeleteChar > UniquePtr
Definition: src/core/lib/gprpp/memory.h:43
gpr_timer_end
void gpr_timer_end(const char *tagstr, int important, const char *file, int line)
tm
static uv_timer_t tm
Definition: test-tcp-open.c:41
value
const char * value
Definition: hpack_parser_table.cc:165
GPR_CLOCK_PRECISE
@ GPR_CLOCK_PRECISE
Definition: gpr_types.h:42
g_mu
static gpr_mu g_mu
Definition: iomgr.cc:55
attr
OPENSSL_EXPORT X509_ATTRIBUTE * attr
Definition: x509.h:1666
global_config.h
benchmark.FILE
FILE
Definition: benchmark.py:21
grpc::fclose
fclose(creds_file)
GPR_GLOBAL_CONFIG_DEFINE_STRING
#define GPR_GLOBAL_CONFIG_DEFINE_STRING(name, default_value, help)
Definition: global_config_env.h:122
alloc.h
next
AllocList * next[kMaxLevel]
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:100
regen-readme.line
line
Definition: regen-readme.py:30
tls.h
log
bool log
Definition: abseil-cpp/absl/synchronization/mutex.cc:310
gpr_timer_add_mark
void gpr_timer_add_mark(const char *tagstr, int important, const char *file, int line)
gpr_timer_begin
void gpr_timer_begin(const char *tagstr, int important, const char *file, int line)
profile_analyzer.thd
thd
Definition: profile_analyzer.py:168
g_once_init
static gpr_once g_once_init
Definition: rb_grpc.c:259
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
gpr_timespec
Definition: gpr_types.h:50
sync.h
gpr_timers_global_init
void gpr_timers_global_init(void)
Definition: basic_timers.cc:288
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
port_platform.h


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:45