Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions module/common/include/oops/str.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ constexpr std::string_view Strip(std::string_view s, std::string_view chars = SP

std::string Elide(std::string_view s, std::size_t n);

// 后续替换成lexcial_cast
template <typename T>
::std::string ToStr(const T &t) {
::std::ostringstream oss;
Expand Down
76 changes: 25 additions & 51 deletions module/profiling/include/oops/system_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,12 @@
namespace oops {
namespace proc {
namespace status {
// clang-format off
enum class Field : uint8_t {
VM_PEAK,
VM_SIZE,
VM_LCK,
VM_PIN,
VM_HWM,
VM_RSS,
RSS_ANON,
RSS_FILE,
RSS_SHMEM,
VM_DATA,
VM_STK,
VM_EXE,
VM_LIB,
VM_PTE,
VM_SWAP,
COUNT
VM_PEAK, VM_SIZE, VM_LCK, VM_PIN, VM_HWM, VM_RSS, RSS_ANON, RSS_FILE, RSS_SHMEM, VM_DATA,
VM_STK, VM_EXE, VM_LIB, VM_PTE, VM_SWAP, COUNT
};
// clang-format on
using FieldMask = EnumBitset<Field>;
using oops::operator|; // 支持Field和FieldMask或运算ADL

Expand Down Expand Up @@ -61,8 +49,8 @@ struct Info {
[[nodiscard]] Info Get(pid_t pid, const FieldMask &field_mask);
std::ostream &operator<<(std::ostream &out, const Info &info);
} // namespace status

// vma数据结构,maps/smaps/smaps共用
namespace maps {
// vma数据结构,maps, smaps, smaps_rollup共用
struct Vma {
std::size_t Size() const { return static_cast<std::size_t>(address.start - address.end); }
std::uint32_t MajorDev() const;
Expand All @@ -86,37 +74,28 @@ struct Vma {
std::string pathname{};
};

struct Info {
std::vector<Vma> vma_table;
};

[[nodiscard]] Info Get();
[[nodiscard]] Info Get(pid_t pid);
std::ostream &operator<<(std::ostream &out, const Info &info);
} // namespace maps
namespace smaps_rollup {
// Since Linux
// clang-format off
enum class Field : uint8_t {
VMA,
RSS,
PSS,
PSS_DIRTY,
PSS_ANON,
PSS_FILE,
PSS_SHMEM,
SHARED_CLEAN,
SHARED_DIRTY,
PRIVATE_CLEAN,
PRIVATE_DIRTY,
REFERENCED,
ANONYMOUS,
KSM,
LAZY_FREE,
ANON_HUGE_PAGES,
SHMEM_PMD_MAPPED,
FILE_PMD_MAPPED,
SHARED_HUGETLB,
PRIVATE_HUGETLB,
SWAP,
SWAP_PSS,
LOCKED,
COUNT
VMA, RSS, PSS, PSS_DIRTY, PSS_ANON, PSS_FILE,
PSS_SHMEM, SHARED_CLEAN, SHARED_DIRTY, PRIVATE_CLEAN, PRIVATE_DIRTY, REFERENCED,
ANONYMOUS, KSM, LAZY_FREE, ANON_HUGE_PAGES, SHMEM_PMD_MAPPED, FILE_PMD_MAPPED,
SHARED_HUGETLB, PRIVATE_HUGETLB, SWAP, SWAP_PSS, LOCKED, COUNT
};
// clang-format on
using FieldMask = EnumBitset<Field>;
using oops::operator|; // 支持Field和FieldMask或运算ADL

using Vma = maps::Vma;
struct Info {
Vma vma;
// 核心内存统计
Expand Down Expand Up @@ -188,17 +167,12 @@ struct Info {
} // namespace proc

namespace lscpu {
// clang-format off
enum class Field {
ARCHITECTURE,
CPUS,
THREADS_PER_CORE,
CORES_PER_SOCKET,
SOCKETS,
NUMA_NODES,
MODEL_NAME,
CPU_MHZ,
COUNT
ARCHITECTURE, CPUS, THREADS_PER_CORE, CORES_PER_SOCKET, SOCKETS, NUMA_NODES,
MODEL_NAME, CPU_MHZ, COUNT
};
// clang-format on
using FieldMask = EnumBitset<Field>;
using oops::operator|; // 支持Field和FieldMask或运算ADL

Expand Down
111 changes: 72 additions & 39 deletions module/profiling/src/system_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ std::string GetCmdOutput(const std::string &cmd) {
class IStreamBacktraceGuard {
public:
explicit IStreamBacktraceGuard(std::istream &is) : is_{is}, pos_{is.tellg()} {}

IStreamBacktraceGuard(const IStreamBacktraceGuard &) = delete;
IStreamBacktraceGuard &operator=(const IStreamBacktraceGuard &) = delete;

Expand All @@ -61,23 +60,33 @@ class IStreamBacktraceGuard {
std::streampos pos_;
};

::std::string ToStr(const KiBs<std::size_t> &t) { return std::to_string(t.Count()); }
template <typename T>
bool ParseField(std::string_view s, T &t, std::string_view ctx = "{}") {
auto scan_res{scn::scan<T>(s, ctx)};
if (scan_res) {
t = scan_res->value();
}
return bool{scan_res};
}

template <>
KiBs<std::size_t> FromStr(const ::std::string_view sv) {
::std::istringstream iss{::std::string{sv}}; // TODO(resserops): 优化自定义stream
std::size_t t{};
iss >> t;
return KiBs<std::size_t>{t};
template <typename R, typename P>
bool ParseField(std::string_view s, Storage<R, P> &storage, std::string_view ctx = "{}") {
R r{};
auto res{ParseField<R>(s, r, ctx)};
storage = Storage<R, P>{r};
return res;
}

template <typename T>
bool FromSv(std::string_view sv, T &value) {
value = FromStr<T>(sv);
return true;
std::string FormatField(const T &t, std::string_view ctx = "{}") {
return fmt::format(ctx, t);
}

template <typename R, typename P>
std::string FormatField(const Storage<R, P> &storage, std::string_view ctx = "{}") {
return FormatField(storage.Count(), ctx);
}

// 新版KeyValueParser
template <typename S, typename F, typename TL>
class KeyValueParser {
template <typename T>
Expand All @@ -97,8 +106,8 @@ class KeyValueParser {
MemberPtrVar member_ptr_var;
std::string suffix{};
// 后续如果没有特殊规则的解析,移除注册固化函数,或者使用fmt格式化字符串
bool (*parse)(std::string_view, MemberPtrVar, Struct &){ParseField};
std::string (*format)(MemberPtrVar, const Struct &){FormatField};
bool (*parse)(std::string_view, MemberPtrVar, Struct &){ParseMemberPtrVar};
std::string (*format)(MemberPtrVar, const Struct &){FormatMemberPtrVar};
};

explicit KeyValueParser(std::initializer_list<Entry> entries) : field_table_{entries} {}
Expand All @@ -109,18 +118,18 @@ class KeyValueParser {
KeyValueParser(std::initializer_list<Entry> entries, std::string delim, std::function<bool(std::string_view)> stop)
: field_table_{entries}, delim_{std::move(delim)}, stop_{std::move(stop)} {}

static bool ParseField(std::string_view value, MemberPtrVar member_ptr_var, Struct &obj) {
auto f = [value, &obj](auto member_ptr) {
static bool ParseMemberPtrVar(std::string_view s, MemberPtrVar member_ptr_var, Struct &obj) {
auto f = [s, &obj](auto member_ptr) {
auto &member{obj.*member_ptr};
return FromSv(value, member);
return ParseField(s, member, "{}");
};
return std::visit(f, member_ptr_var);
}

static std::string FormatField(MemberPtrVar member_ptr_var, const Struct &obj) {
static std::string FormatMemberPtrVar(MemberPtrVar member_ptr_var, const Struct &obj) {
auto f = [&obj](auto member_ptr) -> std::string {
auto &member{obj.*member_ptr};
return ToStr(member);
return FormatField(member, "{}");
};
return std::visit(f, member_ptr_var);
}
Expand All @@ -136,7 +145,7 @@ class KeyValueParser {
if (stop_(line)) {
break;
}
guard.Commit(); // 本行已经确定是KeyValuePair,提交本行
guard.Commit(); // 本行已经确定是kv-pair,提交本行

if (pos == line.npos) {
continue;
Expand Down Expand Up @@ -196,7 +205,7 @@ class KeyValueParser {

namespace proc {
namespace status {
KeyValueParser<Info, Field, TypeList<std::size_t>> parser{
KeyValueParser<Info, Field, TypeList<std::size_t>> kvparser{
{Field::VM_PEAK, "VmPeak", &Info::vm_peak}, {Field::VM_SIZE, "VmSize", &Info::vm_size},
{Field::VM_LCK, "VmLck", &Info::vm_lck}, {Field::VM_PIN, "VmPin", &Info::vm_pin},
{Field::VM_HWM, "VmHWM", &Info::vm_hwm}, {Field::VM_RSS, "VmRSS", &Info::vm_rss},
Expand All @@ -208,7 +217,7 @@ KeyValueParser<Info, Field, TypeList<std::size_t>> parser{

Info Get(std::istream &is, const FieldMask &field_mask) {
Info info;
info.parsed |= parser.Parse(is, info, field_mask);
info.parsed |= kvparser.Parse(is, info, field_mask);
return info;
}

Expand All @@ -221,16 +230,16 @@ Info Get(const FieldMask &field_mask) {
}

Info Get(pid_t pid, const FieldMask &field_mask) {
std::ifstream ifs(std::string{"/proc/"} + std::to_string(pid) + "/status");
std::ifstream ifs(fmt::format("/proc/{}/status", pid));
return Get(ifs, field_mask);
}

std::ostream &operator<<(std::ostream &out, const Info &info) {
parser.Format(out, info, info.parsed);
return out;
std::ostream &operator<<(std::ostream &os, const Info &info) {
kvparser.Format(os, info, info.parsed);
return os;
}
} // namespace status

namespace maps {
std::uint32_t Vma::MajorDev() const { return major(dev); }
std::uint32_t Vma::MinorDev() const { return minor(dev); }

Expand Down Expand Up @@ -293,8 +302,33 @@ void FormatVma(std::ostream &os, const Vma &vma) {
os << "\n";
}

Info Get(std::istream &is) {
Info info;
while (auto res{maps::ParseVma(is)}) {
info.vma_table.push_back(std::move(res.vma));
}
return info;
}

Info Get() {
std::ifstream ifs("/proc/self/maps");
return Get(ifs);
}

Info Get(pid_t pid) {
std::ifstream ifs(fmt::format("/proc/{}/maps", pid));
return Get(ifs);
}

std::ostream &operator<<(std::ostream &os, const Info &info) {
for (const auto &vma : info.vma_table) {
FormatVma(os, vma);
}
return os;
}
} // namespace maps
namespace smaps_rollup {
KeyValueParser<Info, Field, TypeList<KiBs<std::size_t>>> parser{
KeyValueParser<Info, Field, TypeList<KiBs<std::size_t>>> kvparser{
{Field::RSS, "Rss", &Info::rss},
{Field::PSS, "Pss", &Info::pss},
{Field::PSS_DIRTY, "Pss_Dirty", &Info::pss_dirty},
Expand All @@ -321,7 +355,7 @@ KeyValueParser<Info, Field, TypeList<KiBs<std::size_t>>> parser{
Info Get(std::istream &is, const FieldMask &field_mask) {
Info info;
if (field_mask.Test(Field::VMA)) {
auto res{ParseVma(is)};
auto res{maps::ParseVma(is)};
if (res) {
info.vma = std::move(res.vma);
info.parsed.Set(Field::VMA);
Expand All @@ -330,7 +364,7 @@ Info Get(std::istream &is, const FieldMask &field_mask) {
// 跳过VMA行
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
info.parsed |= parser.Parse(is, info, field_mask);
info.parsed |= kvparser.Parse(is, info, field_mask);
return info;
}

Expand All @@ -343,25 +377,24 @@ Info Get(const FieldMask &field_mask) {
}

Info Get(pid_t pid, const FieldMask &field_mask) {
std::ifstream ifs(std::string{"/proc/"} + std::to_string(pid) + "/smaps_rollup");
std::ifstream ifs(fmt::format("/proc/{}/smaps_rollup", pid));
return Get(ifs, field_mask);
}

std::ostream &operator<<(std::ostream &os, const Info &info) {
if (info.parsed.Test(Field::VMA)) {
FormatVma(os, info.vma);
maps::FormatVma(os, info.vma);
}
parser.Format(os, info, info.parsed);
kvparser.Format(os, info, info.parsed);
return os;
}
} // namespace smaps_rollup
namespace numa_maps {
// TODO(resserops): 补充实现
} // namespace numa_maps
} // namespace proc

namespace lscpu {
KeyValueParser<Info, Field, TypeList<std::size_t, double, std::string>> parser{
KeyValueParser<Info, Field, TypeList<std::size_t, double, std::string>> kvparser{
{Field::ARCHITECTURE, "Architecture", &Info::architecture},
{Field::CPUS, "CPU(s)", &Info::cpus},
{Field::THREADS_PER_CORE, "Thread(s) per core", &Info::threads_per_core},
Expand All @@ -375,13 +408,13 @@ Info Get() { return Get(~FieldMask{}); }
Info Get(const FieldMask &field_mask) {
Info info;
std::istringstream iss{GetCmdOutput("lscpu")};
info.parsed |= parser.Parse(iss, info, field_mask);
info.parsed |= kvparser.Parse(iss, info, field_mask);
return info;
}

std::ostream &operator<<(std::ostream &out, const Info &info) {
parser.Format(out, info, info.parsed);
return out;
std::ostream &operator<<(std::ostream &os, const Info &info) {
kvparser.Format(os, info, info.parsed);
return os;
}
} // namespace lscpu
} // namespace oops
5 changes: 5 additions & 0 deletions module/profiling/test/test_system_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ TEST(ProfilingSystemInfo, Lscpu) {
std::cout << lscpu::Get();
}

TEST(ProfilingSystemInfo, Smaps) {
using namespace oops;
std::cout << proc::maps::Get();
}

TEST(ProfilingSystemInfo, SmapsRollup) {
using namespace oops;
std::cout << proc::smaps_rollup::Get();
Expand Down
2 changes: 1 addition & 1 deletion module/profiling/tool/monitor/monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ void ParseArgs(int argc, char *argv[]) {
ENABLED_METRIC_GROUP.Set(MetricGroup::CPU);
matched = true;
}
if ((token == "all" || token == "memory" || token == "m") &&
if ((token == "all" || token == "memory" || token == "mem" || token == "m") &&
!ENABLED_METRIC_GROUP.Test(MetricGroup::MEMORY)) {
ENABLED_METRIC_GROUP.Set(MetricGroup::MEMORY);
matched = true;
Expand Down
Loading