ClickHouse/src/Common/ThreadProfileEvents.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

222 lines
5.8 KiB
C++
Raw Normal View History

#pragma once
2021-10-02 07:13:14 +00:00
#include <base/types.h>
#include <Common/ProfileEvents.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <pthread.h>
2022-04-27 15:05:45 +00:00
#include <Common/logger_useful.h>
#if defined(OS_LINUX)
#include <linux/taskstats.h>
2018-08-22 13:01:50 +00:00
#else
struct taskstats {};
#endif
2018-09-06 00:28:15 +00:00
/** Implement ProfileEvents with statistics about resource consumption of the current thread.
*/
namespace ProfileEvents
{
extern const Event RealTimeMicroseconds;
extern const Event UserTimeMicroseconds;
extern const Event SystemTimeMicroseconds;
extern const Event SoftPageFaults;
extern const Event HardPageFaults;
}
namespace DB
{
/// Handles overflow
template <typename TUInt>
inline TUInt safeDiff(TUInt prev, TUInt curr)
{
return curr >= prev ? curr - prev : 0;
}
struct RUsageCounters
{
/// In nanoseconds
UInt64 real_time = 0;
UInt64 user_time = 0;
UInt64 sys_time = 0;
UInt64 soft_page_faults = 0;
UInt64 hard_page_faults = 0;
RUsageCounters() = default;
RUsageCounters(const ::rusage & rusage_, UInt64 real_time_)
{
set(rusage_, real_time_);
}
void set(const ::rusage & rusage, UInt64 real_time_)
{
real_time = real_time_;
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;
soft_page_faults = static_cast<UInt64>(rusage.ru_minflt);
hard_page_faults = static_cast<UInt64>(rusage.ru_majflt);
}
static RUsageCounters current()
{
2018-08-23 12:20:54 +00:00
::rusage rusage {};
#if !defined(OS_DARWIN)
#if defined(OS_SUNOS)
::getrusage(RUSAGE_LWP, &rusage);
#else
::getrusage(RUSAGE_THREAD, &rusage);
#endif // OS_SUNOS
#endif // __APPLE
return RUsageCounters(rusage, getClockMonotonic());
}
static void incrementProfileEvents(const RUsageCounters & prev, const RUsageCounters & curr, ProfileEvents::Counters & profile_events)
{
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);
}
static void updateProfileEvents(RUsageCounters & last_counters, ProfileEvents::Counters & profile_events)
{
auto current_counters = current();
incrementProfileEvents(last_counters, current_counters, profile_events);
last_counters = current_counters;
}
private:
static inline UInt64 getClockMonotonic()
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
}
};
#if defined(OS_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;
std::string settings_name;
};
struct PerfEventValue
{
2020-05-28 10:48:34 +00:00
UInt64 value = 0;
UInt64 time_enabled = 0;
UInt64 time_running = 0;
2020-04-13 21:10:31 +00:00
};
static constexpr size_t NUMBER_OF_RAW_EVENTS = 22;
2020-05-29 13:04:32 +00:00
struct PerfDescriptorsHolder : boost::noncopyable
{
2020-05-29 13:04:32 +00:00
int descriptors[NUMBER_OF_RAW_EVENTS]{};
2020-05-29 13:04:32 +00:00
PerfDescriptorsHolder();
2020-05-29 13:04:32 +00:00
~PerfDescriptorsHolder();
2020-05-29 13:04:32 +00:00
void releaseResources();
};
2020-05-29 13:04:32 +00:00
struct PerfEventsCounters
2020-04-23 19:38:15 +00:00
{
2020-05-29 13:04:32 +00:00
PerfDescriptorsHolder thread_events_descriptors_holder;
2020-05-29 13:04:32 +00:00
// time_enabled and time_running can't be reset, so we have to store the
// data from the previous profiling period and calculate deltas to them,
// to be able to properly account for counter multiplexing.
PerfEventValue previous_values[NUMBER_OF_RAW_EVENTS]{};
2020-04-23 18:46:19 +00:00
2020-05-29 13:04:32 +00:00
void initializeProfileEvents(const std::string & events_list);
void finalizeProfileEvents(ProfileEvents::Counters & profile_events);
void closeEventDescriptors();
2020-06-01 17:13:54 +00:00
bool processThreadLocalChanges(const std::string & needed_events_list);
2020-05-29 13:04:32 +00:00
2020-06-01 17:13:54 +00:00
static std::vector<size_t> eventIndicesFromString(const std::string & events_list);
};
2020-05-29 13:04:32 +00:00
// Perf event creation is moderately heavy, so we create them once per thread and
// then reuse.
extern thread_local PerfEventsCounters current_thread_counters;
2020-04-23 18:46:19 +00:00
#else
2021-05-12 10:32:50 +00:00
// the functionality is disabled when we are not running on Linux.
2020-04-23 18:46:19 +00:00
struct PerfEventsCounters
{
2020-06-01 17:13:54 +00:00
void initializeProfileEvents(const std::string & /* events_list */) {}
void finalizeProfileEvents(ProfileEvents::Counters & /* profile_events */) {}
void closeEventDescriptors() {}
2020-04-23 18:46:19 +00:00
};
2020-06-02 14:09:51 +00:00
extern PerfEventsCounters current_thread_counters;
2020-06-01 17:13:54 +00:00
2020-04-23 18:46:19 +00:00
#endif
#if defined(OS_LINUX)
2020-04-23 18:46:19 +00:00
class TasksStatsCounters
{
public:
enum class MetricsProvider
{
None,
Procfs,
Netlink,
};
static const char * metricsProviderString(MetricsProvider provider);
static bool checkIfAvailable();
static MetricsProvider findBestAvailableProvider();
static std::unique_ptr<TasksStatsCounters> create(UInt64 tid);
void reset();
void updateCounters(ProfileEvents::Counters & profile_events);
private:
::taskstats stats; //-V730_NOINIT
std::function<::taskstats()> stats_getter;
explicit TasksStatsCounters(UInt64 tid, MetricsProvider provider);
static void incrementProfileEvents(const ::taskstats & prev, const ::taskstats & curr, ProfileEvents::Counters & profile_events);
};
#else
class TasksStatsCounters
{
public:
static bool checkIfAvailable() { return false; }
static std::unique_ptr<TasksStatsCounters> create(const UInt64 /*tid*/) { return {}; }
void reset() {}
void updateCounters(ProfileEvents::Counters &) {}
private:
TasksStatsCounters(const UInt64 /*tid*/) {}
};
#endif
}