mirror of
https://github.com/holub/mame
synced 2025-05-11 08:38:47 +03:00

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
230 lines
6.4 KiB
C++
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));
|
|
}
|