MQLplus/lib_debug/example/LibDebug_Runtime.mq5
super.admin 466f9ca5c5 convert
2025-05-30 16:09:52 +02:00

390 lines
12 KiB
MQL5

/**********************************************************************************
* Copyright (C) 2020 Dominik Egert <info@freie-netze.de>
*
* This file is the lib_debug demonstration file.
*
* Lisence applied: Free, no license applied to this file.
*
* Author Dominik Egert / Freie Netze UG.
**********************************************************************************
*
* Version: 1.01
* State: public
*
* File information
* ================
*
*/
#property version "1.01"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Performance profiling
//
// This feature is only active in runtime builds of your program, and if you activate the flag
// as shown below.
//
// Compile your project and load it onto a chart in the Terminal.
//
/////////////////////////////////////////
//
// Include the library
//
#define LIB_PERF_PROFILING
#include <MQLplus/lib_debug.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Some initial debug message
DBG_MSG("Example how to use lib_debug.mqh for performance metrics");
// Output details about current program
// Available in debugging and runtime
printf("%s", DBG_STR_EX45_FILEINFO);
/////////////////////////////////////////////////////////////////////////////
//
// Standalone performance macros example
//
// To measure certain parts of code in a standalone environment,
// following macros are implemented to do this.
//
// There are three variations of this macro available. Depending on
// the return value of the function to be measured, either having
// a return value, a return object or not having a return value, you
// need to use the appropiate macro.
//
// PERF_COUNTER_TIMEIT_V (V = void)
// This macro is used to measure functions or function sequences
// that do not have a return value.
//
// PERF_COUNTER_TIMEIT_R (R = return)
// This macro will return the resulting value (return value)
// of the function being called, or their combination of such.
// For a better understanding, see the examples below.
//
// PERF_COUNTER_TIMEIT_O (O = Object)
// This macro will return the object (returned by the function)
// of the function being called.
//
// NOTE:
//
// PERF_COUNTER_TIMEIT_V may not be mentioned more than once per line of code.
// Internally the macro uses the __LINE__ macro for identifying the call,
// therefore it is mandatory to have only one call per code line.
// Also be aware, if including this macro inside of another macro, all
// statements will be on one line of code.
//
// PERF_COUNTER_TIMEIT_R uses the complier macro __COUNTER__ to identify
// unique its callings. Be aware, in case you rely on the sequence of
// counting provided by __COUNTER__ within your code. Each mentioning of
// the macro "PERF_COUNTER_TIMEIT_R" will increase the __COUNTER__ by one.
//
// PERF_COUNTER_TIMEIT_O notes are same as for PERF_COUNTER_TIMEIT_R, with
// one addition: The Copy-Constructor of the returned object will be called
// twice. The first call contributes to the measurement results, the second
// consequently does not. In order to encapusalte the function calls, an
// additional copy of the object is required within the process of returning
// values from the function.
//
// For pointers as return value, either macro "PERF_COUNTER_TIMEIT_R" or
// "PERF_COUNTER_TIMEIT_O" can be used. - Both work the same way in this case.
//
// A single function call
PERF_COUNTER_TIMEIT_V(
printf("Some text A");
);
// A block sequence of function calls
PERF_COUNTER_TIMEIT_V(
printf("Some text B");
printf("Some text C");
);
// Example of complex measurements
b_start();
// Return
return(INIT_SUCCEEDED);
}
// Some simple functions to be measured in their runtime
int f1() { Sleep(100); return(1); }
int f2() { Sleep(200); return(2); }
int f3() { Sleep(300); return(3); }
// A collection of function calls
int g()
{
return(PERF_COUNTER_TIMEIT_R(f1() + f2() + f3() == 6) ?
PERF_COUNTER_TIMEIT_R(f1() * f2()) : 0);
}
//+------------------------------------------------------------------+
//| Service program start function |
//+------------------------------------------------------------------+
void b_start()
{
if (PERF_COUNTER_TIMEIT_R(g()) == 2)
{
PERF_COUNTER_TIMEIT_V(
Print(f3() == 3);
);
}
PERF_COUNTER_TIMEIT_V(
Print(f1());
);
PERF_COUNTER_TIMEIT_V(
Print(f2());
);
return;
};
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Destroy timer
EventKillTimer();
// Return
return;
}
///////////////////////////////////////////////////////////////////////
//
// In OnTick we will make use of the full trace integration macros.
//
// Here the macros will be reduced to only perform runtime
// performance data gathering and printing to expert journal.
//
// Turn on tracing
#define DBG_TRACE_EXPERT_MAIN_ONTICK
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
/////////////////////////////////////
// Function debug trace code
#ifdef DBG_TRACE_EXPERT_MAIN_ONTICK
#undef DBG_TRACE_EXPERT_MAIN_ONTICK
#define DBG_TRACE_EXPERT_MAIN_ONTICK(x) x
#define DBG_TRACE_EXPERT_MAIN_ONTICK_RETURN DBG_MSG_TRACE_RETURN
#else
#define DBG_TRACE_EXPERT_MAIN_ONTICK(x)
#define DBG_TRACE_EXPERT_MAIN_ONTICK_RETURN DBG_MSG_NOTRACE_RETURN
#endif
/////////////////////////////////////
void OnTick()
{
DBG_TRACE_EXPERT_MAIN_ONTICK(
DBG_MSG_TRACE_BEGIN;
);
PERF_COUNTER_BEGIN;
// Local init
int some_var = MathRand();
// Some random check operation
if((some_var % 2) == 0)
{
call_sub_function();
call_sub2_function();
call_obj_function();
}
// Some eventual exit at annother point inside the functions body
if((some_var % 2048) == 0)
{ DBG_TRACE_EXPERT_MAIN_ONTICK_RETURN; }
// Return
DBG_TRACE_EXPERT_MAIN_ONTICK_RETURN;
}
///////////////////////////////////////////////////////////////////////
//
// In OnTimer we will use only the performance metrics macros.
//
// For ease of use, a return macro will be defined. This is the
// only requirement for performance metrics to be displayed in the
// experts journal.
//
// Performance macros are enabled only in release versions
// of the code, they are disabled inside of debugging environments.
//
// Debugging environment is defined by the flag LIB_DEBUG.
// To enable performance macros, define LIB_PERF_PROFILING.
//
// NOTE:
// The macro "DBG_MSG_TRACE_RETURN" or "DBG_MSG_NOTRACE_RETURN"
// must be used, so the performance control block will be properly closed.
// Therefore we define relevant macros again, as shown in other examples.
//
// Enable/disable tracing does not influence the perfomrance macros, as tracing
// is only enabled when "LIB_DEBUG" is defined and "PERF_*"-macros are disabled.
// You will get performance measurements when the global macro "LIB_PERF_PROFILING"
// is defined and the global macro "LIB_DEBUG" is not defined.
//
//
// We can now define additional, custom performance blocks on a global level.
// These work accross functions and can be used to trace certain parts of the
// code. - Each block has its own call counter, therefore it is not advised
// to reuse the blocks for different code sections, except of course thats
// exactly what you want to measure.
//
// These blocks may overlap, if required. - It is necessary t ounderstand,
// when doing so, you will also measure the times each macro takes. The execution
// of these macros would be part of your measurement.
//
// See example below.
//
// Create additional performance counters
// IDs can be specified freely
PERF_COUNTER_DEFINE_ID(on_timer_for_loop);
// Additional example (these are not used)
PERF_COUNTER_DEFINE_ID(if_g_func);
PERF_COUNTER_DEFINE_ID(call_f3_func);
PERF_COUNTER_DEFINE_ID(printf_f1);
PERF_COUNTER_DEFINE_ID(printf_f2);
// Performance block IDs can be created on a global scope as well
// as on function local scope and even in code blocks inside of
// functions scope.
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
/////////////////////////////////////
// Function performance trace code
#define DBG_TRACE_EXPERT_MAIN_ONTIMER_RETURN DBG_MSG_NOTRACE_RETURN
/////////////////////////////////////
void OnTimer()
{
PERF_COUNTER_BEGIN;
// Measuring a loop
double sum = NULL;
PERF_COUNTER_BEGIN_ID(on_timer_for_loop);
for(int cnt = NULL; (cnt < 1000000) && !_StopFlag; cnt++)
{
sum += 1.0;
}
PERF_COUNTER_END_ID(on_timer_for_loop);
/////////////////////////////////////////////////////////////////////////////
//
// Here an example of possible nested performance blocks.
// This example is very theoretical, but shows how blocks can be applied.
//
// Local scope
{
// These definitions can be on any scope in
// the hirarchy above this scope of the function all
// the way up to the global scope.
PERF_COUNTER_DEFINE_ID(a_local_scope);
PERF_COUNTER_DEFINE_ID(nested_level_1);
PERF_COUNTER_DEFINE_ID(overlapping_block_a);
PERF_COUNTER_DEFINE_ID(overlapping_block_b);
// Begin measurement of most outer block
PERF_COUNTER_BEGIN_ID(a_local_scope);
// Have some code here (not mandatory)
// Nested performance block 1
PERF_COUNTER_BEGIN_ID(nested_level_1);
// Have more code here
// Overlapping execution block
PERF_COUNTER_BEGIN_ID(overlapping_block_a);
// Maybe some code here for block A
// Open next block
PERF_COUNTER_BEGIN_ID(overlapping_block_b);
// Have some code here for block A and B (shared code block)
// Now closing block A
PERF_COUNTER_END_ID(overlapping_block_a);
// Some code for block B
// Now closing block B
PERF_COUNTER_END_ID(overlapping_block_b);
// Maybe more code here for nested level 1
// Close nested block 1
PERF_COUNTER_END_ID(nested_level_1);
// Optionally have code here as well....
// Close most outer block
PERF_COUNTER_END_ID(a_local_scope);
}
// The above example will also measure the performance counters itself.
// Although they are held as short as possible, code-wise, it will
// have some influence on the pure code thats being measured.
//
// The impact can vary, depending on the memory-paging that happens
// by accessing different areas of memory. - The variations will be
// within the margins of error and therefore can (mostly) be ignored.
//
/////////////////////////////////////////////////////////////////////////////
// Return
DBG_TRACE_EXPERT_MAIN_ONTIMER_RETURN;
}