blob: 01af39f65b82d83e689eedd3536d206afbc954a5 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// This file is copied from
// https://github.com/apache/impala/blob/branch-2.9.0/be/src/util/perf-counters.h
// and modified by Doris
#pragma once
#include <gen_cpp/Metrics_types.h>
#include <stdint.h>
#include <iostream>
#include <string>
#include <vector>
// This is a utility class that aggregates counters from the kernel. These counters
// come from different sources.
// - perf counter syscall (/usr/include/linux/perf_event.h")
// - /proc/self/io: io stats
// - /proc/self/status: memory stats
// The complexity here is that all these sources have data in a different and not
// easy to get at format.
//
// A typical usage pattern would be:
// PerfCounters counters;
// counters.add_default_counters();
// counters.snapshot("After Init");
// <do your work>
// counters.snapshot("After Work");
// counters.PrettyPrint(cout);
//
// TODO: Expect PerfCounters to be refactored to ProcessState.
namespace doris {
class PerfCounters {
public:
enum Counter {
PERF_COUNTER_SW_CPU_CLOCK,
PERF_COUNTER_SW_PAGE_FAULTS,
PERF_COUNTER_SW_CONTEXT_SWITCHES,
PERF_COUNTER_SW_CPU_MIGRATIONS,
PERF_COUNTER_HW_CPU_CYCLES,
PERF_COUNTER_HW_INSTRUCTIONS,
PERF_COUNTER_HW_CACHE_HIT,
PERF_COUNTER_HW_CACHE_MISSES,
PERF_COUNTER_HW_BRANCHES,
PERF_COUNTER_HW_BRANCH_MISSES,
PERF_COUNTER_HW_BUS_CYCLES,
PERF_COUNTER_VM_USAGE,
PERF_COUNTER_VM_PEAK_USAGE,
PERF_COUNTER_RESIDENT_SET_SIZE,
PERF_COUNTER_BYTES_READ,
PERF_COUNTER_BYTES_WRITE,
PERF_COUNTER_DISK_READ,
PERF_COUNTER_DISK_WRITE,
};
// Add the 'default' counters as ones to collect. Returns false if any of those
// counters are not available.
// Counters cannot be added after a snapshot has been taken.
bool add_default_counters();
// Add a specific counter to watch. Return false if that counter is not available.
// Counters cannot be added after a snapshot has been taken.
bool add_counter(Counter);
// Take a snapshot of all the counters and store it. The caller can specify a name
// for the snapshot.
void snapshot(const std::string& name);
// Returns the results of that snapshot
const std::vector<int64_t>* counters(int snapshot) const;
// Returns readable names for the added counters
const std::vector<std::string>* counter_names() const { return &_counter_names; }
// Prints out the names and results for all snapshots to 'out'
void pretty_print(std::ostream* out) const;
PerfCounters();
~PerfCounters();
// Refactor
struct ProcStatus {
int64_t vm_size = 0;
int64_t vm_peak = 0;
int64_t vm_rss = 0;
int64_t vm_hwm = 0;
};
static int parse_int(const std::string& state_key);
static int64_t parse_int64(const std::string& state_key);
static std::string parse_string(const std::string& state_key);
// Original data's unit is B or KB.
static int64_t parse_bytes(const std::string& state_key);
// Flush cached process status info from `/proc/self/status`.
static void refresh_proc_status();
static void get_proc_status(ProcStatus* out);
// Return the process actual physical memory in bytes.
static inline int64_t get_vm_rss() { return _vm_rss; }
static inline std::string get_vm_rss_str() { return _vm_rss_str; }
static inline int64_t get_vm_hwm() { return _vm_hwm; }
static inline int64_t get_vm_size() { return _vm_size; }
static inline int64_t get_vm_peak() { return _vm_peak; }
private:
// Copy constructor and assignment not allowed
PerfCounters(const PerfCounters&);
PerfCounters& operator=(const PerfCounters&);
bool init_sys_counter(Counter counter);
bool init_proc_self_io_counter(Counter counter);
bool init_proc_self_status_counter(Counter counter);
bool get_sys_counters(std::vector<int64_t>& snapshot);
bool get_proc_self_io_counters(std::vector<int64_t>& snapshot);
bool get_proc_self_status_counters(std::vector<int64_t>& snapshot);
enum DataSource {
SYS_PERF_COUNTER,
PROC_SELF_IO,
PROC_SELF_STATUS,
};
struct CounterData {
Counter counter;
DataSource source;
TUnit::type type;
// DataSource specific data. This is used to pull the counter values.
union {
// For SYS_PERF_COUNTER. File descriptor where the counter value is stored.
int64_t fd;
// For PROC_SELF_IO. Line number from /proc/self/io file with this counter's value
int proc_io_line_number;
};
// For PROC_SELF_STATUS. Field name for counter
std::string proc_status_field;
};
std::vector<CounterData> _counters;
std::vector<std::string> _counter_names;
std::vector<std::string> _snapshot_names;
std::vector<std::vector<int64_t>> _snapshots;
// System perf counters can be grouped together. The OS will update all grouped counters
// at the same time. This is useful to better correlate counter values.
int64_t _group_fd;
static int64_t _vm_rss;
static std::string _vm_rss_str;
static int64_t _vm_hwm;
static int64_t _vm_size;
static int64_t _vm_peak;
};
} // namespace doris