void w_perf_log(w_perf_t *perf) { json_t *info; char *dumped = NULL; if (!perf->will_log) { return; } // Assemble a perf blob info = json_pack("{s:u, s:O, s:i, s:u}", // "description", perf->description, // "meta", perf->meta_data, // "pid", getpid(), // "version", PACKAGE_VERSION // ); #ifdef WATCHMAN_BUILD_INFO set_unicode_prop(info, "buildinfo", WATCHMAN_BUILD_INFO); #endif #define ADDTV(name, tv) \ set_prop(info, name, json_real(w_timeval_abs_seconds(tv))) ADDTV("elapsed_time", perf->duration); ADDTV("start_time", perf->time_begin); #ifdef HAVE_SYS_RESOURCE_H ADDTV("user_time", perf->usage.ru_utime); ADDTV("system_time", perf->usage.ru_stime); #define ADDU(n) set_prop(info, #n, json_integer(perf->usage.n)) ADDU(ru_maxrss); ADDU(ru_ixrss); ADDU(ru_idrss); ADDU(ru_minflt); ADDU(ru_majflt); ADDU(ru_nswap); ADDU(ru_inblock); ADDU(ru_oublock); ADDU(ru_msgsnd); ADDU(ru_msgrcv); ADDU(ru_nsignals); ADDU(ru_nvcsw); ADDU(ru_nivcsw); #endif // HAVE_SYS_RESOURCE_H #undef ADDU #undef ADDTV // Log to the log file dumped = json_dumps(info, 0); w_log(W_LOG_ERR, "PERF: %s\n", dumped); free(dumped); if (!cfg_get_json(NULL, "perf_logger_command")) { json_decref(info); return; } // Send this to our logging thread for async processing pthread_mutex_lock(&perf_log_lock); if (!perf_log_thread_started) { pthread_cond_init(&perf_log_cond, NULL); pthread_create(&perf_log_thr, NULL, perf_log_thread, NULL); perf_log_thread_started = true; } if (!perf_log_samples) { perf_log_samples = json_array(); } json_array_append_new(perf_log_samples, info); pthread_mutex_unlock(&perf_log_lock); pthread_cond_signal(&perf_log_cond); }
void watchman_perf_sample::log() { char *dumped = NULL; if (!will_log) { return; } // Assemble a perf blob auto info = json_object( {{"description", typed_string_to_json(description)}, {"meta", meta_data}, {"pid", json_integer(getpid())}, {"version", typed_string_to_json(PACKAGE_VERSION, W_STRING_UNICODE)}}); #ifdef WATCHMAN_BUILD_INFO info.set( "buildinfo", typed_string_to_json(WATCHMAN_BUILD_INFO, W_STRING_UNICODE)); #endif #define ADDTV(name, tv) info.set(name, json_real(w_timeval_abs_seconds(tv))) ADDTV("elapsed_time", duration); ADDTV("start_time", time_begin); #ifdef HAVE_SYS_RESOURCE_H ADDTV("user_time", usage.ru_utime); ADDTV("system_time", usage.ru_stime); #define ADDU(n) info.set(#n, json_integer(usage.n)) ADDU(ru_maxrss); ADDU(ru_ixrss); ADDU(ru_idrss); ADDU(ru_minflt); ADDU(ru_majflt); ADDU(ru_nswap); ADDU(ru_inblock); ADDU(ru_oublock); ADDU(ru_msgsnd); ADDU(ru_msgrcv); ADDU(ru_nsignals); ADDU(ru_nvcsw); ADDU(ru_nivcsw); #endif // HAVE_SYS_RESOURCE_H #undef ADDU #undef ADDTV // Log to the log file dumped = json_dumps(info, 0); w_log(W_LOG_ERR, "PERF: %s\n", dumped); free(dumped); if (!cfg_get_json("perf_logger_command")) { return; } // Send this to our logging thread for async processing { // The common case is that we already set up the logging // thread and that we can just log through it. auto rlock = perfThread.rlock(); if (rlock->get()) { (*rlock)->addSample(std::move(info)); return; } } // If it wasn't set, then we need an exclusive lock to // make sure that we don't spawn multiple instances. { auto wlock = perfThread.wlock(); if (!wlock->get()) { *wlock = watchman::make_unique<PerfLogThread>(); } (*wlock)->addSample(std::move(info)); } }