| CRM64Pro GDK v0.19.0 A free cross-platform game development kit built on top of SDL 3.0

Loading...
Searching...
No Matches
Timer
Core modules

## Description

Timer module for timing control, frame rates and micro-benchmarking [v26.02.0].

### Overview

The Timer module manages all timing-related functionality including timer control, Render Frame Rate, Logic Frame Rate and micro-benchmarks. The Timer must be initiated with Timer::init().
One of the most important features is the fixed virtual logic frame rate with interpolation, which is implemented in this module and in Main::update() method.

### Key features

- Timer control: Core timing management for application execution
- Render Frame Rate (RFR): Asynchronous rendering rate control
- Logic Frame Rate (LFR): Synchronous logic execution rate control
- Micro-benchmarking: Statistical analysis of code snippet performance
- Fixed virtual logic frame rate: Interpolation support for smooth gameplay

### Frame rate types

By default, no preferred Render and Logic Frame Rate are set (both equal to 0). Use setRate() to configure specific values. Rates can be throttled down, but upper limits are imposed by the underlying hardware and ConfigMgr::setMTFriendly() value.

Render Frame Rate (RFR) | Asynchronous rate that does not stop your main loop. Renders all enabled and visible screens at the preferred rate. This rate is not guaranteed as some render frames may be dropped to maintain stable LFR. When vsync is enabled, set RFR to 0 for smoothest output
Logic Frame Rate (LFR) | Synchronous rate that slows down your main loop to accommodate this rate. Under normal conditions (hardware can execute at preferred ratio), this rate remains quite stable

### Micro-benchmarking system

The micro-benchmarking system measures small code snippets, capturing execution time and calculating statistical analysis on those measurements. It supports both latency and throughput benchmarks.

Benchmark metric types

BM_LATENCY | Measures execution time in milliseconds (lower is better). Default type.
BM_THROUGHPUT | Measures base work units per second (higher is better). Requires workAmount in benchStop(). Output can be scaled automatically, for example from B/s to MB/s.

Thread safety
Although the system is not fully thread-safe, it can be made thread-safe by following these steps:

1. Create micro-benchmarks on the same thread (usually main)
2. Use each benchmark on different threads
3. Close benchmarks from the same thread where they were created

Benchmark workflow

benchCreate() | Create a named benchmark with estimated run count, unit, and metric type
benchStart() | Start a measurement cycle
benchStop() | Stop the current measurement cycle and optionally record work amount (for throughput benchmarks)
benchStats() | Retrieve statistical results into a Timer::Stats structure
benchInfo() | Display benchmark statistics to the default log
benchInfoEx() | Generate interactive HTML report with charts and statistics
benchClose() | Close the benchmark and release resources

### Usage examples

Deterministic function testing
Testing a function with a known number of iterations:

Main &mC64 = Main::instance();
Timer::Stats Stats;
Sint32 iRuns = 1000;
Sint32 idBench = mC64.timer().benchCreate("benchMain", iRuns);
for(Sint32 i = 0; i < iRuns; ++i)
{
mC64.timer().benchStart(idBench);
func_to_be_tested();
mC64.timer().benchStop(idBench);
}
mC64.timer().benchStats(idBench, Stats);
// Optionally call mC64.timer().benchInfo(idBench) to display stats via the default log
mC64.timer().benchClose(idBench);
CRM64Pro::Main::instance
static Main & instance()
Access the Main singleton.
Definition CoreMain.cpp:461

Application behavior profiling
Measuring logic and render performance throughout application lifetime:

Main &mC64 = Main::instance();
Sint32 iRuns = 10000; // Estimation; more will be allocated if needed
Sint32 idBenchL = mC64.timer().benchCreate("benchMain-Logic", iRuns);
Sint32 idBenchR = mC64.timer().benchCreate("benchMain-Render", iRuns);
while(iDone == 0)
{
// Logic stuff
mC64.timer().benchStart(idBenchL);
...
mC64.timer().benchStop(idBenchL);
// Render stuff
mC64.timer().benchStart(idBenchR);
...
mC64.timer().benchStop(idBenchR);
}
mC64.timer().info(); // Displays all benchmarks stats
mC64.timer().benchClose(idBenchL);
mC64.timer().benchClose(idBenchR);

Throughput benchmark (file I/O)
Measuring data processing throughput in MB/s:

Main &mC64 = Main::instance();
Sint32 iRuns = 100;
Sint32 idBench = mC64.timer().benchCreate("FileRead", iRuns, "B/s", Timer::BM_THROUGHPUT);
for(Sint32 i = 0; i < iRuns; ++i)
{
mC64.timer().benchStart(idBench);
Uint64 iBytes = ReadDataFromFile();
mC64.timer().benchStop(idBench, iBytes);
}
mC64.timer().benchInfo(idBench); // Shows average MB/s, fastest, slowest, etc.
mC64.timer().benchClose(idBench);
CRM64Pro::Timer::BM_THROUGHPUT
@ BM_THROUGHPUT
Work units per second. Higher is better.
Definition CRM64Pro.h:2282

