summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Martin Hansen <nielsm@indvikleren.dk>2019-02-04 01:26:55 +0100
committerNiels Martin Hansen <nielsm@indvikleren.dk>2019-02-23 14:29:07 +0100
commit7e1e2756d4fdbd9c2fb3508b4213de8dc855f21c (patch)
tree15e4f7b212bafdd3e83653aca1a465a5f6f4461b
parent4adb91202d7c0118b52daeab2c4e6b040b30e4a9 (diff)
downloadopenttd-7e1e2756d4fdbd9c2fb3508b4213de8dc855f21c.tar.xz
Add: Show performance of AI and GS in framerate window
-rw-r--r--README.md6
-rw-r--r--src/ai/ai_core.cpp5
-rw-r--r--src/framerate_gui.cpp151
-rw-r--r--src/framerate_type.h18
-rw-r--r--src/game/game_core.cpp13
-rw-r--r--src/lang/english.txt6
-rw-r--r--src/openttd.cpp7
7 files changed, 187 insertions, 19 deletions
diff --git a/README.md b/README.md
index 7c842a1f8..038c177a7 100644
--- a/README.md
+++ b/README.md
@@ -476,6 +476,12 @@ The following is an explanation of the different statistics:
- *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,
diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp
index d4ff23311..51522edaf 100644
--- a/src/ai/ai_core.cpp
+++ b/src/ai/ai_core.cpp
@@ -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);
diff --git a/src/framerate_gui.cpp b/src/framerate_gui.cpp
index 908cf81c0..36ec7e1f2 100644
--- a/src/framerate_gui.cpp
+++ b/src/framerate_gui.cpp
@@ -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(PerformanceElement elem)
/** 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::SetExpectedRate(double rate)
_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(PerformanceElement elem)
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_window_widgets[] = {
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));
diff --git a/src/framerate_type.h b/src/framerate_type.h
index 8df9a279a..3c54e0307 100644
--- a/src/framerate_type.h
+++ b/src/framerate_type.h
@@ -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);
};
diff --git a/src/game/game_core.cpp b/src/game/game_core.cpp
index 2f95e2622..10b079bee 100644
--- a/src/game/game_core.cpp
+++ b/src/game/game_core.cpp
@@ -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++;
diff --git a/src/lang/english.txt b/src/lang/english.txt
index 3c5c7dcdf..6c482f053 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -2747,6 +2747,9 @@ STR_FRAMERATE_DRAWING :{BLACK}Graphics
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 :Graphics render
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
diff --git a/src/openttd.cpp b/src/openttd.cpp
index e876ffda7..6265b9684 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -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();