constunsigned char* EventTracer::GetCategoryEnabled(const char* name) {
if (g_get_category_enabled_ptr) return g_get_category_enabled_ptr(name);
// A string with null terminator means category is disabled. returnreinterpret_cast<constunsigned char*>("\0");
}
// Arguments to this function (phase, etc.) are as defined in // webrtc/rtc_base/trace_event.h. void EventTracer::AddTraceEvent(char phase, constunsigned char* category_enabled, const char* name, unsigned long long id,
int num_args, const char** arg_names, constunsigned char* arg_types, constunsigned long long* arg_values, unsigned char flags) {
if (g_add_trace_event_ptr) {
g_add_trace_event_ptr(phase, category_enabled, name, id, num_args,
arg_names, arg_types, arg_values, flags);
}
} #endif
// This is a guesstimate that should be enough in most cases. staticconst size_t kEventLoggerArgsStrBufferInitialSize = 256; staticconst size_t kTraceArgBufferLength = 32;
namespace tracing {
namespace {
// Atomic-int fast path for avoiding logging when disabled.
std::atomic<int> g_event_logging_active(0);
// TODO(pbos): Log metadata for all threads, etc. class EventLogger final { public:
explicit EventLogger(std::optional<Environment> env)
: env_(env),
clock_(env.has_value() ? env->clock() : *Clock::GetRealTimeClockOnlyUseForRelativeTime()) {}
~EventLogger() { RTC_DCHECK(thread_checker_.IsCurrent()); }
void AddTraceEvent(const char* name, constunsigned char* category_enabled,
char phase,
int num_args, const char** arg_names, constunsigned char* arg_types, constunsigned long long* arg_values,
int /* pid */,
PlatformThreadId thread_id) {
Timestamp now = clock_.CurrentTime();
std::vector<TraceArg> args(num_args);
for (int i = 0; i < num_args; ++i) {
TraceArg& arg = args[i];
arg.name = arg_names[i];
arg.type = arg_types[i];
arg.value.as_uint = arg_values[i];
// Value is a pointer to a temporary string, so we have to make a copy.
if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) { // Space for the string and for the terminating null character.
size_t str_length = strlen(arg.value.as_string) + 1;
char* str_copy = new char[str_length];
memcpy(str_copy, arg.value.as_string, str_length);
arg.value.as_string = str_copy;
}
}
MutexLock lock(&mutex_);
trace_events_.push_back({.name = name,
.category_enabled = category_enabled,
.phase = phase,
.args = args,
.timestamp = now,
.pid = 1,
.tid = thread_id});
}
void Start(FILE* file, bool owned) {
RTC_DCHECK(thread_checker_.IsCurrent());
RTC_DCHECK(file);
RTC_DCHECK(!output_file_);
output_file_ = file;
output_file_owned_ = owned;
{
MutexLock lock(&mutex_); // Since the atomic fast-path for adding events to the queue can be // bypassed while the logging thread is shutting down there may be some // stale events in the queue, hence the vector needs to be cleared to not // log events from a previous logging session (which may be days old).
trace_events_.clear();
} // Enable event logging (fast-path). This should be disabled since starting // shouldn't be done twice.
int zero = 0;
RTC_CHECK(g_event_logging_active.compare_exchange_strong(zero, 1));
// Finally start, everything should be set up now.
logging_thread_ =
PlatformThread::SpawnJoinable([this] { Log(); }, "EventTracingThread");
TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Start",
TRACE_EVENT_SCOPE_GLOBAL);
}
void Stop() {
RTC_DCHECK(thread_checker_.IsCurrent());
TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Stop",
TRACE_EVENT_SCOPE_GLOBAL); // Try to stop. Abort if we're not currently logging.
int one = 1;
if (g_event_logging_active.compare_exchange_strong(one, 0)) return;
// Wake up logging thread to finish writing.
shutdown_event_.Set(); // Join the logging thread.
logging_thread_.Finalize();
}
private: struct TraceArg { const char* name; unsigned char type; // Copied from webrtc/rtc_base/trace_event.h TraceValueUnion. union TraceArgValue { bool as_bool; unsigned long long as_uint;
long long as_int; double as_double; constvoid* as_pointer; const char* as_string;
} value;
// Assert that the size of the union is equal to the size of the as_uint // field since we are assigning to arbitrary types using it.
static_assert(sizeof(TraceArgValue) == sizeof(unsigned long long), "Size of TraceArg value union is not equal to the size of " "the uint field of that union.");
};
if (arg.type == TRACE_VALUE_TYPE_STRING ||
arg.type == TRACE_VALUE_TYPE_COPY_STRING) { // Space for every character to be an espaced character + two for // quatation marks.
output.reserve(strlen(arg.value.as_string) * 2 + 2);
output += '\"'; const char* c = arg.value.as_string; do {
if (*c == '"' || *c == '\\') {
output += '\\';
output += *c;
} else {
output += *c;
}
} while (*++c);
output += '\"';
} else {
output.resize(kTraceArgBufferLength);
size_t print_length = 0; switch (arg.type) { case TRACE_VALUE_TYPE_BOOL:
if (arg.value.as_bool) {
strcpy(&output[0], "true");
print_length = 4;
} else {
strcpy(&output[0], "false");
print_length = 5;
} break; case TRACE_VALUE_TYPE_UINT:
print_length = snprintf(&output[0], kTraceArgBufferLength, "%llu",
arg.value.as_uint); break; case TRACE_VALUE_TYPE_INT:
print_length = snprintf(&output[0], kTraceArgBufferLength, "%lld",
arg.value.as_int); break; case TRACE_VALUE_TYPE_DOUBLE:
print_length = snprintf(&output[0], kTraceArgBufferLength, "%f",
arg.value.as_double); break; case TRACE_VALUE_TYPE_POINTER:
print_length = snprintf(&output[0], kTraceArgBufferLength, "\"%p\"",
arg.value.as_pointer); break;
}
size_t output_length = print_length < kTraceArgBufferLength
? print_length
: kTraceArgBufferLength - 1; // This will hopefully be very close to nop. On most implementations, it // just writes null byte and sets the length field of the string.
output.resize(output_length);
}
return output;
}
Mutex mutex_;
std::vector<TraceEvent> trace_events_ RTC_GUARDED_BY(mutex_); // TODO(https://issues.webrtc.org/481963632): Make environment non-optional // and remove `clock_` once an environment is required.
std::optional<Environment> env_;
Clock& clock_;
PlatformThread logging_thread_;
Event shutdown_event_;
SequenceChecker thread_checker_;
FILE* output_file_ = nullptr; bool output_file_owned_ = false;
};
void InternalAddTraceEvent(char phase, constunsigned char* category_enabled, const char* name, unsigned long long /* id */,
int num_args, const char** arg_names, constunsigned char* arg_types, constunsigned long long* arg_values, unsigned char /* flags */) { // Fast path for when event tracing is inactive.
if (g_event_logging_active.load() == 0) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.