Throughput benchmark (operations)
Measuring computational throughput in operations/second:

Main &mC64 = Main::instance();
Sint32 idBench = mC64.timer().benchCreate("HashOps", 1000, "ops/s", Timer::BM_THROUGHPUT);
for(Sint32 i = 0; i < 1000; ++i)
{
mC64.timer().benchStart(idBench);
Sint32 count = CalculateHashes(); // May calculate multiple hashes per iteration
mC64.timer().benchStop(idBench, count); // Record number of operations
}
mC64.timer().benchInfoEx(idBench, "Hash Performance"); // Generate HTML report
mC64.timer().benchClose(idBench);

### Best practices

- Always call Timer::init() before using any timer functionality
- Use setRate() to configure specific RFR and LFR values based on your application needs
- Set RFR to 0 when vsync is enabled for the smoothest rendering output
- Keep in mind that RFR applies to all enabled and visible screens
- For micro-benchmarks, provide a reasonable estimation of run count to minimize reallocations
- For LATENCY benchmarks: use the canonical millisecond unit
- For THROUGHPUT benchmarks: pass workAmount in the base unit named by sUnit, such as bytes for B/s or operations for ops/s
- When comparing benchmarks in benchInfoEx(), ensure all have the same unit and metric type
- Create and close benchmarks on the same thread to ensure thread safety
- Access the module exclusively through Main::timer()

Note
  The Timer module is a singleton, automatically created once Main is instantiated. You can get a reference to this module using Main::timer() method.
  The Timer module is automatically released when Main::terminate() is called. At this time, any resource still loaded will be released, avoiding resource leaks.

## Classes
class | CRM64Pro::Timer
| Timer class. More...

## Enumerations
enum | CRM64Pro::eTimerState : Sint32 { CRM64Pro::TS_INIT = 0 , CRM64Pro::TS_RESET = 1 }
| Timer init state. More...

## Functions
bool | CRM64Pro::Timer::info (Sint32 iMode=0) override
| Request Timer module information.
bool | CRM64Pro::Timer::init (eTimerState eState=TS_INIT)
| Initialize the timer system.
bool | CRM64Pro::Timer::setRate (Uint16 iR, Uint16 iL)
| Set preferred Render and Logic Frame Rate.
Sint32 | CRM64Pro::Timer::getLFR () const
| Get the preferred Logic Frame Rate.
Sint32 | CRM64Pro::Timer::getRFR () const
| Get the preferred Render Frame Rate.
float | CRM64Pro::Timer::getAverageRFR () const
| Get the average Render Frame Rate since the last timer init or reset.
float | CRM64Pro::Timer::getAverageLFR () const
| Get the average Logic Frame Rate since the last timer init or reset.
Uint32 | CRM64Pro::Timer::getCurrentRFR () const
| Get current Render Frame Rate during last recent second.
Uint32 | CRM64Pro::Timer::getCurrentLFR () const
| Get current Logic Frame Rate during last recent second.
Uint32 | CRM64Pro::Timer::getRenderFrames () const
| Get total render frames since the last timer init or reset.
Uint32 | CRM64Pro::Timer::getLogicFrames () const
| Get total logic frames since the last timer init or reset.
float | CRM64Pro::Timer::getTime () const
| Get the execution time (in seconds) since the last timer init or reset.
Uint64 | CRM64Pro::Timer::getTicks () const
| Get the execution time (in milliseconds) since the last timer init or reset.
Uint64 | CRM64Pro::Timer::getTicksNow () const
| Get the execution time (in milliseconds) since the last timer init or reset.
Uint64 | CRM64Pro::Timer::getHiResTime () const
| Get the execution time (in nanoseconds) since the last timer init or reset.
Sint32 | CRM64Pro::Timer::benchCreate (const string &sName, Sint32 iRuns=0, const string &sUnit="ms", eBenchMetric eMetric=BM_LATENCY)
| Create a microbenchmark.
bool | CRM64Pro::Timer::benchStart (Sint32 idBench)
| Start a microbenchmark measurement cycle.
bool | CRM64Pro::Timer::benchStop (Sint32 idBench, Uint64 workAmount=1)
| Stop a microbenchmark measurement cycle.
bool | CRM64Pro::Timer::benchClose (Sint32 idBench)
| Close a microbenchmark.
bool | CRM64Pro::Timer::benchStats (Sint32 idBench, Stats &stats)
| Calculate the statistical analysis given the current measurements.
bool | CRM64Pro::Timer::benchInfo (Sint32 idBench)
| Display benchmark information to the default log.
bool | CRM64Pro::Timer::benchInfoEx (Sint32 idBench, const string &sTitle="Report")
| Generate HTML benchmark report for a single benchmark.
bool | CRM64Pro::Timer::benchInfoEx (const vector< Sint32 > &vBenchIds, const string &sTitle="Report")
| Generate HTML benchmark report for multiple benchmarks.

