2020-12-21 17:12:05 +03:00
#include "stdafx.h"
2020-10-18 15:00:10 +03:00
#include "perf_meter.hpp"
2020-12-21 17:12:05 +03:00
#include "util/sysinfo.hpp"
2021-12-30 19:39:18 +03:00
#include "util/fence.hpp"
#include "util/tsc.hpp"
2020-12-22 14:08:13 +03:00
#include "Utilities/Thread.h"
2025-02-11 03:00:37 +01:00
#include "Utilities/mutex.h"
2020-12-21 17:12:05 +03:00
2020-11-19 11:12:59 +03:00
#include <map>
#include <mutex>
2020-10-18 15:00:10 +03:00
void perf_stat_base :: push ( u64 ns [ 66 ]) noexcept
{
2020-11-19 11:12:59 +03:00
if ( ! ns [ 0 ])
{
return ;
}
2020-10-18 15:00:10 +03:00
for ( u32 i = 0 ; i < 66 ; i ++ )
{
2020-11-19 11:12:59 +03:00
m_log [ i ] += atomic_storage < u64 >:: exchange ( ns [ i ], 0 );
2020-10-18 15:00:10 +03:00
}
}
2021-04-09 21:12:47 +02:00
void perf_stat_base :: print ( const char * name ) const noexcept
2020-10-18 15:00:10 +03:00
{
if ( u64 num_total = m_log [ 0 ]. load ())
{
2024-12-22 20:59:48 +02:00
perf_log . notice ( u8 "Perf stats for %s: total events: %u (total time %.4fs, avg %.4fus)" , name , num_total , m_log [ 65 ]. load () / 1000'000'000 ., m_log [ 65 ]. load () / 1000. / num_total );
2020-10-18 15:00:10 +03:00
for ( u32 i = 0 ; i < 13 ; i ++ )
{
if ( u64 count = m_log [ i + 1 ]. load ())
{
2024-12-22 20:59:48 +02:00
perf_log . notice ( u8 "Perf stats for %s: events < %.3fus: %u" , name , std :: pow ( 2. , i ) / 1000. , count );
2020-10-18 15:00:10 +03:00
}
}
for ( u32 i = 14 ; i < 23 ; i ++ )
{
if ( u64 count = m_log [ i + 1 ]. load ()) [[unlikely]]
{
perf_log . notice ( "Perf stats for %s: events < %.3fms: %u" , name , std :: pow ( 2. , i ) / 1000'000 ., count );
}
}
for ( u32 i = 24 ; i < 33 ; i ++ )
{
if ( u64 count = m_log [ i + 1 ]. load ()) [[unlikely]]
{
perf_log . notice ( "Perf stats for %s: events < %.3fs: %u" , name , std :: pow ( 2. , i ) / 1000'000'000 ., count );
}
}
for ( u32 i = 34 ; i < 43 ; i ++ )
{
if ( u64 count = m_log [ i + 1 ]. load ()) [[unlikely]]
{
perf_log . notice ( "Perf stats for %s: events < %.0f SEC: %u" , name , std :: pow ( 2. , i ) / 1000'000'000 ., count );
}
}
for ( u32 i = 44 ; i < 63 ; i ++ )
{
if ( u64 count = m_log [ i + 1 ]. load ()) [[unlikely]]
{
perf_log . notice ( "Perf stats for %s: events < %.0f MIN: %u" , name , std :: pow ( 2. , i ) / 60'000'000'000 ., count );
}
}
}
}
2020-11-19 11:12:59 +03:00
2021-02-09 12:33:50 +03:00
SAFE_BUFFERS ( void ) perf_stat_base :: push ( u64 data [ 66 ], u64 start_time , const char * name ) noexcept
2020-12-21 17:12:05 +03:00
{
// Event end
2021-12-30 19:39:18 +03:00
const u64 end_time = ( utils :: lfence (), utils :: get_tsc ());
2020-12-21 17:12:05 +03:00
// Compute difference in seconds
const f64 diff = ( end_time - start_time ) * 1. / utils :: get_tsc_freq ();
// Register perf stat in nanoseconds
const u64 ns = static_cast < u64 > ( diff * 1000'000'000 .);
// Print in microseconds
if ( static_cast < u64 > ( diff * 1000'000 .) >= g_cfg . core . perf_report_threshold )
{
2024-12-22 20:59:48 +02:00
perf_log . notice ( u8 "%s: %.3fus" , name , diff * 1000'000 .);
2020-12-21 17:12:05 +03:00
}
data [ 0 ] += ns != 0 ;
data [ 64 - std :: countl_zero ( ns )] ++ ;
data [ 65 ] += ns ;
}
2020-11-19 11:12:59 +03:00
static shared_mutex s_perf_mutex ;
static std :: map < std :: string , perf_stat_base > s_perf_acc ;
static std :: multimap < std :: string , u64 *> s_perf_sources ;
void perf_stat_base :: add ( u64 ns [ 66 ], const char * name ) noexcept
{
2020-12-22 14:08:13 +03:00
// Don't attempt to register some foreign/unnamed threads
if ( ! thread_ctrl :: get_current ())
{
return ;
}
2020-11-19 11:12:59 +03:00
std :: lock_guard lock ( s_perf_mutex );
s_perf_sources . emplace ( name , ns );
s_perf_acc [ name ];
}
void perf_stat_base :: remove ( u64 ns [ 66 ], const char * name ) noexcept
{
2020-12-22 14:08:13 +03:00
if ( ! thread_ctrl :: get_current ())
{
return ;
}
2020-11-19 11:12:59 +03:00
std :: lock_guard lock ( s_perf_mutex );
const auto found = s_perf_sources . equal_range ( name );
for ( auto it = found . first ; it != found . second ; it ++ )
{
if ( it -> second == ns )
{
s_perf_acc [ name ]. push ( ns );
s_perf_sources . erase ( it );
break ;
}
}
}
void perf_stat_base :: report () noexcept
{
std :: lock_guard lock ( s_perf_mutex );
perf_log . notice ( "Performance report begin (%u src, %u acc):" , s_perf_sources . size (), s_perf_acc . size ());
for ( auto & [ name , ns ] : s_perf_sources )
{
s_perf_acc [ name ]. push ( ns );
}
for ( auto & [ name , data ] : s_perf_acc )
{
data . print ( name . c_str ());
}
s_perf_acc . clear ();
perf_log . notice ( "Performance report end." );
}