1
#pragma once
2

            
3
#include <memory>
4
#include <string>
5

            
6
#include "envoy/common/time.h"
7
#include "envoy/filesystem/filesystem.h"
8

            
9
#include "source/common/common/logger.h"
10
#include "source/extensions/resource_monitors/cpu_utilization/cpu_paths.h"
11
#include "source/extensions/resource_monitors/cpu_utilization/cpu_stats_reader.h"
12

            
13
#include "absl/strings/string_view.h"
14

            
15
namespace Envoy {
16
namespace Extensions {
17
namespace ResourceMonitors {
18
namespace CpuUtilizationMonitor {
19

            
20
constexpr absl::string_view NoSupportedCGroupMessage =
21
    "No supported cgroup CPU implementation found";
22

            
23
// Internal struct for LinuxCpuStatsReader and CgroupV1CpuStatsReader
24
// (shared implementation without effective_cores)
25
struct CpuTimesBase {
26
  bool is_valid;
27
  double work_time; // For container cpu mode, to support normalisation of cgroup cpu usage stat per
28
                    // cpu core by dividing with available cpu limit
29
  uint64_t total_time;
30
};
31

            
32
// Internal struct for CgroupV2CpuStatsReader (includes effective_cores)
33
struct CpuTimesV2 {
34
  bool is_valid;
35
  double work_time;
36
  uint64_t total_time;
37
  double effective_cores; // number of effective cores available to the container
38
};
39

            
40
static const std::string LINUX_CPU_STATS_FILE = "/proc/stat";
41

            
42
class LinuxCpuStatsReader : public CpuStatsReader {
43
public:
44
  explicit LinuxCpuStatsReader(const std::string& cpu_stats_filename = LINUX_CPU_STATS_FILE);
45
  CpuTimesBase getCpuTimes();
46
  absl::StatusOr<double> getUtilization() override;
47

            
48
private:
49
  const std::string cpu_stats_filename_;
50
  CpuTimesBase previous_cpu_times_{false, 0, 0};
51
};
52

            
53
// Container CPU modes with both cgroup v1 and v2 implementations.
54
class LinuxContainerCpuStatsReader : public CpuStatsReader {
55
public:
56
  using ContainerStatsReaderPtr = std::unique_ptr<LinuxContainerCpuStatsReader>;
57

            
58
35
  virtual ~LinuxContainerCpuStatsReader() = default;
59

            
60
  /**
61
   * Create the appropriate cgroup stats reader.
62
   * @param fs Filesystem instance to use for file operations.
63
   * @param time_source TimeSource for measuring elapsed time.
64
   * @return Unique pointer to concrete LinuxContainerCpuStatsReader implementation.
65
   * @throw EnvoyException if no supported cgroup implementation is found.
66
   */
67
  static ContainerStatsReaderPtr create(Filesystem::Instance& fs, TimeSource& time_source);
68

            
69
protected:
70
  LinuxContainerCpuStatsReader(Filesystem::Instance& fs, TimeSource& time_source)
71
35
      : fs_(fs), time_source_(time_source) {}
72

            
73
  Filesystem::Instance& fs_;
74
  TimeSource& time_source_;
75
};
76

            
77
class CgroupV1CpuStatsReader : public LinuxContainerCpuStatsReader,
78
                               private Logger::Loggable<Logger::Id::main> {
79
public:
80
  explicit CgroupV1CpuStatsReader(Filesystem::Instance& fs, TimeSource& time_source);
81

            
82
  // Test-friendly constructor that accepts custom file paths
83
  CgroupV1CpuStatsReader(Filesystem::Instance& fs, TimeSource& time_source,
84
                         const std::string& shares_path, const std::string& usage_path);
85

            
86
  CpuTimesBase getCpuTimes();
87
  absl::StatusOr<double> getUtilization() override;
88

            
89
private:
90
  static constexpr double CONTAINER_MILLICORES_PER_CORE = 1000.0;
91
  const std::string shares_path_;
92
  const std::string usage_path_;
93
  CpuTimesBase previous_cpu_times_{false, 0, 0};
94
};
95

            
96
class CgroupV2CpuStatsReader : public LinuxContainerCpuStatsReader,
97
                               private Logger::Loggable<Logger::Id::main> {
98
public:
99
  explicit CgroupV2CpuStatsReader(Filesystem::Instance& fs, TimeSource& time_source);
100

            
101
  // Test-friendly constructor that accepts custom file paths
102
  CgroupV2CpuStatsReader(Filesystem::Instance& fs, TimeSource& time_source,
103
                         const std::string& stat_path, const std::string& max_path,
104
                         const std::string& effective_path);
105

            
106
  CpuTimesV2 getCpuTimes();
107
  absl::StatusOr<double> getUtilization() override;
108

            
109
private:
110
  const std::string stat_path_;
111
  const std::string max_path_;
112
  const std::string effective_path_;
113
  CpuTimesV2 previous_cpu_times_{false, 0, 0, 0};
114
};
115

            
116
} // namespace CpuUtilizationMonitor
117
} // namespace ResourceMonitors
118
} // namespace Extensions
119
} // namespace Envoy