blob: aaafaabde8fb434acd65e7a572e0a128b88255ff [file]
// Copyright 2025 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEBUGD_SRC_HELPERS_TOP_IO_THREADS_UTILS_H_
#define DEBUGD_SRC_HELPERS_TOP_IO_THREADS_UTILS_H_
#include <iostream>
#include <memory>
#include <queue>
#include <string>
#include <vector>
#include <base/files/dir_reader_posix.h>
namespace debugd {
struct thread_io_stats {
pid_t tid;
pid_t pid;
uint64_t bytes_read;
uint64_t bytes_written;
std::string command;
bool operator<(const thread_io_stats& tios) const {
uint64_t ios1 = bytes_read + bytes_written;
uint64_t ios2 = tios.bytes_read + tios.bytes_written;
// We need a min-heap to collect the set of top I/O intensive threads.
return ios1 > ios2;
}
};
class ProcThreadIterator {
public:
explicit ProcThreadIterator(const std::string& root) : proc_root_(root) {
Init();
}
bool NextThread() { return MoveToNextThread(); }
pid_t GetCurrentProcess() {
return process_iterator_->name() ? std::atoi(process_iterator_->name())
: -1;
}
pid_t GetCurrentThread() {
return thread_iterator_ ? thread_iterator_->name()
? std::atoi(thread_iterator_->name())
: -1
: -1;
}
std::string_view GetCurrentThreadCommand() { return command_; }
uint64_t GetCurrentThreadBytesRead() { return bytes_read_; }
uint64_t GetCurrentThreadBytesWritten() { return bytes_written_; }
protected:
void Init() {
process_iterator_ =
std::make_unique<base::DirReaderPosix>(proc_root_.value().c_str());
}
bool LoadThreadIo();
bool LoadThreadCommand();
bool LoadThreadInfo();
void ResetThreadInfo() {
command_.clear();
bytes_read_ = 0;
bytes_written_ = 0;
}
bool MoveToNextThread();
bool MoveToNextProcess();
base::FilePath GetCurrentProcessTaskPath() {
return proc_root_.Append(std::to_string(GetCurrentProcess()))
.Append("task");
}
base::FilePath GetCurrentThreadPath() {
return GetCurrentProcessTaskPath().Append(
std::to_string(GetCurrentThread()));
}
base::FilePath GetCurrentThreadIoPath() {
return GetCurrentThreadPath().Append("io");
}
base::FilePath GetCurrentThreadCommPath() {
return GetCurrentThreadPath().Append("comm");
}
private:
base::FilePath proc_root_;
std::unique_ptr<base::DirReaderPosix> process_iterator_;
std::unique_ptr<base::DirReaderPosix> thread_iterator_;
std::string command_;
uint64_t bytes_read_;
uint64_t bytes_written_;
};
void LoadThreadIoStats(const base::FilePath& proc_root,
std::vector<thread_io_stats>& stats,
int max_entries);
void PrintThreadIoStats(const std::vector<thread_io_stats>& stats,
std::ostream& output_stream);
} // namespace debugd
#endif // DEBUGD_SRC_HELPERS_TOP_IO_THREADS_UTILS_H_