// 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(constchar* name, constunsignedchar* category_enabled, char phase, int num_args, constchar** arg_names, constunsignedchar* arg_types, constunsignedlonglong* 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 = newchar[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();
}
// 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(unsignedlonglong), "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 += '\"'; constchar* 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;
};
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.