Browse Source

Poormans profiler

w98-profile
Anders Jenbo 3 years ago
parent
commit
098e9a34ca
  1. 1
      Source/CMakeLists.txt
  2. 10
      Source/diablo.cpp
  3. 6
      Source/engine/render/clx_render.cpp
  4. 7
      Source/engine/render/dun_render.cpp
  5. 39
      Source/engine/render/scrollrt.cpp
  6. 1
      Source/engine/render/scrollrt.h
  7. 7
      Source/engine/render/text_render.cpp
  8. 59
      Source/utils/profiler.cpp
  9. 22
      Source/utils/profiler.h

1
Source/CMakeLists.txt

@ -167,6 +167,7 @@ set(libdevilutionx_SRCS
utils/str_cat.cpp
utils/str_case.cpp
utils/surface_to_clx.cpp
utils/profiler.cpp
utils/timer.cpp
utils/utf8.cpp)

10
Source/diablo.cpp

@ -8,6 +8,7 @@
#include <string_view>
#include <fmt/format.h>
#include <utils/profiler.h>
#include <config.h>
@ -697,6 +698,7 @@ bool HandleTextInput(std::string_view text)
void GameEventHandler(const SDL_Event &event, uint16_t modState)
{
FunctionProfiler profiler(__func__);
StaticVector<ControllerButtonEvent, 4> ctrlEvents = ToControllerButtonEvents(event);
for (ControllerButtonEvent ctrlEvent : ctrlEvents) {
GameAction action;
@ -825,6 +827,7 @@ void RunGameLoop(interface_mode uMsg)
unsigned run_game_iteration = 0;
#endif
FunctionProfiler profiler(__func__);
while (gbRunGame) {
#ifdef _DEBUG
@ -2454,6 +2457,12 @@ int DiabloMain(int argc, char **argv)
DiabloSplash();
mainmenu_loop();
for (const auto &timing : FunctionProfiler::Dump()) {
fmt::print("{}: {}ms ({} calls)\n", timing.name, timing.ms, timing.count);
}
fmt::print("\n");
DiabloDeinit();
return 0;
@ -3002,6 +3011,7 @@ void LoadGameLevel(bool firstflag, lvl_entry lvldir)
bool game_loop(bool bStartup)
{
FunctionProfiler profiler(__func__);
uint16_t wait = bStartup ? sgGameInitInfo.nTickRate * 3 : 3;
for (unsigned i = 0; i < wait; i++) {

6
Source/engine/render/clx_render.cpp

@ -12,6 +12,7 @@
#include "engine/render/scrollrt.h"
#include "utils/attributes.h"
#include "utils/clx_decode.hpp"
#include "utils/profiler.h"
#ifdef DEBUG_CLX
#include <fmt/format.h>
@ -194,6 +195,7 @@ void DoRenderBackwards(
const Surface &out, Point position, const uint8_t *src, size_t srcSize,
unsigned srcWidth, unsigned srcHeight, BlitFn &&blitFn)
{
FunctionProfiler profiler(__func__);
if (position.y < 0 || position.y + 1 >= static_cast<int>(out.h() + srcHeight))
return;
const ClipX clipX = CalculateClipX(position.x, srcWidth, out);
@ -615,6 +617,7 @@ template <bool SkipColorIndexZero>
void RenderClxOutline(const Surface &out, Point position, const uint8_t *src, std::size_t srcSize,
std::size_t srcWidth, uint8_t color)
{
FunctionProfiler profiler(__func__);
RenderSrc srcForBackwards { src, src + srcSize, static_cast<uint_fast16_t>(srcWidth) };
if (position.x > 0 && position.x + static_cast<int>(srcWidth) < static_cast<int>(out.w())) {
RenderClxOutlineClippedY<SkipColorIndexZero>(out, position, srcForBackwards, color);
@ -625,6 +628,7 @@ void RenderClxOutline(const Surface &out, Point position, const uint8_t *src, st
void ClxApplyTrans(ClxSprite sprite, const uint8_t *trn)
{
FunctionProfiler profiler(__func__);
// A bit of a hack but this is the only place in the code where we need mutable sprites.
auto *dst = const_cast<uint8_t *>(sprite.pixelData());
uint16_t remaining = sprite.pixelDataSize();
@ -666,6 +670,7 @@ void ClxApplyTrans(ClxSpriteSheet sheet, const uint8_t *trn)
bool IsPointWithinClx(Point position, ClxSprite clx)
{
FunctionProfiler profiler(__func__);
const uint8_t *src = clx.pixelData();
const uint8_t *end = src + clx.pixelDataSize();
const uint16_t width = clx.width();
@ -719,6 +724,7 @@ bool IsPointWithinClx(Point position, ClxSprite clx)
std::pair<int, int> ClxMeasureSolidHorizontalBounds(ClxSprite clx)
{
FunctionProfiler profiler(__func__);
const uint8_t *src = clx.pixelData();
const uint8_t *end = src + clx.pixelDataSize();
const uint16_t width = clx.width();

7
Source/engine/render/dun_render.cpp

@ -18,6 +18,7 @@
#include <climits>
#include <cstdint>
#include "utils/profiler.h"
#include "engine/render/blit_impl.hpp"
#include "lighting.h"
#include "options.h"
@ -922,6 +923,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderTileType(TileType tile, uint8_t *
template <bool OpaquePrefix, int8_t PrefixIncrement>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderTransparentSquareDispatch(uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip)
{
FunctionProfiler profiler(__func__);
if (tbl == LightTables[LightsMax].data()) {
RenderTransparentSquare<LightType::FullyDark, OpaquePrefix, PrefixIncrement>(dst, dstPitch, src, tbl, clip);
} else if (tbl == LightTables[0].data()) {
@ -964,6 +966,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderRightTrapezoidOrTransparentSquare
template <bool OpaquePrefix, int8_t PrefixIncrement>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderLeftTrapezoidOrTransparentSquareDispatch(TileType tile, uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip)
{
FunctionProfiler profiler(__func__);
if (tbl == LightTables[LightsMax].data()) {
RenderLeftTrapezoidOrTransparentSquare<LightType::FullyDark, OpaquePrefix, PrefixIncrement>(tile, dst, dstPitch, src, tbl, clip);
} else if (tbl == LightTables[0].data()) {
@ -976,6 +979,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderLeftTrapezoidOrTransparentSquareD
template <bool OpaquePrefix, int8_t PrefixIncrement>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderRightTrapezoidOrTransparentSquareDispatch(TileType tile, uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip)
{
FunctionProfiler profiler(__func__);
if (tbl == LightTables[LightsMax].data()) {
RenderRightTrapezoidOrTransparentSquare<LightType::FullyDark, OpaquePrefix, PrefixIncrement>(tile, dst, dstPitch, src, tbl, clip);
} else if (tbl == LightTables[0].data()) {
@ -988,6 +992,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderRightTrapezoidOrTransparentSquare
template <bool Transparent>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderTileDispatch(TileType tile, uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip)
{
FunctionProfiler profiler(__func__);
if (tbl == LightTables[LightsMax].data()) {
RenderTileType<LightType::FullyDark, Transparent>(tile, dst, dstPitch, src, tbl, clip);
} else if (tbl == LightTables[0].data()) {
@ -1126,6 +1131,7 @@ std::string_view MaskTypeToString(MaskType maskType)
void RenderTile(const Surface &out, Point position,
LevelCelBlock levelCelBlock, MaskType maskType, const uint8_t *tbl)
{
FunctionProfiler profiler(__func__);
const TileType tile = levelCelBlock.type();
#ifdef DEBUG_RENDER_OFFSET_X
@ -1180,6 +1186,7 @@ void RenderTile(const Surface &out, Point position,
void world_draw_black_tile(const Surface &out, int sx, int sy)
{
FunctionProfiler profiler(__func__);
#ifdef DEBUG_RENDER_OFFSET_X
sx += DEBUG_RENDER_OFFSET_X;
#endif

39
Source/engine/render/scrollrt.cpp

@ -86,6 +86,7 @@ std::unordered_multimap<WorldTilePosition, Missile *> MissilesAtRenderingTile;
*/
bool CouldMissileCollide(Point tile, bool checkPlayerAndMonster)
{
FunctionProfiler profiler(__func__);
if (!InDungeonBounds(tile))
return true;
if (checkPlayerAndMonster) {
@ -100,6 +101,7 @@ bool CouldMissileCollide(Point tile, bool checkPlayerAndMonster)
void UpdateMissilePositionForRendering(Missile &m, int progress)
{
FunctionProfiler profiler(__func__);
DisplacementOf<int64_t> velocity = m.position.velocity;
velocity *= progress;
velocity /= AnimationInfo::baseValueFraction;
@ -113,6 +115,7 @@ void UpdateMissilePositionForRendering(Missile &m, int progress)
void UpdateMissileRendererData(Missile &m)
{
FunctionProfiler profiler(__func__);
m.position.tileForRendering = m.position.tile;
m.position.offsetForRendering = m.position.offset;
@ -155,6 +158,7 @@ void UpdateMissileRendererData(Missile &m)
void UpdateMissilesRendererData()
{
FunctionProfiler profiler(__func__);
MissilesAtRenderingTile.clear();
for (auto &m : Missiles) {
@ -174,6 +178,7 @@ Rectangle PrevCursorRect;
void BlitCursor(uint8_t *dst, uint32_t dstPitch, uint8_t *src, uint32_t srcPitch, uint32_t srcWidth, uint32_t srcHeight)
{
FunctionProfiler profiler(__func__);
for (std::uint32_t i = 0; i < srcHeight; ++i, src += srcPitch, dst += dstPitch) {
memcpy(dst, src, srcWidth);
}
@ -184,6 +189,7 @@ void BlitCursor(uint8_t *dst, uint32_t dstPitch, uint8_t *src, uint32_t srcPitch
*/
void UndrawCursor(const Surface &out)
{
FunctionProfiler profiler(__func__);
DrawnCursor &cursor = GetDrawnCursor();
BlitCursor(&out[cursor.rect.position], out.pitch(), cursor.behindBuffer, cursor.rect.size.width, cursor.rect.size.width, cursor.rect.size.height);
PrevCursorRect = cursor.rect;
@ -191,6 +197,7 @@ void UndrawCursor(const Surface &out)
bool ShouldShowCursor()
{
FunctionProfiler profiler(__func__);
if (ControlMode == ControlTypes::KeyboardAndMouse)
return true;
if (pcurs == CURSOR_TELEPORT)
@ -208,6 +215,7 @@ bool ShouldShowCursor()
*/
void DrawCursor(const Surface &out)
{
FunctionProfiler profiler(__func__);
DrawnCursor &cursor = GetDrawnCursor();
if (IsHardwareCursor()) {
SetHardwareCursorVisible(ShouldShowCursor());
@ -268,6 +276,7 @@ void DrawCursor(const Surface &out)
*/
void DrawMissilePrivate(const Surface &out, const Missile &missile, Point targetBufferPosition, bool pre)
{
FunctionProfiler profiler(__func__);
if (missile._miPreFlag != pre || !missile._miDrawFlag)
return;
@ -290,6 +299,7 @@ void DrawMissilePrivate(const Surface &out, const Missile &missile, Point target
*/
void DrawMissile(const Surface &out, WorldTilePosition tilePosition, Point targetBufferPosition, bool pre)
{
FunctionProfiler profiler(__func__);
const auto [begin, end] = MissilesAtRenderingTile.equal_range(tilePosition);
for (auto it = begin; it != end; ++it) {
DrawMissilePrivate(out, *it->second, targetBufferPosition, pre);
@ -305,6 +315,7 @@ void DrawMissile(const Surface &out, WorldTilePosition tilePosition, Point targe
*/
void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosition, const Monster &monster)
{
FunctionProfiler profiler(__func__);
if (!monster.animInfo.sprites) {
Log("Draw Monster \"{}\": NULL Cel Buffer", monster.name());
return;
@ -334,6 +345,7 @@ void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosit
*/
void DrawPlayerIconHelper(const Surface &out, MissileGraphicID missileGraphicId, Point position, const Player &player, bool infraVision)
{
FunctionProfiler profiler(__func__);
bool lighting = &player != MyPlayer;
if (player.isWalking())
@ -365,6 +377,7 @@ void DrawPlayerIconHelper(const Surface &out, MissileGraphicID missileGraphicId,
*/
void DrawPlayerIcons(const Surface &out, const Player &player, Point position, bool infraVision)
{
FunctionProfiler profiler(__func__);
if (player.pManaShield)
DrawPlayerIconHelper(out, MissileGraphicID::ManaShield, position, player, infraVision);
if (player.wReflections > 0)
@ -380,6 +393,7 @@ void DrawPlayerIcons(const Surface &out, const Player &player, Point position, b
*/
void DrawPlayer(const Surface &out, const Player &player, Point tilePosition, Point targetBufferPosition)
{
FunctionProfiler profiler(__func__);
if (!IsTileLit(tilePosition) && !MyPlayer->_pInfraFlag && !MyPlayer->isOnArenaLevel() && leveltype != DTYPE_TOWN) {
return;
}
@ -422,6 +436,7 @@ void DrawPlayer(const Surface &out, const Player &player, Point tilePosition, Po
*/
void DrawDeadPlayer(const Surface &out, Point tilePosition, Point targetBufferPosition)
{
FunctionProfiler profiler(__func__);
dFlags[tilePosition.x][tilePosition.y] &= ~DungeonFlag::DeadPlayer;
for (Player &player : Players) {
@ -442,6 +457,7 @@ void DrawDeadPlayer(const Surface &out, Point tilePosition, Point targetBufferPo
*/
void DrawObject(const Surface &out, Point tilePosition, Point targetBufferPosition, bool pre)
{
FunctionProfiler profiler(__func__);
if (LightTableIndex >= LightsMax) {
return;
}
@ -480,6 +496,7 @@ static void DrawDungeon(const Surface & /*out*/, Point /*tilePosition*/, Point /
*/
void DrawCell(const Surface &out, Point tilePosition, Point targetBufferPosition)
{
FunctionProfiler profiler(__func__);
const uint16_t levelPieceId = dPiece[tilePosition.x][tilePosition.y];
const MICROS *pMap = &DPieceMicros[levelPieceId];
@ -593,6 +610,7 @@ void DrawCell(const Surface &out, Point tilePosition, Point targetBufferPosition
*/
void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPosition)
{
FunctionProfiler profiler(__func__);
LightTableIndex = dLight[tilePosition.x][tilePosition.y];
const uint8_t *tbl = LightTables[LightTableIndex].data();
@ -627,6 +645,7 @@ void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPositio
*/
void DrawItem(const Surface &out, Point tilePosition, Point targetBufferPosition, bool pre)
{
FunctionProfiler profiler(__func__);
int8_t bItem = dItem[tilePosition.x][tilePosition.y];
if (bItem <= 0)
@ -654,6 +673,7 @@ void DrawItem(const Surface &out, Point tilePosition, Point targetBufferPosition
*/
void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBufferPosition)
{
FunctionProfiler profiler(__func__);
int mi = dMonster[tilePosition.x][tilePosition.y];
bool isNegativeMonster = mi < 0;
mi = std::abs(mi) - 1;
@ -715,6 +735,7 @@ void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBuffe
*/
void DrawPlayerHelper(const Surface &out, const Player &player, Point tilePosition, Point targetBufferPosition)
{
FunctionProfiler profiler(__func__);
DrawPlayer(out, player, tilePosition, targetBufferPosition);
}
@ -726,6 +747,7 @@ void DrawPlayerHelper(const Surface &out, const Player &player, Point tilePositi
*/
void DrawDungeon(const Surface &out, Point tilePosition, Point targetBufferPosition)
{
FunctionProfiler profiler(__func__);
assert(InDungeonBounds(tilePosition));
if (dRendered.test(tilePosition.x, tilePosition.y))
@ -814,6 +836,7 @@ void DrawDungeon(const Surface &out, Point tilePosition, Point targetBufferPosit
*/
void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPosition, int rows, int columns)
{
FunctionProfiler profiler(__func__);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if (InDungeonBounds(tilePosition)) {
@ -845,6 +868,7 @@ void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPositio
bool IsWall(Point position)
{
FunctionProfiler profiler(__func__);
return TileHasAny(dPiece[position.x][position.y], TileProperties::Solid) || dSpecial[position.x][position.y] != 0;
}
@ -858,6 +882,7 @@ bool IsWall(Point position)
*/
void DrawTileContent(const Surface &out, Point tilePosition, Point targetBufferPosition, int rows, int columns)
{
FunctionProfiler profiler(__func__);
// Keep evaluating until MicroTiles can't affect screen
rows += MicroTileLen;
dRendered.reset();
@ -907,6 +932,7 @@ void DrawTileContent(const Surface &out, Point tilePosition, Point targetBufferP
*/
void Zoom(const Surface &out)
{
FunctionProfiler profiler(__func__);
int viewportWidth = out.w();
int viewportOffsetX = 0;
if (CanPanelsCoverView()) {
@ -964,6 +990,7 @@ int tileRows;
void CalcFirstTilePosition(Point &position, Displacement &offset)
{
FunctionProfiler profiler(__func__);
// Adjust by player offset and tile grid alignment
Player &myPlayer = *MyPlayer;
offset = tileOffset;
@ -1015,6 +1042,7 @@ void CalcFirstTilePosition(Point &position, Displacement &offset)
*/
void DrawGame(const Surface &fullOut, Point position, Displacement offset)
{
FunctionProfiler profiler(__func__);
// Limit rendering to the view area
const Surface &out = !*sgOptions.Graphics.zoom
? fullOut.subregionY(0, gnViewportHeight)
@ -1093,6 +1121,7 @@ void DrawGame(const Surface &fullOut, Point position, Displacement offset)
*/
void DrawView(const Surface &out, Point startPosition)
{
FunctionProfiler profiler(__func__);
#ifdef _DEBUG
DebugCoordsMap.clear();
#endif
@ -1263,6 +1292,7 @@ void DrawFPS(const Surface &out)
*/
void DoBlitScreen(int x, int y, int w, int h)
{
FunctionProfiler profiler(__func__);
#ifdef DEBUG_DO_BLIT_SCREEN
const Surface &out = GlobalBackBuffer();
const uint8_t debugColor = PAL8_RED;
@ -1291,6 +1321,7 @@ void DrawMain(const Surface &out, int dwHgt, bool drawDesc, bool drawHp, bool dr
if (!gbActive || RenderDirectlyToOutputSurface) {
return;
}
FunctionProfiler profiler(__func__);
assert(dwHgt >= 0 && dwHgt <= gnScreenHeight);
@ -1339,6 +1370,7 @@ void DrawMain(const Surface &out, int dwHgt, bool drawDesc, bool drawHp, bool dr
Displacement GetOffsetForWalking(const AnimationInfo &animationInfo, const Direction dir, bool cameraMode /*= false*/)
{
FunctionProfiler profiler(__func__);
// clang-format off
// South, SouthWest, West, NorthWest, North, NorthEast, East, SouthEast,
constexpr Displacement StartOffset[8] = { { 0, -32 }, { 32, -16 }, { 64, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { -64, 0 }, { -32, -16 } };
@ -1372,6 +1404,7 @@ void ShiftGrid(int *x, int *y, int horizontal, int vertical)
int RowsCoveredByPanel()
{
FunctionProfiler profiler(__func__);
auto &mainPanelSize = GetMainPanel().size;
if (GetScreenWidth() <= mainPanelSize.width) {
return 0;
@ -1387,6 +1420,7 @@ int RowsCoveredByPanel()
void CalcTileOffset(int *offsetX, int *offsetY)
{
FunctionProfiler profiler(__func__);
uint16_t screenWidth = GetScreenWidth();
uint16_t viewportHeight = GetViewportHeight();
@ -1412,6 +1446,7 @@ void CalcTileOffset(int *offsetX, int *offsetY)
void TilesInView(int *rcolumns, int *rrows)
{
FunctionProfiler profiler(__func__);
uint16_t screenWidth = GetScreenWidth();
uint16_t viewportHeight = GetViewportHeight();
@ -1489,6 +1524,7 @@ void CalcViewportGeometry()
Point GetScreenPosition(Point tile)
{
FunctionProfiler profiler(__func__);
Point firstTile = ViewPosition;
Displacement offset = {};
CalcFirstTilePosition(firstTile, offset);
@ -1507,6 +1543,7 @@ void ClearScreenBuffer()
{
if (HeadlessMode)
return;
FunctionProfiler profiler(__func__);
assert(PalSurface != nullptr);
SDL_FillRect(PalSurface, nullptr, 0);
@ -1583,6 +1620,7 @@ void scrollrt_draw_game_screen()
{
if (HeadlessMode)
return;
FunctionProfiler profiler(__func__);
int hgt = 0;
@ -1604,6 +1642,7 @@ void DrawAndBlit()
if (!gbRunGame || HeadlessMode) {
return;
}
FunctionProfiler profiler(__func__);
int hgt = 0;
bool drawHealth = IsRedrawComponent(PanelDrawComponent::Health);

1
Source/engine/render/scrollrt.h

@ -7,6 +7,7 @@
#include <cstdint>
#include <utils/profiler.h>
#include "engine.h"
#include "engine/animationinfo.h"
#include "engine/point.hpp"

7
Source/engine/render/text_render.cpp

@ -15,6 +15,7 @@
#include <fmt/core.h>
#include "utils/profiler.h"
#include "DiabloUI/diabloui.h"
#include "DiabloUI/ui_item.h"
#include "engine.h"
@ -469,6 +470,7 @@ void UnloadFonts()
int GetLineWidth(std::string_view text, GameFontTables size, int spacing, int *charactersInLine)
{
FunctionProfiler profiler(__func__);
int lineWidth = 0;
CurrentFont currentFont;
uint32_t codepoints = 0;
@ -502,6 +504,7 @@ int GetLineWidth(std::string_view text, GameFontTables size, int spacing, int *c
int GetLineWidth(std::string_view fmt, DrawStringFormatArg *args, std::size_t argsLen, size_t argsOffset, GameFontTables size, int spacing, int *charactersInLine)
{
FunctionProfiler profiler(__func__);
int lineWidth = 0;
CurrentFont currentFont;
@ -555,6 +558,7 @@ int GetLineWidth(std::string_view fmt, DrawStringFormatArg *args, std::size_t ar
int GetLineHeight(std::string_view text, GameFontTables fontIndex)
{
FunctionProfiler profiler(__func__);
if (fontIndex == GameFont12 && IsSmallFontTall() && ContainsSmallFontTallCodepoints(text)) {
return SmallFontTallLineHeight;
}
@ -574,6 +578,7 @@ int AdjustSpacingToFitHorizontally(int &lineWidth, int maxSpacing, int character
std::string WordWrapString(std::string_view text, unsigned width, GameFontTables size, int spacing)
{
FunctionProfiler profiler(__func__);
std::string output;
if (text.empty() || text[0] == '\0')
return output;
@ -660,6 +665,7 @@ std::string WordWrapString(std::string_view text, unsigned width, GameFontTables
*/
uint32_t DrawString(const Surface &out, std::string_view text, const Rectangle &rect, UiFlags flags, int spacing, int lineHeight)
{
FunctionProfiler profiler(__func__);
GameFontTables size = GetSizeFromFlags(flags);
text_color color = GetColorFromFlags(flags);
@ -710,6 +716,7 @@ uint32_t DrawString(const Surface &out, std::string_view text, const Rectangle &
void DrawStringWithColors(const Surface &out, std::string_view fmt, DrawStringFormatArg *args, std::size_t argsLen, const Rectangle &rect, UiFlags flags, int spacing, int lineHeight)
{
FunctionProfiler profiler(__func__);
GameFontTables size = GetSizeFromFlags(flags);
text_color color = GetColorFromFlags(flags);

59
Source/utils/profiler.cpp

@ -0,0 +1,59 @@
#include <utils/profiler.h>
#include <algorithm>
#include <unordered_map>
#include <windows.h>
#include <SDL.h>
std::unordered_map<std::string, TimingInfo> timings;
FunctionProfiler::FunctionProfiler(std::string name)
: _name(name)
{
LARGE_INTEGER frequency;
if (QueryPerformanceFrequency(&frequency)) {
_frequency = frequency.QuadPart;
} else {
_frequency = 1000;
}
LARGE_INTEGER ticks;
if (QueryPerformanceCounter(&ticks)) {
_start = ticks.QuadPart;
} else {
_start = SDL_GetTicks() * _frequency / 1000;
}
}
FunctionProfiler::~FunctionProfiler()
{
LARGE_INTEGER ticks;
uint64_t now;
if (QueryPerformanceCounter(&ticks)) {
now = ticks.QuadPart;
} else {
now = SDL_GetTicks() * _frequency / 1000;
}
double ms = (double)(now - _start) * 1000.0 / (double)_frequency;
TimingInfo &timing = timings[_name];
timing.ms += ms;
timing.count++;
}
static bool CompareTiming(const TimingInfo &a, const TimingInfo &b)
{
return a.ms > b.ms;
}
std::vector<TimingInfo> FunctionProfiler::Dump()
{
std::vector<TimingInfo> timingList;
for (auto it = timings.begin(); it != timings.end(); ++it) {
it->second.name = it->first;
timingList.push_back(it->second);
}
std::sort(timingList.begin(), timingList.end(), CompareTiming);
return timingList;
}

22
Source/utils/profiler.h

@ -0,0 +1,22 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
struct TimingInfo {
std::string name;
double ms;
int count;
};
class FunctionProfiler {
public:
FunctionProfiler(std::string name);
~FunctionProfiler();
static std::vector<TimingInfo> Dump();
private:
std::string _name;
uint64_t _frequency;
uint64_t _start;
};
Loading…
Cancel
Save