text: // Copyright 2021 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef CONTENT_BROWSER_COMPUTE_PRESSURE_PROCFS_STAT_CPU_PARSER_H_
  #define CONTENT_BROWSER_COMPUTE_PRESSURE_PROCFS_STAT_CPU_PARSER_H_
  
  #include <stdint.h>
  
  #include <vector>
  
  #include "base/files/file_path.h"
  #include "base/sequence_checker.h"
  #include "base/strings/string_piece.h"
  #include "base/thread_annotations.h"
  #include "content/common/content_export.h"
  
  namespace content {
  
  // Parses CPU time usage stats from procfs (/proc/stat).
  //
  // This class is not thread-safe. Each instance must be used on the same
  // sequence, which must allow blocking I/O. The constructor may be used on a
  // different sequence.
  class CONTENT_EXPORT ProcfsStatCpuParser {
   public:
    // CPU core utilization statistics.
    //
    // Quantities are expressed in "user hertz", which is a Linux kernel
    // configuration knob (USER_HZ). Typical values range between 1/100 seconds
    // and 1/1000 seconds. The denominator can be obtained from
    // sysconf(_SC_CLK_TCK).
    struct CoreTimes {
      // Normal processes executing in user mode.
      uint64_t user() const { return times[0]; }
      // Niced processes executing in user mode.
      uint64_t nice() const { return times[1]; }
      // Processes executing in kernel mode.
      uint64_t system() const { return times[2]; }
      // Twiddling thumbs.
      uint64_t idle() const { return times[3]; }
      // Waiting for I/O to complete. Unreliable.
      uint64_t iowait() const { return times[4]; }
      // Servicing interrupts.
      uint64_t irq() const { return times[5]; }
      // Servicing softirqs.
      uint64_t softirq() const { return times[6]; }
      // Involuntary wait.
      uint64_t steal() const { return times[7]; }
      // Running a normal guest.
      uint64_t guest() const { return times[8]; }
      // Running a niced guest.
      uint64_t guest_nice() const { return times[9]; }
  
      uint64_t times[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  
      // Computes a CPU's utilization over the time between two stat snapshots.
      //
      // Returns a value between 0.0 and 1.0 on success, and -1.0 when given
      // invalid data, such as a `baseline` that does not represent a stat
      // snapshot collected before `this` snapshot.
      double TimeUtilization(const CoreTimes& baseline) const;
    };
  
    // The "production" `procfs_path` value for the constructor.
    static constexpr base::FilePath::CharType kProcfsStatPath[] =
        FILE_PATH_LITERAL("/proc/stat");
  
    // `stat_path` is exposed for testing. Production instances should be
    // constructed using base::FilePath(kProcfsStatPath).
    explicit ProcfsStatCpuParser(base::FilePath stat_path);
    ~ProcfsStatCpuParser();
  
    ProcfsStatCpuParser(const ProcfsStatCpuParser&) = delete;
    ProcfsStatCpuParser& operator=(const ProcfsStatCpuParser&) = delete;
  
    const std::vector<CoreTimes>& core_times() const {
      DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
      return core_times_;
    }
  
    // Reads /proc/stat and updates the vector returned by core_times().
    //
    // Returns false if parsing fails. This only happens if /proc/stat is not
    // accessible. Invalid data is ignored.
    //
    // Cores without entries in /proc/stat will remain unchanged. Counters that
    // decrease below the last parsed value are ignored.
    bool Update();
  
   private:
    // Returns -1 if the line does not include any CPU.
    static int CoreIdFromLine(base::StringPiece stat_line);
  
    static void UpdateCore(base::StringPiece core_line, CoreTimes& core_times);
  
    SEQUENCE_CHECKER(sequence_checker_);
  
    const base::FilePath stat_path_;
  
    std::vector<CoreTimes> core_times_ GUARDED_BY_CONTEXT(sequence_checker_);
  };
  
  }  // namespace content
  
  #endif  // CONTENT_BROWSER_COMPUTE_PRESSURE_PROCFS_STAT_CPU_PARSER_H_
  