## Enumeration Type Documentation

## ◆ eTimerState

enum CRM64Pro::eTimerState : Sint32

Timer init state.

Enumerator
TS_INIT | 'eState' parameter in Timer::init(), initializes or resets all timer settings.
TS_RESET | 'eState' parameter in Timer::init(), only resets the timer if it was previously initialized keeping RFR and LFR rates.

## Function Documentation

## ◆ info()

bool CRM64Pro::Timer::info | ( | Sint32 | iMode = 0 | ) |
| override

Request Timer module information.

Writes Timer module information to the default log.

Parameters

  iMode | Reserved for future use. Pass 0.

Returns
  true on success, or false on failure.

## ◆ init()

bool CRM64Pro::Timer::init | ( | eTimerState | eState = TS_INIT | ) |

Initialize the timer system.

The first call to this method initializes the SDL timer subsystem.

Parameters

  eState | Check ::eTimerState enum for further information. Default is TS_INIT.

Returns
  true on success, or false on failure.

Note
  init(TS_RESET) is called internally by Main::terminate().

## ◆ setRate()

bool CRM64Pro::Timer::setRate | ( | Uint16 | iR,
|  | Uint16 | iL )

Set preferred Render and Logic Frame Rate.

Parameters

  iR | preferred Render Frame Rate. Default 0 means unlimited. Maximum value is 500.
  iL | preferred Logic Frame Rate. Default 0 means unlimited. Maximum value is 20000.

Returns
  true on success, or false on failure.

## ◆ getLFR()

Sint32 CRM64Pro::Timer::getLFR | ( |  | ) | const

Get the preferred Logic Frame Rate.

Returns
  The configured Logic Frame Rate (0 means unlimited), or -1 on failure.

## ◆ getRFR()

Sint32 CRM64Pro::Timer::getRFR | ( |  | ) | const

Get the preferred Render Frame Rate.

Returns
  The configured Render Frame Rate (0 means unlimited), or -1 on failure.

## ◆ getAverageRFR()

float CRM64Pro::Timer::getAverageRFR | ( |  | ) | const

Get the average Render Frame Rate since the last timer init or reset.

Returns
  The average Render Frame Rate, or -1 on failure.

## ◆ getAverageLFR()

float CRM64Pro::Timer::getAverageLFR | ( |  | ) | const

Get the average Logic Frame Rate since the last timer init or reset.

Returns
  The average Logic Frame Rate, or -1 on failure.

## ◆ getCurrentRFR()

Uint32 CRM64Pro::Timer::getCurrentRFR | ( |  | ) | const

Get current Render Frame Rate during last recent second.

Returns
  Render Frame Rate.

## ◆ getCurrentLFR()

Uint32 CRM64Pro::Timer::getCurrentLFR | ( |  | ) | const

Get current Logic Frame Rate during last recent second.

Returns
  Logic Frame Rate.

## ◆ getRenderFrames()

Uint32 CRM64Pro::Timer::getRenderFrames | ( |  | ) | const

Get total render frames since the last timer init or reset.

Returns
  Total number of Render frames.

## ◆ getLogicFrames()

Uint32 CRM64Pro::Timer::getLogicFrames | ( |  | ) | const

Get total logic frames since the last timer init or reset.

Returns
  Total number of Logic frames.

## ◆ getTime()

float CRM64Pro::Timer::getTime | ( |  | ) | const

Get the execution time (in seconds) since the last timer init or reset.

This time will be constant inside the same Logic Frame iteration and will be updated on Main::update() if a new Logic Frame must be produced.

Returns
  The elapsed time in seconds, or -1 on failure.

## ◆ getTicks()

Uint64 CRM64Pro::Timer::getTicks | ( |  | ) | const

Get the execution time (in milliseconds) since the last timer init or reset.

This time will be constant inside the same Logic Frame iteration and will be updated on Main::update() if a new Logic Frame must be produced.

Returns
  Uint64 value with the milliseconds.

## ◆ getTicksNow()

Uint64 CRM64Pro::Timer::getTicksNow | ( |  | ) | const

Get the execution time (in milliseconds) since the last timer init or reset.

This time will be exactly the "now" time, in other words, it is not linked anyway to the Logic Frame iteration.

Returns
  Uint64 value with the milliseconds.

