Coverage Report

Created: 2024-11-21 20:24

/root/doris/be/src/util/system_metrics.cpp
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#include "util/system_metrics.h"
19
20
#include <ctype.h>
21
// IWYU pragma: no_include <bthread/errno.h>
22
#include <errno.h> // IWYU pragma: keep
23
#include <glog/logging.h>
24
#include <inttypes.h>
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>
28
29
#include <functional>
30
#include <ostream>
31
#include <unordered_map>
32
#include <utility>
33
34
#include "gutil/strings/split.h" // for string split
35
#include "gutil/strtoint.h"      //  for atoi64
36
#include "util/mem_info.h"
37
#include "util/perf_counters.h"
38
39
namespace doris {
40
41
#define DEFINE_CPU_COUNTER_METRIC(metric)                                            \
42
    DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(cpu_##metric, MetricUnit::PERCENT, "", cpu, \
43
                                         Labels({{"mode", #metric}}));
44
DEFINE_CPU_COUNTER_METRIC(user);
45
DEFINE_CPU_COUNTER_METRIC(nice);
46
DEFINE_CPU_COUNTER_METRIC(system);
47
DEFINE_CPU_COUNTER_METRIC(idle);
48
DEFINE_CPU_COUNTER_METRIC(iowait);
49
DEFINE_CPU_COUNTER_METRIC(irq);
50
DEFINE_CPU_COUNTER_METRIC(soft_irq);
51
DEFINE_CPU_COUNTER_METRIC(steal);
52
DEFINE_CPU_COUNTER_METRIC(guest);
53
DEFINE_CPU_COUNTER_METRIC(guest_nice);
54
55
// /proc/stat: http://www.linuxhowtos.org/System/procstat.htm
56
struct CpuMetrics {
57
33
    CpuMetrics(MetricEntity* ent) : entity(ent) {
58
33
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, cpu_user);
59
33
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, cpu_nice);
60
33
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, cpu_system);
61
33
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, cpu_idle);
62
33
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, cpu_iowait);
63
33
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, cpu_irq);
64
33
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, cpu_soft_irq);
65
33
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, cpu_steal);
66
33
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, cpu_guest);
67
33
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, cpu_guest_nice);
68
69
33
        metrics[0] = cpu_user;
70
33
        metrics[1] = cpu_nice;
71
33
        metrics[2] = cpu_system;
72
33
        metrics[3] = cpu_idle;
73
33
        metrics[4] = cpu_iowait;
74
33
        metrics[5] = cpu_irq;
75
33
        metrics[6] = cpu_soft_irq;
76
33
        metrics[7] = cpu_steal;
77
33
        metrics[8] = cpu_guest;
78
33
        metrics[9] = cpu_guest_nice;
79
33
    }
80
81
    static constexpr int cpu_num_metrics = 10;
82
83
    MetricEntity* entity = nullptr;
84
    IntAtomicCounter* cpu_user;
85
    IntAtomicCounter* cpu_nice;
86
    IntAtomicCounter* cpu_system;
87
    IntAtomicCounter* cpu_idle;
88
    IntAtomicCounter* cpu_iowait;
89
    IntAtomicCounter* cpu_irq;
90
    IntAtomicCounter* cpu_soft_irq;
91
    IntAtomicCounter* cpu_steal;
92
    IntAtomicCounter* cpu_guest;
93
    IntAtomicCounter* cpu_guest_nice;
94
95
    IntAtomicCounter* metrics[cpu_num_metrics];
96
};
97
98
#define DEFINE_MEMORY_GAUGE_METRIC(metric, unit) \
99
    DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(memory_##metric, unit);
100
DEFINE_MEMORY_GAUGE_METRIC(allocated_bytes, MetricUnit::BYTES);
101
DEFINE_MEMORY_GAUGE_METRIC(pgpgin, MetricUnit::NOUNIT);
102
DEFINE_MEMORY_GAUGE_METRIC(pgpgout, MetricUnit::NOUNIT);
103
DEFINE_MEMORY_GAUGE_METRIC(pswpin, MetricUnit::NOUNIT);
104
DEFINE_MEMORY_GAUGE_METRIC(pswpout, MetricUnit::NOUNIT);
105
#ifndef USE_JEMALLOC
106
DEFINE_MEMORY_GAUGE_METRIC(tcmalloc_allocated_bytes, MetricUnit::BYTES);
107
DEFINE_MEMORY_GAUGE_METRIC(tcmalloc_total_thread_cache_bytes, MetricUnit::BYTES);
108
DEFINE_MEMORY_GAUGE_METRIC(tcmalloc_central_cache_free_bytes, MetricUnit::BYTES);
109
DEFINE_MEMORY_GAUGE_METRIC(tcmalloc_transfer_cache_free_bytes, MetricUnit::BYTES);
110
DEFINE_MEMORY_GAUGE_METRIC(tcmalloc_thread_cache_free_bytes, MetricUnit::BYTES);
111
DEFINE_MEMORY_GAUGE_METRIC(tcmalloc_pageheap_free_bytes, MetricUnit::BYTES);
112
DEFINE_MEMORY_GAUGE_METRIC(tcmalloc_pageheap_unmapped_bytes, MetricUnit::BYTES);
113
#else
114
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_allocated_bytes, MetricUnit::BYTES);
115
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_active_bytes, MetricUnit::BYTES);
116
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_metadata_bytes, MetricUnit::BYTES);
117
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_resident_bytes, MetricUnit::BYTES);
118
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_mapped_bytes, MetricUnit::BYTES);
119
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_retained_bytes, MetricUnit::BYTES);
120
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_tcache_bytes, MetricUnit::BYTES);
121
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_pactive_num, MetricUnit::NOUNIT);
122
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_pdirty_num, MetricUnit::NOUNIT);
123
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_pmuzzy_num, MetricUnit::NOUNIT);
124
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_dirty_purged_num, MetricUnit::NOUNIT);
125
DEFINE_MEMORY_GAUGE_METRIC(jemalloc_muzzy_purged_num, MetricUnit::NOUNIT);
126
#endif
127
128
struct MemoryMetrics {
129
2
    MemoryMetrics(MetricEntity* ent) : entity(ent) {
130
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_allocated_bytes);
131
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_pgpgin);
132
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_pgpgout);
133
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_pswpin);
134
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_pswpout);
135
136
2
#ifndef USE_JEMALLOC
137
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_tcmalloc_allocated_bytes);
138
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_tcmalloc_total_thread_cache_bytes);
139
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_tcmalloc_central_cache_free_bytes);
140
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_tcmalloc_transfer_cache_free_bytes);
141
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_tcmalloc_thread_cache_free_bytes);
142
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_tcmalloc_pageheap_free_bytes);
143
2
        INT_GAUGE_METRIC_REGISTER(entity, memory_tcmalloc_pageheap_unmapped_bytes);
