Changeset - r23351:74c208bc690a
[Not reviewed]
master
0 7 0
Niels Martin Hansen - 5 years ago 2019-02-04 00:26:55
nielsm@indvikleren.dk
Add: Show performance of AI and GS in framerate window
7 files changed with 187 insertions and 19 deletions:
0 comments (0 inline, 0 general)
README.md
Show inline comments
 
@@ -476,6 +476,12 @@ The following is an explanation of the d
 
- *World ticks* - Time spent on other world/landscape processing. This
 
  includes towns growing, building animations, updates of farmland and trees,
 
  and station rating updates.
 
- *GS/AI total*, *Game script*, and *AI players* - Time spent running logic
 
  for game scripts and AI players. The total may show as less than the current
 
  sum of the individual scripts, this is because AI players at lower
 
  difficulty settings do not run every game tick, and hence contribute less
 
  to the average across all ticks. Keep in mind that the "Current" figure is
 
  also an average, just only over short term.
 
- *Link graph delay* - Time overruns of the cargo distribution link graph
 
  update thread. Usually the link graph is updated in a background thread,
 
  but these updates need to synchronise with the main game loop occasionally,
src/ai/ai_core.cpp
Show inline comments
 
@@ -16,6 +16,7 @@
 
#include "../company_func.h"
 
#include "../network/network.h"
 
#include "../window_func.h"
 
#include "../framerate_type.h"
 
#include "ai_scanner.hpp"
 
#include "ai_instance.hpp"
 
#include "ai_config.hpp"
 
@@ -79,8 +80,11 @@
 
	const Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		if (c->is_ai) {
 
			PerformanceMeasurer framerate((PerformanceElement)(PFE_AI0 + c->index));
 
			cur_company.Change(c->index);
 
			c->ai_instance->GameLoop();
 
		} else {
 
			PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + c->index));
 
		}
 
	}
 
	cur_company.Restore();
 
@@ -101,6 +105,7 @@
 
/* static */ void AI::Stop(CompanyID company)
 
{
 
	if (_networking && !_network_server) return;
 
	PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + company));
 

	
 
	Backup<CompanyByte> cur_company(_current_company, company, FILE_LINE);
 
	Company *c = Company::Get(company);
src/framerate_gui.cpp
Show inline comments
 
@@ -13,13 +13,18 @@
 
#include <chrono>
 
#include "gfx_func.h"
 
#include "window_gui.h"
 
#include "window_func.h"
 
#include "table/sprites.h"
 
#include "string_func.h"
 
#include "strings_func.h"
 
#include "console_func.h"
 
#include "console_type.h"
 
#include "guitimer_func.h"
 
#include "company_base.h"
 
#include "ai/ai_info.hpp"
 

	
 
#include "widgets/framerate_widget.h"
 
#include "safeguards.h"
 

	
 

	
 
/**
 
@@ -183,6 +188,23 @@ namespace {
 
		PerformanceData(1),                     // PFE_ACC_DRAWWORLD
 
		PerformanceData(60.0),                  // PFE_VIDEO
 
		PerformanceData(1000.0 * 8192 / 44100), // PFE_SOUND
 
		PerformanceData(1),                     // PFE_ALLSCRIPTS
 
		PerformanceData(1),                     // PFE_GAMESCRIPT
 
		PerformanceData(1),                     // PFE_AI0 ...
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),
 
		PerformanceData(1),                     // PFE_AI14
 
	};
 

	
 
}
 
@@ -215,6 +237,15 @@ PerformanceMeasurer::PerformanceMeasurer
 
/** Finish a cycle of a measured element and store the measurement taken. */
 
PerformanceMeasurer::~PerformanceMeasurer()
 
{
 
	if (this->elem == PFE_ALLSCRIPTS) {
 
		/* Hack to not record scripts total when no scripts are active */
 
		bool any_active = _pf_data[PFE_GAMESCRIPT].num_valid > 0;
 
		for (uint e = PFE_AI0; e < PFE_MAX; e++) any_active |= _pf_data[e].num_valid > 0;
 
		if (!any_active) {
 
			PerformanceMeasurer::SetInactive(PFE_ALLSCRIPTS);
 
			return;
 
		}
 
	}
 
	_pf_data[this->elem].Add(this->start_time, GetPerformanceTimer());
 
}
 

	
 
