1#pragma once
2
3#include <Core/Types.h>
4#include <Common/ProfileEvents.h>
5#include <sys/time.h>
6#include <sys/resource.h>
7#include <pthread.h>
8
9#if defined(__linux__)
10#include <linux/taskstats.h>
11#else
12struct taskstats {};
13#endif
14
15
16/** Implement ProfileEvents with statistics about resource consumption of the current thread.
17 */
18
19namespace ProfileEvents
20{
21 extern const Event RealTimeMicroseconds;
22 extern const Event UserTimeMicroseconds;
23 extern const Event SystemTimeMicroseconds;
24 extern const Event SoftPageFaults;
25 extern const Event HardPageFaults;
26 extern const Event VoluntaryContextSwitches;
27 extern const Event InvoluntaryContextSwitches;
28
29#if defined(__linux__)
30 extern const Event OSIOWaitMicroseconds;
31 extern const Event OSCPUWaitMicroseconds;
32 extern const Event OSCPUVirtualTimeMicroseconds;
33 extern const Event OSReadChars;
34 extern const Event OSWriteChars;
35 extern const Event OSReadBytes;
36 extern const Event OSWriteBytes;
37#endif
38}
39
40
41namespace DB
42{
43
44/// Handles overflow
45template <typename TUInt>
46inline TUInt safeDiff(TUInt prev, TUInt curr)
47{
48 return curr >= prev ? curr - prev : 0;
49}
50
51
52inline UInt64 getCurrentTimeNanoseconds(clockid_t clock_type = CLOCK_MONOTONIC)
53{
54 struct timespec ts;
55 clock_gettime(clock_type, &ts);
56 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
57}
58
59
60struct RUsageCounters
61{
62 /// In nanoseconds
63 UInt64 real_time = 0;
64 UInt64 user_time = 0;
65 UInt64 sys_time = 0;
66
67 UInt64 soft_page_faults = 0;
68 UInt64 hard_page_faults = 0;
69
70 RUsageCounters() = default;
71 RUsageCounters(const ::rusage & rusage_, UInt64 real_time_)
72 {
73 set(rusage_, real_time_);
74 }
75
76 void set(const ::rusage & rusage, UInt64 real_time_)
77 {
78 real_time = real_time_;
79 user_time = rusage.ru_utime.tv_sec * 1000000000UL + rusage.ru_utime.tv_usec * 1000UL;
80 sys_time = rusage.ru_stime.tv_sec * 1000000000UL + rusage.ru_stime.tv_usec * 1000UL;
81
82 soft_page_faults = static_cast<UInt64>(rusage.ru_minflt);
83 hard_page_faults = static_cast<UInt64>(rusage.ru_majflt);
84 }
85
86 static RUsageCounters zeros(UInt64 real_time_ = getCurrentTimeNanoseconds())
87 {
88 RUsageCounters res;
89 res.real_time = real_time_;
90 return res;
91 }
92
93 static RUsageCounters current(UInt64 real_time_ = getCurrentTimeNanoseconds())
94 {
95 ::rusage rusage {};
96#if !defined(__APPLE__)
97 ::getrusage(RUSAGE_THREAD, &rusage);
98#endif
99 return RUsageCounters(rusage, real_time_);
100 }
101
102 static void incrementProfileEvents(const RUsageCounters & prev, const RUsageCounters & curr, ProfileEvents::Counters & profile_events)
103 {
104 profile_events.increment(ProfileEvents::RealTimeMicroseconds, (curr.real_time - prev.real_time) / 1000U);
105 profile_events.increment(ProfileEvents::UserTimeMicroseconds, (curr.user_time - prev.user_time) / 1000U);
106 profile_events.increment(ProfileEvents::SystemTimeMicroseconds, (curr.sys_time - prev.sys_time) / 1000U);
107
108 profile_events.increment(ProfileEvents::SoftPageFaults, curr.soft_page_faults - prev.soft_page_faults);
109 profile_events.increment(ProfileEvents::HardPageFaults, curr.hard_page_faults - prev.hard_page_faults);
110 }
111
112 static void updateProfileEvents(RUsageCounters & last_counters, ProfileEvents::Counters & profile_events)
113 {
114 auto current_counters = current();
115 incrementProfileEvents(last_counters, current_counters, profile_events);
116 last_counters = current_counters;
117 }
118};
119
120
121#if defined(__linux__)
122
123struct TasksStatsCounters
124{
125 ::taskstats stat;
126
127 TasksStatsCounters() = default;
128
129 static TasksStatsCounters current();
130
131 static void incrementProfileEvents(const TasksStatsCounters & prev, const TasksStatsCounters & curr, ProfileEvents::Counters & profile_events)
132 {
133 profile_events.increment(ProfileEvents::OSCPUWaitMicroseconds,
134 safeDiff(prev.stat.cpu_delay_total, curr.stat.cpu_delay_total) / 1000U);
135 profile_events.increment(ProfileEvents::OSIOWaitMicroseconds,
136 safeDiff(prev.stat.blkio_delay_total, curr.stat.blkio_delay_total) / 1000U);
137 profile_events.increment(ProfileEvents::OSCPUVirtualTimeMicroseconds,
138 safeDiff(prev.stat.cpu_run_virtual_total, curr.stat.cpu_run_virtual_total) / 1000U);
139
140 /// Since TASKSTATS_VERSION = 3 extended accounting and IO accounting is available.
141 if (curr.stat.version < 3)
142 return;
143
144 profile_events.increment(ProfileEvents::OSReadChars, safeDiff(prev.stat.read_char, curr.stat.read_char));
145 profile_events.increment(ProfileEvents::OSWriteChars, safeDiff(prev.stat.write_char, curr.stat.write_char));
146 profile_events.increment(ProfileEvents::OSReadBytes, safeDiff(prev.stat.read_bytes, curr.stat.read_bytes));
147 profile_events.increment(ProfileEvents::OSWriteBytes, safeDiff(prev.stat.write_bytes, curr.stat.write_bytes));
148 }
149
150 static void updateProfileEvents(TasksStatsCounters & last_counters, ProfileEvents::Counters & profile_events)
151 {
152 auto current_counters = current();
153 incrementProfileEvents(last_counters, current_counters, profile_events);
154 last_counters = current_counters;
155 }
156};
157
158#else
159
160struct TasksStatsCounters
161{
162 ::taskstats stat;
163
164 static TasksStatsCounters current();
165 static void incrementProfileEvents(const TasksStatsCounters &, const TasksStatsCounters &, ProfileEvents::Counters &) {}
166 static void updateProfileEvents(TasksStatsCounters &, ProfileEvents::Counters &) {}
167};
168
169#endif
170
171}
172