## ◆ getHiResTime()

Uint64 CRM64Pro::Timer::getHiResTime | ( |  | ) | const

Get the execution time (in nanoseconds) since the last timer init or reset.

This is the high resolution timer when you need more accurate time precision.

Returns
  Uint64 value with the nanoseconds.

## ◆ benchCreate()

Sint32 CRM64Pro::Timer::benchCreate | ( | const string & | sName,
|  | Sint32 | iRuns = 0,
|  | const string & | sUnit = "ms",
|  | eBenchMetric | eMetric = BM_LATENCY )

Create a microbenchmark.

Creates a named benchmark with an estimated number of measurement runs.

Parameters

  sName | string with the name of this benchmark.
  iRuns | estimated number of runs. Default 0 (automatically managed).
  sUnit | Display unit. ::BM_LATENCY requires "ms". For ::BM_THROUGHPUT, use the rate label matching workAmount (e.g., "B/s" or "ops/s"). No conversion is inferred from this string.
  eMetric | metric direction: BM_LATENCY (lower is better) or BM_THROUGHPUT (higher is better). Default BM_LATENCY.

Returns
  Greater than 0 on success (the Bench id), or a negative error code on failure.

Note
  If a benchmark with the same name already exists, it returns the existing Bench id.

## ◆ benchStart()

bool CRM64Pro::Timer::benchStart | ( | Sint32 | idBench | ) |

Start a microbenchmark measurement cycle.

Parameters

  idBench | Bench id.

Returns
  true on success, or false on failure.

Note
  Each benchStart() must be followed by a benchStop().

## ◆ benchStop()

bool CRM64Pro::Timer::benchStop | ( | Sint32 | idBench,
|  | Uint64 | workAmount = 1 )

Stop a microbenchmark measurement cycle.

Stops the measurement and records the elapsed time. For throughput benchmarks, also records the amount of work completed to calculate throughput.

Parameters

  idBench | Bench id.
  workAmount | Amount of work completed during this measurement cycle. For ::BM_LATENCY benchmarks, this value is ignored. For ::BM_THROUGHPUT benchmarks, pass the base work quantity matching sUnit (e.g., bytes for "B/s" or operations for "ops/s").

Returns
  true on success, or false on failure.

Note
  Each benchStart() must be followed by a benchStop(). ::BM_LATENCY stores elapsed time in milliseconds. ::BM_THROUGHPUT stores workAmount / elapsed_time in work units per second.

## ◆ benchClose()

bool CRM64Pro::Timer::benchClose | ( | Sint32 | idBench | ) |

Close a microbenchmark.

Frees the resources of the benchmark and its stats.

Parameters

  idBench | Bench id. Use -1 to close all benchmarks.

Returns
  true on success, or false on failure.

## ◆ benchStats()

bool CRM64Pro::Timer::benchStats | ( | Sint32 | idBench,
|  | Stats & | stats )

Calculate the statistical analysis given the current measurements.

Parameters

  idBench | Bench id.
  stats | Stats structure to fill. Values use the units documented by Stats and selected metric.

Returns
  true on success, or false on failure.

## ◆ benchInfo()

bool CRM64Pro::Timer::benchInfo | ( | Sint32 | idBench | ) |

Display benchmark information to the default log.

Outputs the benchmark statistics to the default log.

Parameters

  idBench | Bench id.

Returns
  true on success, or false on failure.

Note
  If statistics haven't been calculated yet, benchStats() will be called automatically.

## ◆ benchInfoEx() [1/2]

bool CRM64Pro::Timer::benchInfoEx | ( | Sint32 | idBench,
|  | const string & | sTitle = "Report" )

Generate HTML benchmark report for a single benchmark.

Parameters

  idBench | Bench id.
  sTitle | Report title used in the HTML and filename. Default "Report".

Returns
  true on success, or false on failure.

Note
  Unit and metric direction are read from the benchmark properties set during benchCreate(). Generates file: Microbench_{TITLE}_YYYYMMDD_HHMMSS.html in the current working directory.

## ◆ benchInfoEx() [2/2]

bool CRM64Pro::Timer::benchInfoEx | ( | const vector< Sint32 > & | vBenchIds,
|  | const string & | sTitle = "Report" )

Generate HTML benchmark report for multiple benchmarks.

Parameters

  vBenchIds | Vector of Bench ids to include in the report.
  sTitle | Report title used in the HTML and filename. Default "Report".

Returns
  true on success, or false on failure.

Note
  Unit and metric direction are read from the first benchmark in the vector. If other benchmarks have different units/metrics, a warning is logged but processing continues. The first benchmark in the vector is used as baseline for delta calculations. Generates file: Microbench_{TITLE}_YYYYMMDD_HHMMSS.html in the current working directory.