@@ -224,11 +255,19 @@ void PerformanceMeasurer::SetExpectedRat
 
	_pf_data[this->elem].expected_rate = rate;
 
}
 

	
 
/** Mark a performance element as not currently in use. */
 
/* static */ void PerformanceMeasurer::SetInactive(PerformanceElement elem)
 
{
 
	_pf_data[elem].num_valid = 0;
 
	_pf_data[elem].next_index = 0;
 
	_pf_data[elem].prev_index = 0;
 
}
 

	
 
/**
 
 * Indicate that a cycle of "pause" where no processing occurs.
 
 * @param elem The element not currently being processed
 
 */
 
void PerformanceMeasurer::Paused(PerformanceElement elem)
 
/* static */ void PerformanceMeasurer::Paused(PerformanceElement elem)
 
{
 
	_pf_data[elem].AddPause(GetPerformanceTimer());
 
}
 
@@ -266,6 +305,44 @@ void PerformanceAccumulator::Reset(Perfo
 
void ShowFrametimeGraphWindow(PerformanceElement elem);
 

	
 

	
 
static const PerformanceElement DISPLAY_ORDER_PFE[PFE_MAX] = {
 
	PFE_GAMELOOP,
 
	PFE_GL_ECONOMY,
 
	PFE_GL_TRAINS,
 
	PFE_GL_ROADVEHS,
 
	PFE_GL_SHIPS,
 
	PFE_GL_AIRCRAFT,
 
	PFE_GL_LANDSCAPE,
 
	PFE_ALLSCRIPTS,
 
	PFE_GAMESCRIPT,
 
	PFE_AI0,
 
	PFE_AI1,
 
	PFE_AI2,
 
	PFE_AI3,
 
	PFE_AI4,
 
	PFE_AI5,
 
	PFE_AI6,
 
	PFE_AI7,
 
	PFE_AI8,
 
	PFE_AI9,
 
	PFE_AI10,
 
	PFE_AI11,
 
	PFE_AI12,
 
	PFE_AI13,
 
	PFE_AI14,
 
	PFE_GL_LINKGRAPH,
 
	PFE_DRAWING,
 
	PFE_DRAWWORLD,
 
	PFE_VIDEO,
 
	PFE_SOUND,
 
};
 

	
 
static const char * GetAIName(int ai_index)
 
{
 
	if (!Company::IsValidAiID(ai_index)) return "";
 
	return Company::Get(ai_index)->ai_info->GetName();
 
}
 

	
 
/** @hideinitializer */
 
static const NWidgetPart _framerate_window_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
@@ -296,6 +373,7 @@ static const NWidgetPart _framerate_wind
 
struct FramerateWindow : Window {
 
	bool small;
 
	GUITimer next_update;
 
	int num_active;
 

	
 
	struct CachedDecimal {
 
		StringID strid;
 
@@ -369,9 +447,16 @@ struct FramerateWindow : Window {
 

	
 
		this->rate_drawing.SetRate(_pf_data[PFE_DRAWING].GetRate(), _pf_data[PFE_DRAWING].expected_rate);
 

	
 
		int new_active = 0;
 
		for (PerformanceElement e = PFE_FIRST; e < PFE_MAX; e++) {
 
			this->times_shortterm[e].SetTime(_pf_data[e].GetAverageDurationMilliseconds(8), MILLISECONDS_PER_TICK);
 
			this->times_longterm[e].SetTime(_pf_data[e].GetAverageDurationMilliseconds(NUM_FRAMERATE_POINTS), MILLISECONDS_PER_TICK);
 
			if (_pf_data[e].num_valid > 0) new_active++;
 
		}
 

	
 
		if (new_active != this->num_active) {
 
			this->num_active = new_active;
 
			this->ReInit();
 
		}
 
	}
 

	
 
@@ -425,25 +510,32 @@ struct FramerateWindow : Window {
 
				break;
 

	
 
			case WID_FRW_TIMES_NAMES: {
 
				int linecount = PFE_MAX - PFE_FIRST;
 
				size->width = 0;
 
				size->height = FONT_HEIGHT_NORMAL * (linecount + 1) + VSPACING;
 
				for (int line = 0; line < linecount; line++) {
 
					Dimension line_size = GetStringBoundingBox(STR_FRAMERATE_GAMELOOP + line);
 
				size->height = FONT_HEIGHT_NORMAL + VSPACING;
 
				for (PerformanceElement e : DISPLAY_ORDER_PFE) {
 
					if (_pf_data[e].num_valid == 0) continue;
 
					Dimension line_size;
 
					if (e < PFE_AI0) {
 
						line_size = GetStringBoundingBox(STR_FRAMERATE_GAMELOOP + e);
 
					} else {
 
						SetDParam(0, e - PFE_AI0 + 1);
 
						SetDParamStr(1, GetAIName(e - PFE_AI0));
 
						line_size = GetStringBoundingBox(STR_FRAMERATE_AI);
 
					}
 
					size->width = max(size->width, line_size.width);
 
					size->height += FONT_HEIGHT_NORMAL;
 
				}
 
				break;
 
			}
 

	
 
			case WID_FRW_TIMES_CURRENT:
 
			case WID_FRW_TIMES_AVERAGE: {
 
				int linecount = PFE_MAX - PFE_FIRST;
 
				*size = GetStringBoundingBox(STR_FRAMERATE_CURRENT + (widget - WID_FRW_TIMES_CURRENT));
 
				SetDParam(0, 999999);
 
				SetDParam(1, 2);
 
				Dimension item_size = GetStringBoundingBox(STR_FRAMERATE_MS_GOOD);
 
				size->width = max(size->width, item_size.width);
 
				size->height += FONT_HEIGHT_NORMAL * linecount + VSPACING;
 
				size->height += FONT_HEIGHT_NORMAL * this->num_active + VSPACING;
 
				break;
 
			}
 
		}
 
@@ -456,7 +548,8 @@ struct FramerateWindow : Window {
 
		DrawString(r.left, r.right, y, heading_str, TC_FROMSTRING, SA_CENTER, true);
 
		y += FONT_HEIGHT_NORMAL + VSPACING;
 

	
 
		for (PerformanceElement e = PFE_FIRST; e < PFE_MAX; e++) {
 
		for (PerformanceElement e : DISPLAY_ORDER_PFE) {
 
			if (_pf_data[e].num_valid == 0) continue;
 
			values[e].InsertDParams(0);
 
			DrawString(r.left, r.right, y, values[e].strid, TC_FROMSTRING, SA_RIGHT);
 
			y += FONT_HEIGHT_NORMAL;
 
@@ -468,10 +561,16 @@ struct FramerateWindow : Window {
 
		switch (widget) {
 
			case WID_FRW_TIMES_NAMES: {
 
				/* Render a column of titles for performance element names */
 
				int linecount = PFE_MAX - PFE_FIRST;
 
				int y = r.top + FONT_HEIGHT_NORMAL + VSPACING; // first line contains headings in the value columns
 
				for (int i = 0; i < linecount; i++) {
 
					DrawString(r.left, r.right, y, STR_FRAMERATE_GAMELOOP + i, TC_FROMSTRING, SA_LEFT);
 
				for (PerformanceElement e : DISPLAY_ORDER_PFE) {
 
					if (_pf_data[e].num_valid == 0) continue;
 
					if (e < PFE_AI0) {
 
						DrawString(r.left, r.right, y, STR_FRAMERATE_GAMELOOP + e, TC_FROMSTRING, SA_LEFT);
 
					} else {
 
						SetDParam(0, e - PFE_AI0 + 1);
 
						SetDParamStr(1, GetAIName(e - PFE_AI0));
 
						DrawString(r.left, r.right, y, STR_FRAMERATE_AI, TC_FROMSTRING, SA_LEFT);
 
					}
 
					y += FONT_HEIGHT_NORMAL;
 
				}
 
				break;
 
@@ -496,8 +595,14 @@ struct FramerateWindow : Window {
 
				/* Open time graph windows when clicking detail measurement lines */
 
				int line = this->GetRowFromWidget(pt.y, widget, VSPACING, FONT_HEIGHT_NORMAL);
 
				if (line > 0) {
 
					line -= 1;
 
					ShowFrametimeGraphWindow((PerformanceElement)line);
 
					/* Find the visible line that was clicked */
 
					for (PerformanceElement e : DISPLAY_ORDER_PFE) {
 
						if (_pf_data[e].num_valid > 0) line--;
 
						if (line == 0) {
 
							ShowFrametimeGraphWindow(e);
 
							break;
 
						}
 
					}
 
				}
 
				break;
 
			}
 
@@ -549,7 +654,13 @@ struct FrametimeGraphWindow : Window {
 
	{
 
		switch (widget) {
 
			case WID_FGW_CAPTION:
 
				SetDParam(0, STR_FRAMETIME_CAPTION_GAMELOOP + this->element);
 
				if (this->element < PFE_AI0) {
 
					SetDParam(0, STR_FRAMETIME_CAPTION_GAMELOOP + this->element);
 
				} else {
 
					SetDParam(0, STR_FRAMETIME_CAPTION_AI);
 
					SetDParam(1, this->element - PFE_AI0 + 1);
 
					SetDParamStr(2, GetAIName(this->element - PFE_AI0));
 
				}
 
				break;
 
		}
 
	}
 
@@ -829,7 +940,10 @@ void ConPrintFramerate()
 
		"  Viewport drawing",
 
		"Video output",
 
		"Sound mixing",
 
		"AI/GS scripts total",
 
		"Game script",
 
	};
 
	char ai_name_buf[128];
 

	
 
	static const PerformanceElement rate_elements[] = { PFE_GAMELOOP, PFE_DRAWING, PFE_VIDEO };
 

	
 
@@ -848,8 +962,15 @@ void ConPrintFramerate()
 
	for (PerformanceElement e = PFE_FIRST; e < PFE_MAX; e++) {
 
		auto &pf = _pf_data[e];
 
		if (pf.num_valid == 0) continue;
 
		const char *name;
 
		if (e < PFE_AI0) {
 
			name = MEASUREMENT_NAMES[e];
 
		} else {
 
			seprintf(ai_name_buf, lastof(ai_name_buf), "AI %d %s", e - PFE_AI0 + 1, GetAIName(e - PFE_AI0)),
 
			name = ai_name_buf;
 
		}
 
		IConsolePrintF(TC_LIGHT_BLUE, "%s times: %.2fms  %.2fms  %.2fms",
 
			MEASUREMENT_NAMES[e],
 
			name,
 
			pf.GetAverageDurationMilliseconds(count1),
 
			pf.GetAverageDurationMilliseconds(count2),
 
			pf.GetAverageDurationMilliseconds(count3));
src/framerate_type.h
Show inline comments
 
@@ -60,6 +60,23 @@ enum PerformanceElement {
 
	PFE_DRAWWORLD,     ///< Time spent drawing world viewports in GUI
 
	PFE_VIDEO,         ///< Speed of painting drawn video buffer.
 
	PFE_SOUND,         ///< Speed of mixing audio samples
 
	PFE_ALLSCRIPTS,    ///< Sum of all GS/AI scripts
 
	PFE_GAMESCRIPT,    ///< Game script execution
 
	PFE_AI0,           ///< AI execution for player slot 1
 
	PFE_AI1,           ///< AI execution for player slot 2
 
	PFE_AI2,           ///< AI execution for player slot 3
 
	PFE_AI3,           ///< AI execution for player slot 4
 
	PFE_AI4,           ///< AI execution for player slot 5
 
	PFE_AI5,           ///< AI execution for player slot 6
 
	PFE_AI6,           ///< AI execution for player slot 7
 
	PFE_AI7,           ///< AI execution for player slot 8
 
	PFE_AI8,           ///< AI execution for player slot 9
 
	PFE_AI9,           ///< AI execution for player slot 10
 
	PFE_AI10,          ///< AI execution for player slot 11
 
	PFE_AI11,          ///< AI execution for player slot 12
 
	PFE_AI12,          ///< AI execution for player slot 13
 
	PFE_AI13,          ///< AI execution for player slot 14
 
	PFE_AI14,          ///< AI execution for player slot 15
 
	PFE_MAX,           ///< End of enum, must be last.
 
};
 
DECLARE_POSTFIX_INCREMENT(PerformanceElement)
 
@@ -81,6 +98,7 @@ public:
 
	PerformanceMeasurer(PerformanceElement elem);
 
	~PerformanceMeasurer();
 
	void SetExpectedRate(double rate);
 
	static void SetInactive(PerformanceElement elem);
 
	static void Paused(PerformanceElement elem);
 
};
 

	
src/game/game_core.cpp
Show inline comments
 
@@ -15,6 +15,7 @@
 
#include "../company_func.h"
 
#include "../network/network.h"
 
#include "../window_func.h"
 
#include "../framerate_type.h"
 
#include "game.hpp"
 
#include "game_scanner.hpp"
 
#include "game_config.hpp"
 
@@ -31,8 +32,16 @@
 

	
 
/* static */ void Game::GameLoop()
 
{
 
	if (_networking && !_network_server) return;
 
	if (Game::instance == NULL) return;
 
	if (_networking && !_network_server) {
 
		PerformanceMeasurer::SetInactive(PFE_GAMESCRIPT);
 
		return;
 
	}
 
	if (Game::instance == NULL) {
 
		PerformanceMeasurer::SetInactive(PFE_GAMESCRIPT);
 
		return;
 
	}
 

	
 
	PerformanceMeasurer framerate(PFE_GAMESCRIPT);
 

	
 
	Game::frame_counter++;
 

	
src/lang/english.txt
Show inline comments
 
@@ -2747,6 +2747,9 @@ STR_FRAMERATE_DRAWING                   
 
STR_FRAMERATE_DRAWING_VIEWPORTS                                 :{BLACK}  World viewports:
 
STR_FRAMERATE_VIDEO                                             :{BLACK}Video output:
 
STR_FRAMERATE_SOUND                                             :{BLACK}Sound mixing:
 
STR_FRAMERATE_ALLSCRIPTS                                        :{BLACK}  GS/AI total:
 
STR_FRAMERATE_GAMESCRIPT                                        :{BLACK}   Game script:
 
STR_FRAMERATE_AI                                                :{BLACK}   AI {NUM} {RAW_STRING}
 
############ End of leave-in-this-order
 
############ Leave those lines in this order!!
 
STR_FRAMETIME_CAPTION_GAMELOOP                                  :Game loop
 
@@ -2761,6 +2764,9 @@ STR_FRAMETIME_CAPTION_DRAWING           
 
STR_FRAMETIME_CAPTION_DRAWING_VIEWPORTS                         :World viewport rendering
 
STR_FRAMETIME_CAPTION_VIDEO                                     :Video output
 
STR_FRAMETIME_CAPTION_SOUND                                     :Sound mixing
 
STR_FRAMETIME_CAPTION_ALLSCRIPTS                                :GS/AI scripts total
 
STR_FRAMETIME_CAPTION_GAMESCRIPT                                :Game script
 
STR_FRAMETIME_CAPTION_AI                                        :AI {NUM} {RAW_STRING}
 
############ End of leave-in-this-order
 

	
 

	
src/openttd.cpp
Show inline comments
 
@@ -1407,8 +1407,11 @@ void StateGameLoop()
 
		BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP);
 

	
 
#ifndef DEBUG_DUMP_COMMANDS
 
		AI::GameLoop();
 
		Game::GameLoop();
 
		{
 
			PerformanceMeasurer framerate(PFE_ALLSCRIPTS);
 
			AI::GameLoop();
 
			Game::GameLoop();
 
		}
 
#endif
 
		UpdateLandscapingLimits();
 

	
0 comments (0 inline, 0 general)