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 |
12 | struct taskstats {}; |
13 | #endif |
14 | |
15 | |
16 | /** Implement ProfileEvents with statistics about resource consumption of the current thread. |
17 | */ |
18 | |
19 | namespace 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 | |
41 | namespace DB |
42 | { |
43 | |
44 | /// Handles overflow |
45 | template <typename TUInt> |
46 | inline TUInt safeDiff(TUInt prev, TUInt curr) |
47 | { |
48 | return curr >= prev ? curr - prev : 0; |
49 | } |
50 | |
51 | |
52 | inline 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 | |
60 | struct 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 | |
123 | struct 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 | |
160 | struct 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 | |