summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/profiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/profiler.cpp')
-rw-r--r--src/emu/profiler.cpp229
1 files changed, 229 insertions, 0 deletions
diff --git a/src/emu/profiler.cpp b/src/emu/profiler.cpp
new file mode 100644
index 00000000000..50e289e8d46
--- /dev/null
+++ b/src/emu/profiler.cpp
@@ -0,0 +1,229 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ profiler.c
+
+ Functions to manage profiling of MAME execution.
+
+****************************************************************************
+
+ Profiling is scope-based. To start profiling, put a profiler_scope
+ object on the stack. To end profiling, just end the scope:
+
+ {
+ profiler_scope scope(PROFILER_VIDEO);
+
+ your_work_here();
+ }
+
+ the profiler handles a FILO list so calls may be nested.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "profiler.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+struct profile_string
+{
+ int type;
+ const char *string;
+};
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+profiler_state g_profiler;
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define TEXT_UPDATE_TIME 0.5
+
+
+
+//**************************************************************************
+// DUMMY PROFILER STATE
+//**************************************************************************
+
+//-------------------------------------------------
+// dummy_profiler_state - constructor
+//-------------------------------------------------
+
+dummy_profiler_state::dummy_profiler_state()
+{
+}
+
+
+
+//**************************************************************************
+// REAL PROFILER STATE
+//**************************************************************************
+
+//-------------------------------------------------
+// real_profiler_state - constructor
+//-------------------------------------------------
+
+real_profiler_state::real_profiler_state()
+{
+ memset(m_filo, 0, sizeof(m_filo));
+ memset(m_data, 0, sizeof(m_data));
+ reset(false);
+}
+
+
+
+//-------------------------------------------------
+// reset - initializes state
+//-------------------------------------------------
+
+void real_profiler_state::reset(bool enabled)
+{
+ m_text_time = attotime::never;
+
+ if (enabled)
+ {
+ // we're enabled now
+ m_filoptr = m_filo;
+
+ // set up dummy entry
+ m_filoptr->start = 0;
+ m_filoptr->type = PROFILER_TOTAL;
+ }
+ else
+ {
+ // magic value to indicate disabled
+ m_filoptr = NULL;
+ }
+}
+
+
+
+//-------------------------------------------------
+// text - return the current text in an std::string
+//-------------------------------------------------
+
+const char *real_profiler_state::text(running_machine &machine)
+{
+ start(PROFILER_PROFILER);
+
+ // get the current time
+ attotime current_time = machine.scheduler().time();
+
+ // we only want to update the text periodically
+ if ((m_text_time == attotime::never) || ((current_time - m_text_time).as_double() >= TEXT_UPDATE_TIME))
+ {
+ update_text(machine);
+ m_text_time = current_time;
+ }
+
+ stop();
+ return m_text.c_str();
+}
+
+
+
+//-------------------------------------------------
+// update_text - update the current std::string
+//-------------------------------------------------
+
+void real_profiler_state::update_text(running_machine &machine)
+{
+ static const profile_string names[] =
+ {
+ { PROFILER_DRC_COMPILE, "DRC Compilation" },
+ { PROFILER_MEM_REMAP, "Memory Remapping" },
+ { PROFILER_MEMREAD, "Memory Read" },
+ { PROFILER_MEMWRITE, "Memory Write" },
+ { PROFILER_VIDEO, "Video Update" },
+ { PROFILER_DRAWGFX, "drawgfx" },
+ { PROFILER_COPYBITMAP, "copybitmap" },
+ { PROFILER_TILEMAP_DRAW, "Tilemap Draw" },
+ { PROFILER_TILEMAP_DRAW_ROZ, "Tilemap ROZ Draw" },
+ { PROFILER_TILEMAP_UPDATE, "Tilemap Update" },
+ { PROFILER_BLIT, "OSD Blitting" },
+ { PROFILER_SOUND, "Sound Generation" },
+ { PROFILER_TIMER_CALLBACK, "Timer Callbacks" },
+ { PROFILER_INPUT, "Input Processing" },
+ { PROFILER_MOVIE_REC, "Movie Recording" },
+ { PROFILER_LOGERROR, "Error Logging" },
+ { PROFILER_EXTRA, "Unaccounted/Overhead" },
+ { PROFILER_USER1, "User 1" },
+ { PROFILER_USER2, "User 2" },
+ { PROFILER_USER3, "User 3" },
+ { PROFILER_USER4, "User 4" },
+ { PROFILER_USER5, "User 5" },
+ { PROFILER_USER6, "User 6" },
+ { PROFILER_USER7, "User 7" },
+ { PROFILER_USER8, "User 8" },
+ { PROFILER_PROFILER, "Profiler" },
+ { PROFILER_IDLE, "Idle" }
+ };
+
+ // compute the total time for all bits, not including profiler or idle
+ UINT64 computed = 0;
+ profile_type curtype;
+ for (curtype = PROFILER_DEVICE_FIRST; curtype < PROFILER_PROFILER; curtype++)
+ computed += m_data[curtype];
+
+ // save that result in normalize, and continue adding the rest
+ UINT64 normalize = computed;
+ for ( ; curtype < PROFILER_TOTAL; curtype++)
+ computed += m_data[curtype];
+
+ // this becomes the total; if we end up with 0 for anything, we were just started, so return empty
+ UINT64 total = computed;
+ m_text.clear();
+ if (total == 0 || normalize == 0)
+ {
+ return;
+ }
+
+ // loop over all types and generate the string
+ device_iterator iter(machine.root_device());
+ for (curtype = PROFILER_DEVICE_FIRST; curtype < PROFILER_TOTAL; curtype++)
+ {
+ // determine the accumulated time for this type
+ computed = m_data[curtype];
+
+ // if we have non-zero data and we're ready to display, do it
+ if (computed != 0)
+ {
+ // start with the un-normalized percentage
+ strcatprintf(m_text, "%02d%% ", (int)((computed * 100 + total / 2) / total));
+
+ // followed by the normalized percentage for everything but profiler and idle
+ if (curtype < PROFILER_PROFILER)
+ strcatprintf(m_text, "%02d%% ", (int)((computed * 100 + normalize / 2) / normalize));
+
+ // and then the text
+ if (curtype >= PROFILER_DEVICE_FIRST && curtype <= PROFILER_DEVICE_MAX)
+ strcatprintf(m_text, "'%s'", iter.byindex(curtype - PROFILER_DEVICE_FIRST)->tag());
+ else
+ for (int nameindex = 0; nameindex < ARRAY_LENGTH(names); nameindex++)
+ if (names[nameindex].type == curtype)
+ {
+ m_text.append(names[nameindex].string);
+ break;
+ }
+
+ // followed by a carriage return
+ m_text.append("\n");
+ }
+ }
+
+ // reset data set to 0
+ memset(m_data, 0, sizeof(m_data));
+}