2018-06-20 17:49:52 +00:00
# pragma once
2018-08-22 05:56:06 +00:00
2018-08-28 19:36:27 +00:00
# include <Core/Types.h>
2018-06-20 17:49:52 +00:00
# include <Common/ProfileEvents.h>
2020-02-04 20:47:30 +00:00
# include <ctime>
2018-06-20 17:49:52 +00:00
# include <sys/resource.h>
# include <pthread.h>
2020-02-21 18:43:23 +00:00
# include <common/logger_useful.h>
2018-08-22 05:56:06 +00:00
# if defined(__linux__)
2018-06-20 17:49:52 +00:00
# include <linux/taskstats.h>
2018-08-22 13:01:50 +00:00
# else
struct taskstats { } ;
2018-08-22 05:56:06 +00:00
# endif
2018-06-20 17:49:52 +00:00
2018-09-06 00:28:15 +00:00
/** Implement ProfileEvents with statistics about resource consumption of the current thread.
*/
2018-06-20 17:49:52 +00:00
namespace ProfileEvents
{
extern const Event RealTimeMicroseconds ;
extern const Event UserTimeMicroseconds ;
extern const Event SystemTimeMicroseconds ;
extern const Event SoftPageFaults ;
extern const Event HardPageFaults ;
extern const Event VoluntaryContextSwitches ;
extern const Event InvoluntaryContextSwitches ;
2018-08-22 05:56:06 +00:00
# if defined(__linux__)
2018-06-20 17:49:52 +00:00
extern const Event OSIOWaitMicroseconds ;
extern const Event OSCPUWaitMicroseconds ;
extern const Event OSCPUVirtualTimeMicroseconds ;
extern const Event OSReadChars ;
extern const Event OSWriteChars ;
extern const Event OSReadBytes ;
extern const Event OSWriteBytes ;
2020-02-04 20:47:30 +00:00
2020-02-21 18:43:23 +00:00
extern const Event PERF_COUNT_HW_CPU_CYCLES ;
extern const Event PERF_COUNT_HW_INSTRUCTIONS ;
extern const Event PERF_COUNT_HW_CACHE_REFERENCES ;
extern const Event PERF_COUNT_HW_CACHE_MISSES ;
extern const Event PERF_COUNT_HW_BRANCH_INSTRUCTIONS ;
extern const Event PERF_COUNT_HW_BRANCH_MISSES ;
extern const Event PERF_COUNT_HW_BUS_CYCLES ;
extern const Event PERF_COUNT_HW_STALLED_CYCLES_FRONTEND ;
extern const Event PERF_COUNT_HW_STALLED_CYCLES_BACKEND ;
extern const Event PERF_COUNT_HW_REF_CPU_CYCLES ;
2020-02-19 16:35:01 +00:00
// extern const Event PERF_COUNT_SW_CPU_CLOCK;
2020-02-04 20:47:30 +00:00
extern const Event PERF_COUNT_SW_TASK_CLOCK ;
extern const Event PERF_COUNT_SW_PAGE_FAULTS ;
extern const Event PERF_COUNT_SW_CONTEXT_SWITCHES ;
extern const Event PERF_COUNT_SW_CPU_MIGRATIONS ;
extern const Event PERF_COUNT_SW_PAGE_FAULTS_MIN ;
extern const Event PERF_COUNT_SW_PAGE_FAULTS_MAJ ;
extern const Event PERF_COUNT_SW_ALIGNMENT_FAULTS ;
extern const Event PERF_COUNT_SW_EMULATION_FAULTS ;
2020-02-21 18:43:23 +00:00
extern const Event PERF_CUSTOM_INSTRUCTIONS_PER_CPU_CYCLE_SCALED ;
extern const Event PERF_CUSTOM_INSTRUCTIONS_PER_CPU_CYCLE ;
2018-08-22 05:56:06 +00:00
# endif
2018-06-20 17:49:52 +00:00
}
namespace DB
{
/// Handles overflow
template < typename TUInt >
inline TUInt safeDiff ( TUInt prev , TUInt curr )
{
return curr > = prev ? curr - prev : 0 ;
}
inline UInt64 getCurrentTimeNanoseconds ( clockid_t clock_type = CLOCK_MONOTONIC )
{
struct timespec ts ;
clock_gettime ( clock_type , & ts ) ;
return ts . tv_sec * 1000000000ULL + ts . tv_nsec ;
}
2018-08-14 20:29:42 +00:00
struct RUsageCounters
2018-06-20 17:49:52 +00:00
{
/// In nanoseconds
UInt64 real_time = 0 ;
UInt64 user_time = 0 ;
UInt64 sys_time = 0 ;
UInt64 soft_page_faults = 0 ;
UInt64 hard_page_faults = 0 ;
2018-08-14 20:29:42 +00:00
RUsageCounters ( ) = default ;
RUsageCounters ( const : : rusage & rusage_ , UInt64 real_time_ )
2018-06-20 17:49:52 +00:00
{
set ( rusage_ , real_time_ ) ;
}
void set ( const : : rusage & rusage , UInt64 real_time_ )
{
real_time = real_time_ ;
2018-08-19 04:25:53 +00:00
user_time = rusage . ru_utime . tv_sec * 1000000000UL + rusage . ru_utime . tv_usec * 1000UL ;
sys_time = rusage . ru_stime . tv_sec * 1000000000UL + rusage . ru_stime . tv_usec * 1000UL ;
2018-06-20 17:49:52 +00:00
soft_page_faults = static_cast < UInt64 > ( rusage . ru_minflt ) ;
hard_page_faults = static_cast < UInt64 > ( rusage . ru_majflt ) ;
}
2018-08-14 20:29:42 +00:00
static RUsageCounters zeros ( UInt64 real_time_ = getCurrentTimeNanoseconds ( ) )
2018-06-20 17:49:52 +00:00
{
2018-08-14 20:29:42 +00:00
RUsageCounters res ;
2018-06-20 17:49:52 +00:00
res . real_time = real_time_ ;
return res ;
}
2018-08-14 20:29:42 +00:00
static RUsageCounters current ( UInt64 real_time_ = getCurrentTimeNanoseconds ( ) )
2018-06-20 17:49:52 +00:00
{
2018-08-23 12:20:54 +00:00
: : rusage rusage { } ;
2018-08-22 16:56:00 +00:00
# if !defined(__APPLE__)
2018-06-20 17:49:52 +00:00
: : getrusage ( RUSAGE_THREAD , & rusage ) ;
2018-08-22 13:12:20 +00:00
# endif
2018-08-14 20:29:42 +00:00
return RUsageCounters ( rusage , real_time_ ) ;
2018-06-20 17:49:52 +00:00
}
2018-08-14 20:29:42 +00:00
static void incrementProfileEvents ( const RUsageCounters & prev , const RUsageCounters & curr , ProfileEvents : : Counters & profile_events )
2018-06-20 17:49:52 +00:00
{
profile_events . increment ( ProfileEvents : : RealTimeMicroseconds , ( curr . real_time - prev . real_time ) / 1000U ) ;
profile_events . increment ( ProfileEvents : : UserTimeMicroseconds , ( curr . user_time - prev . user_time ) / 1000U ) ;
profile_events . increment ( ProfileEvents : : SystemTimeMicroseconds , ( curr . sys_time - prev . sys_time ) / 1000U ) ;
profile_events . increment ( ProfileEvents : : SoftPageFaults , curr . soft_page_faults - prev . soft_page_faults ) ;
profile_events . increment ( ProfileEvents : : HardPageFaults , curr . hard_page_faults - prev . hard_page_faults ) ;
}
2018-08-14 20:29:42 +00:00
static void updateProfileEvents ( RUsageCounters & last_counters , ProfileEvents : : Counters & profile_events )
2018-06-20 17:49:52 +00:00
{
auto current_counters = current ( ) ;
incrementProfileEvents ( last_counters , current_counters , profile_events ) ;
last_counters = current_counters ;
}
} ;
2020-02-21 18:43:23 +00:00
# if defined(__linux__)
2020-04-13 21:10:31 +00:00
struct PerfEventInfo
{
// see perf_event.h/perf_type_id enum
int event_type ;
// see configs in perf_event.h
int event_config ;
ProfileEvents : : Event profile_event ;
} ;
2020-02-21 18:43:23 +00:00
# endif
2020-02-04 20:47:30 +00:00
struct PerfEventsCounters
{
// cat /proc/sys/kernel/perf_event_paranoid - if perf_event_paranoid is set to 3, all calls to `perf_event_open` are rejected (even for the current process)
// https://lwn.net/Articles/696234/
// -1: Allow use of (almost) all events by all users
// >=0: Disallow raw tracepoint access by users without CAP_IOC_LOCK
// >=1: Disallow CPU event access by users without CAP_SYS_ADMIN
// >=2: Disallow kernel profiling by users without CAP_SYS_ADMIN
// >=3: Disallow all event access by users without CAP_SYS_ADMIN
// https://lwn.net/Articles/696216/
// It adds a another value that can be set for the sysctl parameter (i.e. kernel.perf_event_paranoid=3)
// that restricts perf_event_open() to processes with the CAP_SYS_ADMIN capability
// todo: check whether perf_event_open() is available with CAP_SYS_ADMIN
2020-02-19 16:35:01 +00:00
# if defined(__linux__)
2020-02-21 18:43:23 +00:00
static constexpr size_t NUMBER_OF_RAW_EVENTS = 18 ;
2020-02-19 16:35:01 +00:00
2020-02-21 18:43:23 +00:00
static const PerfEventInfo perf_raw_events_info [ ] ;
2020-02-19 16:35:01 +00:00
2020-03-06 16:31:31 +00:00
int events_descriptors [ NUMBER_OF_RAW_EVENTS ] { } ;
2020-02-21 18:43:23 +00:00
// temp array just to not create it each time event processing finishes
2020-04-14 16:23:33 +00:00
Int64 raw_event_values [ NUMBER_OF_RAW_EVENTS ] { } ;
2020-02-19 16:35:01 +00:00
bool perf_events_recording = false ;
# endif
static void initializeProfileEvents ( PerfEventsCounters & counters ) ;
static void finalizeProfileEvents ( PerfEventsCounters & counters , ProfileEvents : : Counters & profile_events ) ;
2020-02-21 18:43:23 +00:00
2020-02-21 18:59:08 +00:00
# if defined(__linux__)
2020-02-21 18:43:23 +00:00
private :
2020-04-14 13:55:46 +00:00
// used to write information about perf unavailability only once for all threads
static std : : atomic < bool > perf_unavailability_logged ;
// used to write information about particular perf events unavailability only once for all threads
static std : : atomic < bool > particular_events_unavailability_logged ;
2020-02-21 18:43:23 +00:00
static Logger * getLogger ( ) ;
2020-04-14 16:23:33 +00:00
[[nodiscard]] Int64 getRawValue ( int event_type , int event_config ) const ;
2020-02-21 18:59:08 +00:00
# endif
2020-02-04 20:47:30 +00:00
} ;
2018-06-20 17:49:52 +00:00
2018-08-22 05:56:06 +00:00
# if defined(__linux__)
2018-06-20 17:49:52 +00:00
struct TasksStatsCounters
{
: : taskstats stat ;
TasksStatsCounters ( ) = default ;
static TasksStatsCounters current ( ) ;
static void incrementProfileEvents ( const TasksStatsCounters & prev , const TasksStatsCounters & curr , ProfileEvents : : Counters & profile_events )
{
profile_events . increment ( ProfileEvents : : OSCPUWaitMicroseconds ,
safeDiff ( prev . stat . cpu_delay_total , curr . stat . cpu_delay_total ) / 1000U ) ;
profile_events . increment ( ProfileEvents : : OSIOWaitMicroseconds ,
safeDiff ( prev . stat . blkio_delay_total , curr . stat . blkio_delay_total ) / 1000U ) ;
profile_events . increment ( ProfileEvents : : OSCPUVirtualTimeMicroseconds ,
safeDiff ( prev . stat . cpu_run_virtual_total , curr . stat . cpu_run_virtual_total ) / 1000U ) ;
2019-02-28 21:49:52 +00:00
/// Since TASKSTATS_VERSION = 3 extended accounting and IO accounting is available.
if ( curr . stat . version < 3 )
2018-06-20 17:49:52 +00:00
return ;
2018-11-26 00:56:50 +00:00
profile_events . increment ( ProfileEvents : : OSReadChars , safeDiff ( prev . stat . read_char , curr . stat . read_char ) ) ;
2018-06-20 17:49:52 +00:00
profile_events . increment ( ProfileEvents : : OSWriteChars , safeDiff ( prev . stat . write_char , curr . stat . write_char ) ) ;
2018-11-26 00:56:50 +00:00
profile_events . increment ( ProfileEvents : : OSReadBytes , safeDiff ( prev . stat . read_bytes , curr . stat . read_bytes ) ) ;
2018-06-20 17:49:52 +00:00
profile_events . increment ( ProfileEvents : : OSWriteBytes , safeDiff ( prev . stat . write_bytes , curr . stat . write_bytes ) ) ;
}
static void updateProfileEvents ( TasksStatsCounters & last_counters , ProfileEvents : : Counters & profile_events )
{
auto current_counters = current ( ) ;
incrementProfileEvents ( last_counters , current_counters , profile_events ) ;
last_counters = current_counters ;
}
} ;
2018-08-22 05:56:06 +00:00
# else
struct TasksStatsCounters
{
2018-08-22 05:59:27 +00:00
: : taskstats stat ;
2018-08-22 13:01:50 +00:00
static TasksStatsCounters current ( ) ;
2018-08-22 05:56:06 +00:00
static void incrementProfileEvents ( const TasksStatsCounters & , const TasksStatsCounters & , ProfileEvents : : Counters & ) { }
static void updateProfileEvents ( TasksStatsCounters & , ProfileEvents : : Counters & ) { }
} ;
# endif
2018-06-20 17:49:52 +00:00
}