mame/src/emu/profiler.cpp
Miodrag Milanovic ddb290d5f6 NOTICE (TYPE NAME CONSOLIDATION)
Use standard uint64_t, uint32_t, uint16_t or uint8_t instead of UINT64, UINT32, UINT16 or UINT8
also use standard int64_t, int32_t, int16_t or int8_t instead of INT64, INT32, INT16 or INT8
2016-10-22 13:13:17 +02:00

230 lines
6.4 KiB
C++

// 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 = nullptr;
}
}
//-------------------------------------------------
// 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_t 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_t 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_t 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
m_text.append(string_format("%02d%% ", (int)((computed * 100 + total / 2) / total)));
// followed by the normalized percentage for everything but profiler and idle
if (curtype < PROFILER_PROFILER)
m_text.append(string_format("%02d%% ", (int)((computed * 100 + normalize / 2) / normalize)));
// and then the text
if (curtype >= PROFILER_DEVICE_FIRST && curtype <= PROFILER_DEVICE_MAX)
m_text.append(string_format("'%s'", iter.byindex(curtype - PROFILER_DEVICE_FIRST)->tag()));
else
for (auto & name : names)
if (name.type == curtype)
{
m_text.append(name.string);
break;
}
// followed by a carriage return
m_text.append("\n");
}
}
// reset data set to 0
memset(m_data, 0, sizeof(m_data));
}