void end(trace_event* evt) { if (!do_trace_events) { // No one to process the event is here return; } if (!initialized) { return; } Assertion(evt->pid == get_pid(), "Complete events must be generated from the same process!"); Assertion(evt->tid == get_tid(), "Complete events must be generated from the same thread!"); evt->duration = timer_get_nanoseconds() - evt->timestamp; evt->end_event_id = ++current_id; // Process CPU events submit_event(evt); // Create GPU events if (do_gpu_queries && evt->category->usesGPUCounter()) { Assertion(get_tid() == main_thread_id, "This function must be called from the main thread!"); gpu_trace_event gpu_event; gpu_event.base_evt.category = evt->category; gpu_event.base_evt.tid = 1; gpu_event.base_evt.pid = GPU_PID; gpu_event.base_evt.type = EventType::End; gpu_event.gpu_begin_query = get_gpu_timestamp_query(); // This does not need to be synchronized since GPU queries are only allowed on the main thread. gpu_events.push(gpu_event); } }
void init() { do_trace_events = false; do_async_events = false; do_counter_events = false; if (Cmdline_json_profiling) { traceEventWriter.reset(new ThreadedTraceEventWriter()); do_trace_events = true; do_async_events = true; do_counter_events = true; } if (Cmdline_profile_write_file) { mainFrameTimer.reset(new ThreadedMainFrameTimer()); do_async_events = true; } if (Cmdline_frame_profile) { frameProfiler.reset(new FrameProfiler()); do_trace_events = true; } do_gpu_queries = gr_is_capable(CAPABILITY_TIMESTAMP_QUERY); if (do_gpu_queries) { gpu_start_query = get_gpu_timestamp_query(); } cpu_start_time = timer_get_nanoseconds(); main_thread_id = get_tid(); initialized = true; }
/** * Used to end profiling of a section of code. Note that the parameter given MUST match that of the preceding call * to profile_begin * @param name A globally unique string that will be displayed in the HUD readout */ void profile_end(const char* name) { if (Cmdline_json_profiling) { std::lock_guard<std::mutex> guard(json_mutex); tracing_data data; data.name = name; data.pid = get_pid(); data.tid = get_tid(); data.enter = false; data.time = timer_get_nanoseconds(); if (do_gpu_queries) { data.gpu_query = get_query_object(); gr_query_value(data.gpu_query, QueryType::Timestamp); } else { data.gpu_query = -1; } current_frame_data.push_back(data); } if (Cmdline_frame_profile) { int num_parents = 0; int child_of = -1; for ( int i = 0; i < (int)samples.size(); i++ ) { if ( samples[i].open_profiles ) { if ( samples[i].num_children == 1 ) { child_of = i; } } } for ( int i = 0; i < (int)samples.size(); i++ ) { if ( !strcmp(samples[i].name.c_str(), name) && samples[i].parent == child_of ) { int inner = 0; int parent = -1; std::uint64_t end_time = timer_get_microseconds(); samples[i].open_profiles--; // count all parents and find the immediate parent while ( inner < (int)samples.size() ) { if ( samples[inner].open_profiles > 0 ) { // found a parent (any open profiles are parents) num_parents++; if (parent < 0) { // replace invalid parent (index) parent = inner; } else if (samples[inner].start_time >= samples[parent].start_time) { // replace with more immediate parent parent = inner; } } inner++; } // remember the current number of parents of the sample samples[i].num_parents = num_parents; if ( parent >= 0 ) { // record this time in children_sample_time (add it in) samples[parent].children_sample_time += end_time - samples[i].start_time; } // save sample time in accumulator samples[i].accumulator += end_time - samples[i].start_time; break; } } for (int i = 0; i < (int)samples.size(); i++) { if (samples[i].open_profiles) { samples[i].num_children--; samples[i].num_children = MAX(samples[i].num_children, 0); } } } }
/** * Used to start profiling a section of code. A section started by profile_begin needs to be closed off by calling * profile_end with the same argument. * @param name A globally unique string that will be displayed in the HUD readout */ void profile_begin(const char* name) { if (Cmdline_json_profiling) { std::lock_guard<std::mutex> guard(json_mutex); tracing_data data; data.name = name; data.pid = get_pid(); data.tid = get_tid(); data.enter = true; data.time = timer_get_nanoseconds(); if (do_gpu_queries) { data.gpu_query = get_query_object(); gr_query_value(data.gpu_query, QueryType::Timestamp); } else { data.gpu_query = -1; } current_frame_data.push_back(data); } if (Cmdline_frame_profile) { int parent = -1; for (int i = 0; i < (int)samples.size(); i++) { if ( !samples[i].open_profiles ) { continue; } samples[i].num_children++; if (samples[i].num_children == 1) { // this is our direct parent for this new sample parent = i; } } for(int i = 0; i < (int)samples.size(); i++) { if( !strcmp(samples[i].name.c_str(), name) && samples[i].parent == parent ) { // found the profile sample samples[i].open_profiles++; samples[i].profile_instances++; samples[i].start_time = timer_get_microseconds(); Assert(samples[i].open_profiles == 1); // max 1 open at once return; } } // create a new profile sample profile_sample new_sample; new_sample.name = SCP_string(name); new_sample.open_profiles = 1; new_sample.profile_instances = 1; new_sample.accumulator = 0; new_sample.start_time = timer_get_microseconds(); new_sample.children_sample_time = 0; new_sample.num_children = 0; new_sample.parent = parent; samples.push_back(new_sample); } }