From 6783ab26f8689bea08a6a253d40c3dec0da17cf2 Mon Sep 17 00:00:00 2001 From: hiker Date: Mon, 7 Aug 2017 17:53:15 +1000 Subject: [PATCH] Keep a list of all event names in the order in which they first appear. This list allows the proper ordering of events when drawing the bar chart to show nesting. Make sure that enabling the profiler starts at the next synch point (to avoid incomplete event pairs). Create a seprate output file for each thread. --- src/utils/debug.cpp | 3 +-- src/utils/profiler.cpp | 58 +++++++++++++++++++++++++----------------- src/utils/profiler.hpp | 7 +++++ 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index c4d475742..4bf9ef289 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -346,8 +346,7 @@ bool handleContextMenuAction(s32 cmd_id) irr_driver->toggleBoundingBoxesViz(); break; case DEBUG_PROFILER: - UserConfigParams::m_profiler_enabled = - !UserConfigParams::m_profiler_enabled; + profiler.toggleStatus(); break; case DEBUG_PROFILER_WRITE_REPORT: profiler.writeToFile(); diff --git a/src/utils/profiler.cpp b/src/utils/profiler.cpp index 13328ed24..c208c66cf 100644 --- a/src/utils/profiler.cpp +++ b/src/utils/profiler.cpp @@ -26,6 +26,7 @@ #include "graphics/irr_driver.hpp" #include "guiengine/scalable_font.hpp" #include "io/file_manager.hpp" +#include "utils/string_utils.hpp" #include "utils/vs.hpp" #include @@ -186,6 +187,11 @@ void Profiler::pushCPUMarker(const char* name, const video::SColor& colour) EventData ed(colour, m_max_frames); ed.setStart(m_current_frame, start, td.m_event_stack.size()); td.m_all_event_data[name] = ed; + // Ordered headings is used to determine the order in which the + // bar graph is drawn. Outer profiling events will be added first, + // so they will be drawn first, which gives the proper nested + // displayed of events. + td.m_ordered_headings.push_back(name); } td.m_event_stack.push_back(name); m_lock.unlock(); @@ -223,6 +229,21 @@ void Profiler::popCPUMarker() m_lock.unlock(); } // popCPUMarker +//----------------------------------------------------------------------------- +/** Switches the profiler either on or off. + */ +void Profiler::toggleStatus() +{ + UserConfigParams::m_profiler_enabled = !UserConfigParams::m_profiler_enabled; + // If the profiler would immediately enabled, calls that have started but + // not finished would not be registered correctly. So set the state to + // waiting, so the unfreeze started at the next sync frame (which is + // outside of the main loop, i.e. all profiling events inside of the main + // loop will work as expected. + if (m_freeze_state == UNFROZEN) + m_freeze_state = WAITING_FOR_UNFREEZE; +} // toggleStatus + //----------------------------------------------------------------------------- /** Saves all data for the current frame, and starts the next frame in the * circular buffer. Any events that are currently active (e.g. in a separate @@ -335,9 +356,9 @@ void Profiler::draw() { ThreadData &td = m_all_threads_data[i]; AllEventData &aed = td.m_all_event_data; - AllEventData::iterator j; - for (j = aed.begin(); j != aed.end(); ++j) + for(int k=0; k<(int)td.m_ordered_headings.size(); k++) { + AllEventData::iterator j = aed.find(td.m_ordered_headings[k]); const Marker &marker = j->second.getMarker(indx); core::rect pos((s32)(x_offset + factor*marker.getStart()), (s32)(y_offset + i*line_height), @@ -518,40 +539,29 @@ void Profiler::writeToFile() std::string base_name = file_manager->getUserConfigFile(file_manager->getStdoutName()); // First CPU data - std::ofstream f(base_name + ".profile-cpu"); for (int thread_id = 0; thread_id < m_threads_used; thread_id++) { + std::ofstream f(base_name + ".profile-cpu-" + + StringUtils::toString(thread_id) ); ThreadData &td = m_all_threads_data[thread_id]; - AllEventData::iterator j; - std::vector new_headings; - for (j = td.m_all_event_data.begin(); j != td.m_all_event_data.end(); j++) - { - std::vector::iterator f = - std::find(m_all_event_names.begin(), - m_all_event_names.end(), j->first); - if(f==m_all_event_names.end()) - new_headings.push_back(j->first); - } - std::sort(new_headings.begin(), new_headings.end()); - f << "# \"Thread(1)\" "; - for (unsigned int i = 0; i < new_headings.size(); i++) - f << "\"" << new_headings[i] << "(" << i+2 <<")\" "; + f << "# "; + for (unsigned int i = 0; i < td.m_ordered_headings.size(); i++) + f << "\"" << td.m_ordered_headings[i] << "(" << i+1 <<")\" "; f << std::endl; int start = m_has_wrapped_around ? m_current_frame + 1 : 0; if (start > m_max_frames) start -= m_max_frames; while (start != m_current_frame) { - f << "t" << thread_id << " "; - for (unsigned int i = 0; i < new_headings.size(); i++) + for (unsigned int i = 0; i < td.m_ordered_headings.size(); i++) { - const EventData &ed = td.m_all_event_data[new_headings[i]]; + const EventData &ed = td.m_all_event_data[td.m_ordered_headings[i]]; f << int(ed.getMarker(start).getDuration()*1000) << " "; } // for i i new_headings f << std::endl; start = (start + 1) % m_max_frames; - } - } // for - f.close(); + } // while start != m_current_frame + f.close(); + } // for all thread_ids std::ofstream f_gpu(base_name + ".profile-gpu"); f_gpu << "# "; @@ -573,7 +583,7 @@ void Profiler::writeToFile() f_gpu << std::endl; start = (start + 1) % m_max_frames; } - f.close(); + f_gpu.close(); m_lock.unlock(); } // writeFile diff --git a/src/utils/profiler.hpp b/src/utils/profiler.hpp index 059db13b1..eb2258039 100644 --- a/src/utils/profiler.hpp +++ b/src/utils/profiler.hpp @@ -209,6 +209,12 @@ private: /** Stack of events to detect nesting. */ std::vector< std::string > m_event_stack; + /** This stores the event names in the order in which they occur. + * This means that 'outer' events occur here before any child + * events. This list is then used to determine the order in which the + * bar graphs are drawn, which results in the proper nesting of events.*/ + std::vector m_ordered_headings; + AllEventData m_all_event_data; }; // class ThreadData @@ -277,6 +283,7 @@ public: void pushCPUMarker(const char* name="N/A", const video::SColor& color=video::SColor()); void popCPUMarker(); + void toggleStatus(); void synchronizeFrame(); void draw(); void onClick(const core::vector2di& mouse_pos);