144
#else
145
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_allocated_bytes);
146
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_active_bytes);
147
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_metadata_bytes);
148
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_resident_bytes);
149
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_mapped_bytes);
150
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_retained_bytes);
151
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_tcache_bytes);
152
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_pactive_num);
153
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_pdirty_num);
154
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_pmuzzy_num);
155
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_dirty_purged_num);
156
        INT_GAUGE_METRIC_REGISTER(entity, memory_jemalloc_muzzy_purged_num);
157
#endif
158
2
    }
159
160
    MetricEntity* entity = nullptr;
161
    IntGauge* memory_allocated_bytes;
162
    IntGauge* memory_pgpgin;
163
    IntGauge* memory_pgpgout;
164
    IntGauge* memory_pswpin;
165
    IntGauge* memory_pswpout;
166
167
#ifndef USE_JEMALLOC
168
    IntGauge* memory_tcmalloc_allocated_bytes;
169
    IntGauge* memory_tcmalloc_total_thread_cache_bytes;
170
    IntGauge* memory_tcmalloc_central_cache_free_bytes;
171
    IntGauge* memory_tcmalloc_transfer_cache_free_bytes;
172
    IntGauge* memory_tcmalloc_thread_cache_free_bytes;
173
    IntGauge* memory_tcmalloc_pageheap_free_bytes;
174
    IntGauge* memory_tcmalloc_pageheap_unmapped_bytes;
175
#else
176
    IntGauge* memory_jemalloc_allocated_bytes;
177
    IntGauge* memory_jemalloc_active_bytes;
178
    IntGauge* memory_jemalloc_metadata_bytes;
179
    IntGauge* memory_jemalloc_resident_bytes;
180
    IntGauge* memory_jemalloc_mapped_bytes;
181
    IntGauge* memory_jemalloc_retained_bytes;
182
    IntGauge* memory_jemalloc_tcache_bytes;
183
    IntGauge* memory_jemalloc_pactive_num;
184
    IntGauge* memory_jemalloc_pdirty_num;
185
    IntGauge* memory_jemalloc_pmuzzy_num;
186
    IntGauge* memory_jemalloc_dirty_purged_num;
187
    IntGauge* memory_jemalloc_muzzy_purged_num;
188
#endif
189
};
190
191
#define DEFINE_DISK_COUNTER_METRIC(metric, unit) \
192
    DEFINE_COUNTER_METRIC_PROTOTYPE_2ARG(disk_##metric, unit);
193
DEFINE_DISK_COUNTER_METRIC(reads_completed, MetricUnit::OPERATIONS);
194
DEFINE_DISK_COUNTER_METRIC(bytes_read, MetricUnit::BYTES);
195
DEFINE_DISK_COUNTER_METRIC(read_time_ms, MetricUnit::MILLISECONDS);
196
DEFINE_DISK_COUNTER_METRIC(writes_completed, MetricUnit::OPERATIONS);
197
DEFINE_DISK_COUNTER_METRIC(bytes_written, MetricUnit::BYTES);
198
DEFINE_DISK_COUNTER_METRIC(write_time_ms, MetricUnit::MILLISECONDS);
199
DEFINE_DISK_COUNTER_METRIC(io_time_ms, MetricUnit::MILLISECONDS);
200
DEFINE_DISK_COUNTER_METRIC(io_time_weigthed, MetricUnit::MILLISECONDS);
201
202
struct DiskMetrics {
203
2
    DiskMetrics(MetricEntity* ent) : entity(ent) {
204
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, disk_reads_completed);
205
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, disk_bytes_read);
206
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, disk_read_time_ms);
207
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, disk_writes_completed);
208
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, disk_bytes_written);
209
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, disk_write_time_ms);
210
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, disk_io_time_ms);
211
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, disk_io_time_weigthed);
212
2
    }
213
214
    MetricEntity* entity = nullptr;
215
    IntAtomicCounter* disk_reads_completed;
216
    IntAtomicCounter* disk_bytes_read;
217
    IntAtomicCounter* disk_read_time_ms;
218
    IntAtomicCounter* disk_writes_completed;
219
    IntAtomicCounter* disk_bytes_written;
220
    IntAtomicCounter* disk_write_time_ms;
221
    IntAtomicCounter* disk_io_time_ms;
222
    IntAtomicCounter* disk_io_time_weigthed;
223
};
224
225
#define DEFINE_NETWORK_COUNTER_METRIC(metric, unit) \
226
    DEFINE_COUNTER_METRIC_PROTOTYPE_2ARG(network_##metric, unit);
227
DEFINE_NETWORK_COUNTER_METRIC(receive_bytes, MetricUnit::BYTES);
228
DEFINE_NETWORK_COUNTER_METRIC(receive_packets, MetricUnit::PACKETS);
229
DEFINE_NETWORK_COUNTER_METRIC(send_bytes, MetricUnit::BYTES);
230
DEFINE_NETWORK_COUNTER_METRIC(send_packets, MetricUnit::PACKETS);
231
232
struct NetworkMetrics {
233
2
    NetworkMetrics(MetricEntity* ent) : entity(ent) {
234
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, network_receive_bytes);
235
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, network_receive_packets);
236
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, network_send_bytes);
237
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, network_send_packets);
238
2
    }
239
240
    MetricEntity* entity = nullptr;
241
    IntAtomicCounter* network_receive_bytes;
242
    IntAtomicCounter* network_receive_packets;
243
    IntAtomicCounter* network_send_bytes;
244
    IntAtomicCounter* network_send_packets;
245
};
246
247
#define DEFINE_SNMP_COUNTER_METRIC(metric, unit, desc) \
248
    DEFINE_COUNTER_METRIC_PROTOTYPE_3ARG(snmp_##metric, unit, desc);
249
DEFINE_SNMP_COUNTER_METRIC(tcp_in_errs, MetricUnit::NOUNIT,
250
                           "The number of all problematic TCP packets received");
251
DEFINE_SNMP_COUNTER_METRIC(tcp_retrans_segs, MetricUnit::NOUNIT, "All TCP packets retransmitted");
252
DEFINE_SNMP_COUNTER_METRIC(tcp_in_segs, MetricUnit::NOUNIT, "All received TCP packets");
253
DEFINE_SNMP_COUNTER_METRIC(tcp_out_segs, MetricUnit::NOUNIT, "All send TCP packets with RST mark");
254
255
// metrics read from /proc/net/snmp
256
struct SnmpMetrics {
257
2
    SnmpMetrics(MetricEntity* ent) : entity(ent) {
258
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, snmp_tcp_in_errs);
259
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, snmp_tcp_retrans_segs);
260
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, snmp_tcp_in_segs);
261
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, snmp_tcp_out_segs);
262
2
    }
263
264
    MetricEntity* entity = nullptr;
265
    IntAtomicCounter* snmp_tcp_in_errs;
266
    IntAtomicCounter* snmp_tcp_retrans_segs;
267
    IntAtomicCounter* snmp_tcp_in_segs;
268
    IntAtomicCounter* snmp_tcp_out_segs;
269
};
270
271
#define DEFINE_FD_COUNTER_METRIC(metric, unit) \
272
    DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(fd_##metric, unit);
273
DEFINE_FD_COUNTER_METRIC(num_limit, MetricUnit::NOUNIT);
274
DEFINE_FD_COUNTER_METRIC(num_used, MetricUnit::NOUNIT);
275
276
struct FileDescriptorMetrics {
277
2
    FileDescriptorMetrics(MetricEntity* ent) : entity(ent) {
278
2
        INT_GAUGE_METRIC_REGISTER(entity, fd_num_limit);
279
2
        INT_GAUGE_METRIC_REGISTER(entity, fd_num_used);
280
2
    }
281
282
    MetricEntity* entity = nullptr;
283
    IntGauge* fd_num_limit;
284
    IntGauge* fd_num_used;
285
};
286
287
#define DEFINE_LOAD_AVERAGE_DOUBLE_METRIC(metric)                                     \
288
    DEFINE_GAUGE_METRIC_PROTOTYPE_5ARG(load_average_##metric, MetricUnit::NOUNIT, "", \
289
                                       load_average, Labels({{"mode", #metric}}));
290
DEFINE_LOAD_AVERAGE_DOUBLE_METRIC(1_minutes);
291
DEFINE_LOAD_AVERAGE_DOUBLE_METRIC(5_minutes);
292
DEFINE_LOAD_AVERAGE_DOUBLE_METRIC(15_minutes);
293
294
struct LoadAverageMetrics {
295
2
    LoadAverageMetrics(MetricEntity* ent) : entity(ent) {
296
2
        INT_DOUBLE_METRIC_REGISTER(entity, load_average_1_minutes);
297
2
        INT_DOUBLE_METRIC_REGISTER(entity, load_average_5_minutes);
298
2
        INT_DOUBLE_METRIC_REGISTER(entity, load_average_15_minutes);
299
2
    }
300
301
    MetricEntity* entity = nullptr;
302
    DoubleGauge* load_average_1_minutes;
303
    DoubleGauge* load_average_5_minutes;
304
    DoubleGauge* load_average_15_minutes;
305
};
306
307
#define DEFINE_PROC_STAT_COUNTER_METRIC(metric)                                       \
308
    DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(proc_##metric, MetricUnit::NOUNIT, "", proc, \
309
                                         Labels({{"mode", #metric}}));
310
DEFINE_PROC_STAT_COUNTER_METRIC(interrupt);
311
DEFINE_PROC_STAT_COUNTER_METRIC(ctxt_switch);
312
DEFINE_PROC_STAT_COUNTER_METRIC(procs_running);
313
DEFINE_PROC_STAT_COUNTER_METRIC(procs_blocked);
314
315
struct ProcMetrics {
316
2
    ProcMetrics(MetricEntity* ent) : entity(ent) {
317
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, proc_interrupt);
318
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, proc_ctxt_switch);
319
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, proc_procs_running);
320
2
        INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, proc_procs_blocked);
321
2
    }
322
323
    MetricEntity* entity = nullptr;
324
325
    IntAtomicCounter* proc_interrupt;
326
    IntAtomicCounter* proc_ctxt_switch;
327
    IntAtomicCounter* proc_procs_running;
328
    IntAtomicCounter* proc_procs_blocked;
329
};
330
331
DEFINE_GAUGE_CORE_METRIC_PROTOTYPE_2ARG(max_disk_io_util_percent, MetricUnit::PERCENT);
332
DEFINE_GAUGE_CORE_METRIC_PROTOTYPE_2ARG(max_network_send_bytes_rate, MetricUnit::BYTES);
333
DEFINE_GAUGE_CORE_METRIC_PROTOTYPE_2ARG(max_network_receive_bytes_rate, MetricUnit::BYTES);
334
335
const char* SystemMetrics::_s_hook_name = "system_metrics";
336
337
SystemMetrics::SystemMetrics(MetricRegistry* registry, const std::set<std::string>& disk_devices,
338
2
                             const std::vector<std::string>& network_interfaces) {
339
2
    DCHECK(registry != nullptr);
340
2
    _registry = registry;
341
2
    _server_entity = _registry->register_entity("server");
342
2
    DCHECK(_server_entity != nullptr);
343
2
    _server_entity->register_hook(_s_hook_name, std::bind(&SystemMetrics::update, this));
344
2
    _install_cpu_metrics();
345
2
    _install_memory_metrics(_server_entity.get());
346
2
    _install_disk_metrics(disk_devices);
347
2
    _install_net_metrics(network_interfaces);
348
2
    _install_fd_metrics(_server_entity.get());
349
2
    _install_snmp_metrics(_server_entity.get());
350
2
    _install_load_avg_metrics(_server_entity.get());
351
2
    _install_proc_metrics(_server_entity.get());
352
353
2
    INT_GAUGE_METRIC_REGISTER(_server_entity.get(), max_disk_io_util_percent);
354
2
    INT_GAUGE_METRIC_REGISTER(_server_entity.get(), max_network_send_bytes_rate);
355
2
    INT_GAUGE_METRIC_REGISTER(_server_entity.get(), max_network_receive_bytes_rate);
356
2
}
357
358
2
SystemMetrics::~SystemMetrics() {
359
2
    DCHECK(_server_entity != nullptr);
360
2
    _server_entity->deregister_hook(_s_hook_name);
361
362
33
    for (auto& it : _cpu_metrics) {
363
33
        delete it.second;
364
33
    }
365
2
    for (auto& it : _disk_metrics) {
366
2
        delete it.second;
367
2
    }
368
2
    for (auto& it : _network_metrics) {
369
2
        delete it.second;
370
2
    }
371
2
    if (_line_ptr != nullptr) {
372
1
        free(_line_ptr);
373
1
    }
374
2
}
375
376
1
void SystemMetrics::update() {
377
1
    _update_cpu_metrics();
378
1
    _update_memory_metrics();
379
1
    _update_disk_metrics();
380
1
    _update_net_metrics();
381
1
    _update_fd_metrics();
382
1
    _update_snmp_metrics();
383
1
    _update_load_avg_metrics();
384
1
    _update_proc_metrics();
385
1
}
386
387
2
void SystemMetrics::_install_cpu_metrics() {
388
2
    get_cpu_name();
389
33
    for (auto cpu_name : _cpu_names) {
390
33
        auto cpu_entity = _registry->register_entity(cpu_name, {{"device", cpu_name}});
391
33
        CpuMetrics* metrics = new CpuMetrics(cpu_entity.get());
392
33
        _cpu_metrics.emplace(cpu_name, metrics);
393
33
    }
394
2
}
395
396
#ifdef BE_TEST
397
const char* k_ut_stat_path;
398
const char* k_ut_diskstats_path;
399
const char* k_ut_net_dev_path;
400
const char* k_ut_fd_path;
401
const char* k_ut_net_snmp_path;
402
const char* k_ut_load_avg_path;
403
const char* k_ut_vmstat_path;
404
#endif
405
406
1
void SystemMetrics::_update_cpu_metrics() {
407
1
#ifdef BE_TEST
408
1
    FILE* fp = fopen(k_ut_stat_path, "r");
409
#else
410
    FILE* fp = fopen("/proc/stat", "r");
411
#endif
412
1
    if (fp == nullptr) {
413
0
        char buf[64];
414
0
        LOG(WARNING) << "open /proc/stat failed, errno=" << errno
415
0
                     << ", message=" << strerror_r(errno, buf, 64);
416
0
        return;
417
0
    }
418
419
41
    while (getline(&_line_ptr, &_line_buf_size, fp) > 0) {
420
40
        char cpu[16];
421
40
        int64_t values[CpuMetrics::cpu_num_metrics];
422
40
        memset(values, 0, sizeof(values));
423
40
        int num = sscanf(_line_ptr,
424
40
                         "%15s"
425
40
                         " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64
426
40
                         " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64,
427
40
                         cpu, &values[0], &values[1], &values[2], &values[3], &values[4],
428
40
                         &values[5], &values[6], &values[7], &values[8], &values[9]);
429
40
        if (num < 4) {
430
5
            continue;
431
5
        }
432
433
35
        std::string cpu_name(cpu);
434
35
        auto it = _cpu_metrics.find(cpu_name);
435
35
        if (it == _cpu_metrics.end()) {
436
2
            continue;
437
2
        }
438
439
363
        for (int i = 0; i < CpuMetrics::cpu_num_metrics; ++i) {
440
330
            it->second->metrics[i]->set_value(values[i]);
441
330
        }
442
33
    }
443
444
1
    if (ferror(fp) != 0) {
445
0
        char buf[64];
446
0
        LOG(WARNING) << "getline failed, errno=" << errno
447
0
                     << ", message=" << strerror_r(errno, buf, 64);
448
0
    }
449
450
1
    fclose(fp);
451
1
}
452
453
2
void SystemMetrics::_install_memory_metrics(MetricEntity* entity) {
454
2
    _memory_metrics.reset(new MemoryMetrics(entity));
455
2
}
456
457
1
void SystemMetrics::_update_memory_metrics() {
458
1
    _memory_metrics->memory_allocated_bytes->set_value(PerfCounters::get_vm_rss());
459
1
    get_metrics_from_proc_vmstat();
460
1
}
461
462
0
void SystemMetrics::update_allocator_metrics() {
463
0
#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || defined(THREAD_SANITIZER)
464
0
    LOG(INFO) << "Memory tracking is not available with address sanitizer builds.";
465
#elif defined(USE_JEMALLOC)
466
    _memory_metrics->memory_jemalloc_allocated_bytes->set_value(
467
            MemInfo::get_je_metrics("stats.allocated"));
468
    _memory_metrics->memory_jemalloc_active_bytes->set_value(
469
            MemInfo::get_je_metrics("stats.active"));
470
    _memory_metrics->memory_jemalloc_metadata_bytes->set_value(
471
            MemInfo::get_je_metrics("stats.metadata"));
472
    _memory_metrics->memory_jemalloc_resident_bytes->set_value(
473
            MemInfo::get_je_metrics("stats.resident"));
474
    _memory_metrics->memory_jemalloc_mapped_bytes->set_value(
475
            MemInfo::get_je_metrics("stats.mapped"));
476
    _memory_metrics->memory_jemalloc_retained_bytes->set_value(
477
            MemInfo::get_je_metrics("stats.retained"));
478
    _memory_metrics->memory_jemalloc_tcache_bytes->set_value(
479
            MemInfo::get_je_all_arena_metrics("tcache_bytes"));
480
    _memory_metrics->memory_jemalloc_pactive_num->set_value(
481
            MemInfo::get_je_all_arena_metrics("pactive"));
482
    _memory_metrics->memory_jemalloc_pdirty_num->set_value(
483
            MemInfo::get_je_all_arena_metrics("pdirty"));
484
    _memory_metrics->memory_jemalloc_pmuzzy_num->set_value(
485
            MemInfo::get_je_all_arena_metrics("pmuzzy"));
486
    _memory_metrics->memory_jemalloc_dirty_purged_num->set_value(
487
            MemInfo::get_je_all_arena_metrics("dirty_purged"));
488
    _memory_metrics->memory_jemalloc_muzzy_purged_num->set_value(
489
            MemInfo::get_je_all_arena_metrics("muzzy_purged"));
490
#else
491
    _memory_metrics->memory_tcmalloc_allocated_bytes->set_value(
492
            MemInfo::get_tc_metrics("generic.total_physical_bytes"));
493
    _memory_metrics->memory_tcmalloc_total_thread_cache_bytes->set_value(
494
            MemInfo::allocator_cache_mem());
495
    _memory_metrics->memory_tcmalloc_central_cache_free_bytes->set_value(
496
            MemInfo::get_tc_metrics("tcmalloc.central_cache_free_bytes"));
497
    _memory_metrics->memory_tcmalloc_transfer_cache_free_bytes->set_value(
498
            MemInfo::get_tc_metrics("tcmalloc.transfer_cache_free_bytes"));
499
    _memory_metrics->memory_tcmalloc_thread_cache_free_bytes->set_value(
500
            MemInfo::get_tc_metrics("tcmalloc.thread_cache_free_bytes"));
501
    _memory_metrics->memory_tcmalloc_pageheap_free_bytes->set_value(
502
            MemInfo::get_tc_metrics("tcmalloc.pageheap_free_bytes"));
503
    _memory_metrics->memory_tcmalloc_pageheap_unmapped_bytes->set_value(
504
            MemInfo::get_tc_metrics("tcmalloc.pageheap_unmapped_bytes"));
505
#endif
506
0
}
507
508
2
void SystemMetrics::_install_disk_metrics(const std::set<std::string>& disk_devices) {
509
2
    for (auto& disk_device : disk_devices) {
510
2
        auto disk_entity = _registry->register_entity(std::string("disk_metrics.") + disk_device,
511
2
                                                      {{"device", disk_device}});
512
2
        DiskMetrics* metrics = new DiskMetrics(disk_entity.get());
513
2
        _disk_metrics.emplace(disk_device, metrics);
514
2
    }
515
2
}
516
517
1
void SystemMetrics::_update_disk_metrics() {
518
1
#ifdef BE_TEST
519
1
    FILE* fp = fopen(k_ut_diskstats_path, "r");
520
#else
521
    FILE* fp = fopen("/proc/diskstats", "r");
522
#endif
523
1
    if (fp == nullptr) {
524
0
        char buf[64];
525
0
        LOG(WARNING) << "open /proc/diskstats failed, errno=" << errno
526
0
                     << ", message=" << strerror_r(errno, buf, 64);
527
0
        return;
528
0
    }
529
530
    // /proc/diskstats: https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats
531
    // 1 - major number
532
    // 2 - minor mumber
533
    // 3 - device name
534
    // 4 - reads completed successfully
535
    // 5 - reads merged
536
    // 6 - sectors read
537
    // 7 - time spent reading (ms)
538
    // 8 - writes completed
539
    // 9 - writes merged
540
    // 10 - sectors written
541
    // 11 - time spent writing (ms)
542
    // 12 - I/Os currently in progress
543
    // 13 - time spent doing I/Os (ms)
544
    // 14 - weighted time spent doing I/Os (ms)
545
    // I think 1024 is enough for device name
546
1
    int major = 0;
547
1
    int minor = 0;
548
1
    char device[1024];
549
1
    int64_t values[11];
550
35
    while (getline(&_line_ptr, &_line_buf_size, fp) > 0) {
551
34
        memset(values, 0, sizeof(values));
552
34
        int num = sscanf(_line_ptr,
553
34
                         "%d %d %1023s"
554
34
                         " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64
555
34
                         " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64,
556
34
                         &major, &minor, device, &values[0], &values[1], &values[2], &values[3],
557
34
                         &values[4], &values[5], &values[6], &values[7], &values[8], &values[9],
558
34
                         &values[10]);
559
34
        if (num < 4) {
560
0
            continue;
561
0
        }
562
34
        auto it = _disk_metrics.find(device);
563
34
        if (it == _disk_metrics.end()) {
564
33
            continue;
565
33
        }
566
        // update disk metrics
567
        // reads_completed: 4 reads completed successfully
568
1
        it->second->disk_reads_completed->set_value(values[0]);
569
        // bytes_read: 6 sectors read * 512; 5 reads merged is ignored
570
1
        it->second->disk_bytes_read->set_value(values[2] * 512);
571
        // read_time_ms: 7 time spent reading (ms)
572
1
        it->second->disk_read_time_ms->set_value(values[3]);
573
        // writes_completed: 8 writes completed
574
1
        it->second->disk_writes_completed->set_value(values[4]);
575
        // bytes_written: 10 sectors write * 512; 9 writes merged is ignored
576
1
        it->second->disk_bytes_written->set_value(values[6] * 512);
577
        // write_time_ms: 11 time spent writing (ms)
578
1
        it->second->disk_write_time_ms->set_value(values[7]);
579
        // io_time_ms: 13 time spent doing I/Os (ms)
580
1
        it->second->disk_io_time_ms->set_value(values[9]);
581
        // io_time_weigthed: 14 - weighted time spent doing I/Os (ms)
582
1
        it->second->disk_io_time_weigthed->set_value(values[10]);
583
1
    }
584
1
    if (ferror(fp) != 0) {
585
0
        char buf[64];
586
0
        LOG(WARNING) << "getline failed, errno=" << errno
587
0
                     << ", message=" << strerror_r(errno, buf, 64);
588
0
    }
589
1
    fclose(fp);
590
1
}
591
592
2
void SystemMetrics::_install_net_metrics(const std::vector<std::string>& interfaces) {
593
2
    for (auto& interface : interfaces) {
594
2
        auto interface_entity = _registry->register_entity(
595
2
                std::string("network_metrics.") + interface, {{"device", interface}});
596
2
        NetworkMetrics* metrics = new NetworkMetrics(interface_entity.get());
597
2
        _network_metrics.emplace(interface, metrics);
598
2
    }
599
2
}
600
601
2
void SystemMetrics::_install_snmp_metrics(MetricEntity* entity) {
602
2
    _snmp_metrics.reset(new SnmpMetrics(entity));
603
2
}
604
605
1
void SystemMetrics::_update_net_metrics() {
606
1
#ifdef BE_TEST
607
    // to mock proc
608
1
    FILE* fp = fopen(k_ut_net_dev_path, "r");
609
#else
610
    FILE* fp = fopen("/proc/net/dev", "r");
611
#endif
612
1
    if (fp == nullptr) {
613
0
        char buf[64];
614
0
        LOG(WARNING) << "open /proc/net/dev failed, errno=" << errno
615
0
                     << ", message=" << strerror_r(errno, buf, 64);
616
0
        return;
617
0
    }
618
619
    // Ignore header
620
1
    if (getline(&_line_ptr, &_line_buf_size, fp) < 0 ||
621
1
        getline(&_line_ptr, &_line_buf_size, fp) < 0) {
622
0
        char buf[64];
623
0
        LOG(WARNING) << "read /proc/net/dev first two line failed, errno=" << errno
624
0
                     << ", message=" << strerror_r(errno, buf, 64);
625
0
        fclose(fp);
626
0
        return;
627
0
    }
628
1
    if (_proc_net_dev_version == 0) {
629
1
        if (strstr(_line_ptr, "compressed") != nullptr) {
630
1
            _proc_net_dev_version = 3;
631
1
        } else if (strstr(_line_ptr, "bytes") != nullptr) {
632
0
            _proc_net_dev_version = 2;
633
0
        } else {
634
0
            _proc_net_dev_version = 1;
635
0
        }
636
1
    }
637
638
5
    while (getline(&_line_ptr, &_line_buf_size, fp) > 0) {
639
4
        char* ptr = strrchr(_line_ptr, ':');
640
4
        if (ptr == nullptr) {
641
0
            continue;
642
0
        }
643
4
        char* start = _line_ptr;
644
13
        while (isspace(*start)) {
645
9
            start++;
646
9
        }
647
4
        std::string interface(start, ptr - start);
648
4
        auto it = _network_metrics.find(interface);
649
4
        if (it == _network_metrics.end()) {
650
3
            continue;
651
3
        }
652
1
        ptr++;
653
1
        int64_t receive_bytes = 0;
654
1
        int64_t receive_packets = 0;
655
1
        int64_t send_bytes = 0;
656
1
        int64_t send_packets = 0;
657
1
        switch (_proc_net_dev_version) {
658
1
        case 3:
659
            // receive: bytes packets errs drop fifo frame compressed multicast
660
            // send:    bytes packets errs drop fifo colls carrier compressed
661
1
            sscanf(ptr,
662
1
                   " %" PRId64 " %" PRId64
663
1
                   " %*d %*d %*d %*d %*d %*d"
664
1
                   " %" PRId64 " %" PRId64 " %*d %*d %*d %*d %*d %*d",
665
1
                   &receive_bytes, &receive_packets, &send_bytes, &send_packets);
666
1
            break;
667
0
        case 2:
668
            // receive: bytes packets errs drop fifo frame
669
            // send:    bytes packets errs drop fifo colls carrier
670
0
            sscanf(ptr,
671
0
                   " %" PRId64 " %" PRId64
672
0
                   " %*d %*d %*d %*d"
673
0
                   " %" PRId64 " %" PRId64 " %*d %*d %*d %*d %*d",
674
0
                   &receive_bytes, &receive_packets, &send_bytes, &send_packets);
675
0
            break;
676
0
        case 1:
677
            // receive: packets errs drop fifo frame
678
            // send: packets errs drop fifo colls carrier
679
0
            sscanf(ptr,
680
0
                   " %" PRId64
681
0
                   " %*d %*d %*d %*d"
682
0
                   " %" PRId64 " %*d %*d %*d %*d %*d",
683
0
                   &receive_packets, &send_packets);
684
0
            break;
685
0
        default:
686
0
            break;
687
1
        }
688
1
        it->second->network_receive_bytes->set_value(receive_bytes);
689
1
        it->second->network_receive_packets->set_value(receive_packets);
690
1
        it->second->network_send_bytes->set_value(send_bytes);
691
1
        it->second->network_send_packets->set_value(send_packets);
692
1
    }
693
1
    if (ferror(fp) != 0) {
694
0
        char buf[64];
695
0
        LOG(WARNING) << "getline failed, errno=" << errno
696
0
                     << ", message=" << strerror_r(errno, buf, 64);
697
0
    }
698
1
    fclose(fp);
699
1
}
700
701
1
void SystemMetrics::_update_snmp_metrics() {
702
1
#ifdef BE_TEST
703
    // to mock proc
704
1
    FILE* fp = fopen(k_ut_net_snmp_path, "r");
705
#else
706
    FILE* fp = fopen("/proc/net/snmp", "r");
707
#endif
708
1
    if (fp == nullptr) {
709
0
        char buf[64];
710
0
        LOG(WARNING) << "open /proc/net/snmp failed, errno=" << errno
711
0
                     << ", message=" << strerror_r(errno, buf, 64);
712
0
        return;
713
0
    }
714
715
    // We only care about Tcp lines, so skip other lines in front of Tcp line
716
1
    int res = 0;
717
7
    while ((res = getline(&_line_ptr, &_line_buf_size, fp)) > 0) {
718
7
        if (strstr(_line_ptr, "Tcp") != nullptr) {
719
1
            break;
720
1
        }
721
7
    }
722
1
    if (res <= 0) {
723
0
        char buf[64];
724
0
        LOG(WARNING) << "failed to skip lines of /proc/net/snmp, errno=" << errno
725
0
                     << ", message=" << strerror_r(errno, buf, 64);
726
0
        fclose(fp);
727
0
        return;
728
0
    }
729
730
    // parse the Tcp header
731
    // Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
732
1
    std::vector<std::string> headers = strings::Split(_line_ptr, " ");
733
1
    std::unordered_map<std::string, int32_t> header_map;
734
1
    int32_t pos = 0;
735
16
    for (auto& h : headers) {
736
16
        header_map.emplace(h, pos++);
737
16
    }
738
739
    // read the metrics of TCP
740
1
    if (getline(&_line_ptr, &_line_buf_size, fp) < 0) {
741
0
        char buf[64];
742
0
        LOG(WARNING) << "failed to skip Tcp header line of /proc/net/snmp, errno=" << errno
743
0
                     << ", message=" << strerror_r(errno, buf, 64);
744
0
        fclose(fp);
745
0
        return;
746
0
    }
747
748
    // metric line looks like:
749
    // Tcp: 1 200 120000 -1 47849374 38601877 3353843 2320314 276 1033354613 1166025166 825439 12694 23238924 0
750
1
    std::vector<std::string> metrics = strings::Split(_line_ptr, " ");
751
1
    if (metrics.size() != headers.size()) {
752
0
        LOG(WARNING) << "invalid tcp metrics line: " << _line_ptr;
753
0
        fclose(fp);
754
0
        return;
755
0
    }
756
1
    int64_t retrans_segs = atoi64(metrics[header_map["RetransSegs"]]);
757
1
    int64_t in_errs = atoi64(metrics[header_map["InErrs"]]);
758
1
    int64_t in_segs = atoi64(metrics[header_map["InSegs"]]);
759
1
    int64_t out_segs = atoi64(metrics[header_map["OutSegs"]]);
760
1
    _snmp_metrics->snmp_tcp_retrans_segs->set_value(retrans_segs);
761
1
    _snmp_metrics->snmp_tcp_in_errs->set_value(in_errs);
762
1
    _snmp_metrics->snmp_tcp_in_segs->set_value(in_segs);
763
1
    _snmp_metrics->snmp_tcp_out_segs->set_value(out_segs);
764
765
1
    if (ferror(fp) != 0) {
766
0
        char buf[64];
767
0
        LOG(WARNING) << "getline failed, errno=" << errno
768
0
                     << ", message=" << strerror_r(errno, buf, 64);
769
0
    }
770
1
    fclose(fp);
771
1
}
772
773
2
void SystemMetrics::_install_fd_metrics(MetricEntity* entity) {
774
2
    _fd_metrics.reset(new FileDescriptorMetrics(entity));
775
2
}
776
777
1
void SystemMetrics::_update_fd_metrics() {
778
1
#ifdef BE_TEST
779
1
    FILE* fp = fopen(k_ut_fd_path, "r");
780
#else
781
    FILE* fp = fopen("/proc/sys/fs/file-nr", "r");
782
#endif
783
1
    if (fp == nullptr) {
784
0
        char buf[64];
785
0
        LOG(WARNING) << "open /proc/sys/fs/file-nr failed, errno=" << errno
786
0
                     << ", message=" << strerror_r(errno, buf, 64);
787
0
        return;
788
0
    }
789
790
    // /proc/sys/fs/file-nr: https://www.kernel.org/doc/Documentation/sysctl/fs.txt
791
    // 1 - the number of allocated file handles
792
    // 2 - the number of allocated but unused file handles
793
    // 3 - the maximum number of file handles
794
795
1
    int64_t values[3];
796
1
    if (getline(&_line_ptr, &_line_buf_size, fp) > 0) {
797
1
        memset(values, 0, sizeof(values));
798
1
        int num = sscanf(_line_ptr, "%" PRId64 " %" PRId64 " %" PRId64, &values[0], &values[1],
799
1
                         &values[2]);
800
1
        if (num == 3) {
801
1
            _fd_metrics->fd_num_limit->set_value(values[2]);
802
1
            _fd_metrics->fd_num_used->set_value(values[0] - values[1]);
803
1
        }
804
1
    }
805
806
1
    if (ferror(fp) != 0) {
807
0
        char buf[64];
808
0
        LOG(WARNING) << "getline failed, errno=" << errno
809
0
                     << ", message=" << strerror_r(errno, buf, 64);
810
0
    }
811
1
    fclose(fp);
812
1
}
813
814
2
void SystemMetrics::_install_load_avg_metrics(MetricEntity* entity) {
815
2
    _load_average_metrics.reset(new LoadAverageMetrics(entity));
816
2
}
817
818
1
void SystemMetrics::_update_load_avg_metrics() {
819
1
#ifdef BE_TEST
820
1
    FILE* fp = fopen(k_ut_load_avg_path, "r");
821
#else
822
    FILE* fp = fopen("/proc/loadavg", "r");
823
#endif
824
1
    if (fp == nullptr) {
825
0
        char buf[64];
826
0
        LOG(WARNING) << "open /proc/loadavg failed, errno=" << errno
827
0
                     << ", message=" << strerror_r(errno, buf, 64);
828
0
        return;
829
0
    }
830
831
1
    double values[3];
832
1
    if (getline(&_line_ptr, &_line_buf_size, fp) > 0) {
833
1
        memset(values, 0, sizeof(values));
834
1
        int num = sscanf(_line_ptr, "%lf %lf %lf", &values[0], &values[1], &values[2]);
835
1
        if (num == 3) {
836
1
            _load_average_metrics->load_average_1_minutes->set_value(values[0]);
837
1
            _load_average_metrics->load_average_5_minutes->set_value(values[1]);
838
1
            _load_average_metrics->load_average_15_minutes->set_value(values[2]);
839
1
        }
840
1
    }
841
842
1
    if (ferror(fp) != 0) {
843
0
        char buf[64];
844
0
        LOG(WARNING) << "getline failed, errno=" << errno
845
0
                     << ", message=" << strerror_r(errno, buf, 64);
846
0
    }
847
1
    fclose(fp);
848
1
}
849
850
int64_t SystemMetrics::get_max_io_util(const std::map<std::string, int64_t>& lst_value,
851
0
                                       int64_t interval_sec) {
852
0
    int64_t max = 0;
853
0
    for (auto& it : _disk_metrics) {
854
0
        int64_t cur = it.second->disk_io_time_ms->value();
855
0
        const auto find = lst_value.find(it.first);
856
0
        if (find == lst_value.end()) {
857
0
            continue;
858
0
        }
859
0
        int64_t incr = cur - find->second;
860
0
        if (incr > max) max = incr;
861
0
    }
862
0
    return max / interval_sec / 10;
863
0
}
864
865
0
void SystemMetrics::get_disks_io_time(std::map<std::string, int64_t>* map) {
866
0
    map->clear();
867
0
    for (auto& it : _disk_metrics) {
868
0
        map->emplace(it.first, it.second->disk_io_time_ms->value());
869
0
    }
870
0
}
871
872
0
double SystemMetrics::get_load_average_1_min() {
873
0
    if (_load_average_metrics) {
874
0
        return _load_average_metrics->load_average_1_minutes->value();
875
0
    } else {
876
0
        return 0;
877
0
    }
878
0
}
879
880
void SystemMetrics::get_network_traffic(std::map<std::string, int64_t>* send_map,
881
0
                                        std::map<std::string, int64_t>* rcv_map) {
882
0
    send_map->clear();
883
0
    rcv_map->clear();
884
0
    for (auto& it : _network_metrics) {
885
0
        if (it.first == "lo") {
886
0
            continue;
887
0
        }
888
0
        send_map->emplace(it.first, it.second->network_send_bytes->value());
889
0
        rcv_map->emplace(it.first, it.second->network_receive_bytes->value());
890
0
    }
891
0
}
892
893
void SystemMetrics::get_max_net_traffic(const std::map<std::string, int64_t>& lst_send_map,
894
                                        const std::map<std::string, int64_t>& lst_rcv_map,
895
                                        int64_t interval_sec, int64_t* send_rate,
896
0
                                        int64_t* rcv_rate) {
897
0
    int64_t max_send = 0;
898
0
    int64_t max_rcv = 0;
899
0
    for (auto& it : _network_metrics) {
900
0
        int64_t cur_send = it.second->network_send_bytes->value();
901
0
        int64_t cur_rcv = it.second->network_receive_bytes->value();
902
903
0
        const auto find_send = lst_send_map.find(it.first);
904
0
        if (find_send != lst_send_map.end()) {
905
0
            int64_t incr = cur_send - find_send->second;
906
0
            if (incr > max_send) max_send = incr;
907
0
        }
908
0
        const auto find_rcv = lst_rcv_map.find(it.first);
909
0
        if (find_rcv != lst_rcv_map.end()) {
910
0
            int64_t incr = cur_rcv - find_rcv->second;
911
0
            if (incr > max_rcv) max_rcv = incr;
912
0
        }
913
0
    }
914
915
0
    *send_rate = max_send / interval_sec;
916
0
    *rcv_rate = max_rcv / interval_sec;
917
0
}
918
919
void SystemMetrics::update_max_disk_io_util_percent(const std::map<std::string, int64_t>& lst_value,
920
0
                                                    int64_t interval_sec) {
921
0
    max_disk_io_util_percent->set_value(get_max_io_util(lst_value, interval_sec));
922
0
}
923
924
0
void SystemMetrics::update_max_network_send_bytes_rate(int64_t max_send_bytes_rate) {
925
0
    max_network_send_bytes_rate->set_value(max_send_bytes_rate);
926
0
}
927
928
0
void SystemMetrics::update_max_network_receive_bytes_rate(int64_t max_receive_bytes_rate) {
929
0
    max_network_receive_bytes_rate->set_value(max_receive_bytes_rate);
930
0
}
931
932
2
void SystemMetrics::_install_proc_metrics(MetricEntity* entity) {
933
2
    _proc_metrics.reset(new ProcMetrics(entity));
934
2
}
935
936
1
void SystemMetrics::_update_proc_metrics() {
937
1
#ifdef BE_TEST
938
1
    FILE* fp = fopen(k_ut_stat_path, "r");
939
#else
940
    FILE* fp = fopen("/proc/stat", "r");
941
#endif
942
1
    if (fp == nullptr) {
943
0
        char buf[64];
944
0
        LOG(WARNING) << "open /proc/stat failed, errno=" << errno
945
0
                     << ", message=" << strerror_r(errno, buf, 64);
946
0
        return;
947
0
    }
948
949
1
    uint64_t inter = 0, ctxt = 0, procs_r = 0, procs_b = 0;
950
41
    while (getline(&_line_ptr, &_line_buf_size, fp) > 0) {
951
40
        char* start_pos = nullptr;
952
40
        start_pos = strstr(_line_ptr, "intr ");
953
40
        if (start_pos) {
954
1
            sscanf(start_pos, "intr %" PRIu64, &inter);
955
1
            _proc_metrics->proc_interrupt->set_value(inter);
956
1
        }
957
958
40
        start_pos = strstr(_line_ptr, "ctxt ");
959
40
        if (start_pos) {
960
1
            sscanf(start_pos, "ctxt %" PRIu64, &ctxt);
961
1
            _proc_metrics->proc_ctxt_switch->set_value(ctxt);
962
1
        }
963
964
40
        start_pos = strstr(_line_ptr, "procs_running ");
965
40
        if (start_pos) {
966
1
            sscanf(start_pos, "procs_running %" PRIu64, &procs_r);
967
1
            _proc_metrics->proc_procs_running->set_value(procs_r);
968
1
        }
969
970
40
        start_pos = strstr(_line_ptr, "procs_blocked ");
971
40
        if (start_pos) {
972
1
            sscanf(start_pos, "procs_blocked %" PRIu64, &procs_b);
973
1
            _proc_metrics->proc_procs_blocked->set_value(procs_b);
974
1
        }
975
40
    }
976
977
1
    if (ferror(fp) != 0) {
978
0
        char buf[64];
979
0
        LOG(WARNING) << "getline failed, errno=" << errno
980
0
                     << ", message=" << strerror_r(errno, buf, 64);
981
0
    }
982
983
1
    fclose(fp);
984
1
}
985
986
1
void SystemMetrics::get_metrics_from_proc_vmstat() {
987
1
#ifdef BE_TEST
988
1
    FILE* fp = fopen(k_ut_vmstat_path, "r");
989
#else
990
    FILE* fp = fopen("/proc/vmstat", "r");
991
#endif
992
1
    if (fp == nullptr) {
993
0
        char buf[64];
994
0
        LOG(WARNING) << "open /proc/vmstat failed, errno=" << errno
995
0
                     << ", message=" << strerror_r(errno, buf, 64);
996
0
        return;
997
0
    }
998
999
13
    while (getline(&_line_ptr, &_line_buf_size, fp) > 0) {
1000
12
        uint64_t value;
1001
12
        char name[64];
1002
12
        int num = sscanf(_line_ptr, "%s %" PRIu64, name, &value);
1003
12
        if (num < 2) {
1004
0
            continue;
1005
0
        }
1006
1007
12
        if (strcmp(name, "pgpgin") == 0) {
1008
1
            _memory_metrics->memory_pgpgin->set_value(value);
1009
11
        } else if (strcmp(name, "pgpgout") == 0) {
1010
1
            _memory_metrics->memory_pgpgout->set_value(value);
1011
10
        } else if (strcmp(name, "pswpin") == 0) {
1012
1
            _memory_metrics->memory_pswpin->set_value(value);
1013
9
        } else if (strcmp(name, "pswpout") == 0) {
1014
1
            _memory_metrics->memory_pswpout->set_value(value);
1015
1
        }
1016
12
    }
1017
1018
1
    if (ferror(fp) != 0) {
1019
0
        char buf[64];
1020
0
        LOG(WARNING) << "getline failed, errno=" << errno
1021
0
                     << ", message=" << strerror_r(errno, buf, 64);
1022
0
    }
1023
1024
1
    fclose(fp);
1025
1
}
1026
1027
2
void SystemMetrics::get_cpu_name() {
1028
2
#ifdef BE_TEST
1029
2
    FILE* fp = fopen(k_ut_stat_path, "r");
1030
#else
1031
    FILE* fp = fopen("/proc/stat", "r");
1032
#endif
1033
2
    if (fp == nullptr) {
1034
1
        char buf[64];
1035
1
        LOG(WARNING) << "open /proc/stat failed, errno=" << errno
1036
1
                     << ", message=" << strerror_r(errno, buf, 64);
1037
1
        return;
1038
1
    }
1039
1040
41
    while (getline(&_line_ptr, &_line_buf_size, fp) > 0) {
1041
40
        char cpu[16];
1042
40
        char* start_pos = nullptr;
1043
40
        start_pos = strstr(_line_ptr, "cpu");
1044
40
        if (start_pos) {
1045
33
            sscanf(_line_ptr, "%15s", cpu);
1046
33
            std::string cpu_name(cpu);
1047
33
            _cpu_names.push_back(cpu_name);
1048
33
        }
1049
40
    }
1050
1051
1
    if (ferror(fp) != 0) {
1052
0
        char buf[64];
1053
0
        LOG(WARNING) << "getline failed, errno=" << errno
1054
0
                     << ", message=" << strerror_r(errno, buf, 64);
1055
0
    }
1056
1057
1
    fclose(fp);
1058
1
}
1059
1060
} // namespace doris