From 5d39455cbd9e395b99082f319e29f660ffb601de Mon Sep 17 00:00:00 2001 From: GK Date: Sun, 24 Nov 2024 14:30:41 +0530 Subject: [PATCH 1/5] Cgroup V2 statistic engine improvements --- .../common-code/cmonitor_statistics_engine.py | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/tools/common-code/cmonitor_statistics_engine.py b/tools/common-code/cmonitor_statistics_engine.py index b85ac68d..d5b8c30e 100644 --- a/tools/common-code/cmonitor_statistics_engine.py +++ b/tools/common-code/cmonitor_statistics_engine.py @@ -14,6 +14,7 @@ import gzip from statistics import mean, median, mode, StatisticsError + # ======================================================================================================= # Helper classes # ======================================================================================================= @@ -102,16 +103,21 @@ def dump_cpu_stats(self, verbose) -> dict: def dump_cpu_throttle_stats(self, verbose) -> dict: return self.cpu_throttle.dump_json(verbose) - def insert_memory_stats(self, stats: dict, sample_index: int) -> None: - if "stat.rss" in stats: - self.memory.insert_stat(stats["stat.rss"]) + def insert_memory_stats(self, stats: dict, sample_index: int, cgroup_version: int) -> None: + stat_label = "stat.rss" if cgroup_version == 1 else "stat.file" + if stat_label in stats: + self.memory.insert_stat(stats[stat_label]) else: - print(f"WARNING: The JSON file provided does not contain the 'stat.rss' measurement for sample #{sample_index}. Skipping this sample.") - if "events.failcnt" in stats: - self.memory_failcnt.insert_stat(stats["events.failcnt"]) + print( + f"WARNING: The JSON file provided does not contain the '{stat_label}' measurement for sample #{sample_index}. Skipping this sample." + ) + + stat_label = "events.failcnt" if cgroup_version == 1 else "events.oom_kill" + if stat_label in stats: + self.memory_failcnt.insert_stat(stats[stat_label]) else: print( - f"WARNING: The JSON file provided does not contain the 'events.failcnt' measurement for sample #{sample_index}. Skipping this sample." + f"WARNING: The JSON file provided does not contain the '{stat_label}' measurement for sample #{sample_index}. Skipping this sample." ) def dump_memory_stats(self, verbose) -> dict: @@ -152,6 +158,15 @@ def process(self, json_data) -> bool: print("This tool requires at least 3 samples in the input JSON file. Aborting.") return False + cgroup_version = None + jheader = json_data["header"] + if "cgroup_config" in jheader and "version" in jheader["cgroup_config"]: + cgroup_version = int(jheader["cgroup_config"]["version"]) + + if cgroup_version == None: + print(f"Unsupported cgroup version -> {cgroup_version}") + return False + # skip sample 0 because it contains less statistics due to the differential logic that requires some # initialization sample for most of the stats first_sample = json_data["samples"][1] @@ -183,7 +198,7 @@ def process(self, json_data) -> bool: if do_cpu_stats: self.cgroup_statistics.insert_cpu_stats(sample["cgroup_cpuacct_stats"], nsample) if do_memory_stats: - self.cgroup_statistics.insert_memory_stats(sample["cgroup_memory_stats"], nsample) + self.cgroup_statistics.insert_memory_stats(sample["cgroup_memory_stats"], nsample, cgroup_version) self.num_samples_analyzed = len(samples_to_analyze) # self.cgroup_statistics.insert_io_stats(stats) # cgroup_blkio not yet available From b42f3ebdfb9c9eef20a7fe8d1e7b1ac9f85cff60 Mon Sep 17 00:00:00 2001 From: GK Date: Sun, 24 Nov 2024 15:38:35 +0530 Subject: [PATCH 2/5] improve readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b0620fe0..40cd4d74 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,7 @@ Then run: ``` # install compiler tools & library dependencies with YUM: -sudo dnf install -y gcc-c++ make gtest-devel fmt-devel google-benchmark-devel +sudo dnf install -y gcc-c++ make gtest-devel fmt-devel benchmark-dev # install dependencies with Conan: # (this part can be skipped if you are not interested in Prometheus support) From bacca60e3c2b33e9c5491f990ef225185d2f4938 Mon Sep 17 00:00:00 2001 From: GK Date: Sun, 24 Nov 2024 16:35:55 +0530 Subject: [PATCH 3/5] Default cgroup version to 1 --- tools/common-code/cmonitor_statistics_engine.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tools/common-code/cmonitor_statistics_engine.py b/tools/common-code/cmonitor_statistics_engine.py index d5b8c30e..026207de 100644 --- a/tools/common-code/cmonitor_statistics_engine.py +++ b/tools/common-code/cmonitor_statistics_engine.py @@ -158,14 +158,12 @@ def process(self, json_data) -> bool: print("This tool requires at least 3 samples in the input JSON file. Aborting.") return False - cgroup_version = None + cgroup_version = 1 jheader = json_data["header"] if "cgroup_config" in jheader and "version" in jheader["cgroup_config"]: cgroup_version = int(jheader["cgroup_config"]["version"]) - - if cgroup_version == None: - print(f"Unsupported cgroup version -> {cgroup_version}") - return False + else: + print(f"WARNING: cgroup version not found in header using default value {cgroup_version}") # skip sample 0 because it contains less statistics due to the differential logic that requires some # initialization sample for most of the stats From 3784516d17f964082c5141df004b01809d158284 Mon Sep 17 00:00:00 2001 From: GK Date: Mon, 25 Nov 2024 10:19:07 +0530 Subject: [PATCH 4/5] For cgroup v2 use sum of 'file' and 'anon' for memory utilization stats --- .../common-code/cmonitor_statistics_engine.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tools/common-code/cmonitor_statistics_engine.py b/tools/common-code/cmonitor_statistics_engine.py index 026207de..b025e2a5 100644 --- a/tools/common-code/cmonitor_statistics_engine.py +++ b/tools/common-code/cmonitor_statistics_engine.py @@ -104,13 +104,19 @@ def dump_cpu_throttle_stats(self, verbose) -> dict: return self.cpu_throttle.dump_json(verbose) def insert_memory_stats(self, stats: dict, sample_index: int, cgroup_version: int) -> None: - stat_label = "stat.rss" if cgroup_version == 1 else "stat.file" - if stat_label in stats: - self.memory.insert_stat(stats[stat_label]) - else: - print( - f"WARNING: The JSON file provided does not contain the '{stat_label}' measurement for sample #{sample_index}. Skipping this sample." - ) + stat_labels = ["stat.rss"] if cgroup_version == 1 else ["stats.anon", "stat.file"] + rss = 0 + all_stat_found = True + for stat_label in stat_labels: + if stat_label in stats: + rss += stats[stat_label] + else: + print( + f"WARNING: The JSON file provided does not contain the '{stat_label}' measurement for sample #{sample_index}. Skipping this sample." + ) + all_stat_found = False + if all_stat_found: + self.memory.insert_stat(rss) stat_label = "events.failcnt" if cgroup_version == 1 else "events.oom_kill" if stat_label in stats: From 35c12a032fa8df16fb4c601c3b775e4e52fe8ddf Mon Sep 17 00:00:00 2001 From: GK Date: Mon, 25 Nov 2024 10:41:36 +0530 Subject: [PATCH 5/5] correction --- tools/common-code/cmonitor_statistics_engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/common-code/cmonitor_statistics_engine.py b/tools/common-code/cmonitor_statistics_engine.py index b025e2a5..96bb488f 100644 --- a/tools/common-code/cmonitor_statistics_engine.py +++ b/tools/common-code/cmonitor_statistics_engine.py @@ -104,7 +104,7 @@ def dump_cpu_throttle_stats(self, verbose) -> dict: return self.cpu_throttle.dump_json(verbose) def insert_memory_stats(self, stats: dict, sample_index: int, cgroup_version: int) -> None: - stat_labels = ["stat.rss"] if cgroup_version == 1 else ["stats.anon", "stat.file"] + stat_labels = ["stat.rss"] if cgroup_version == 1 else ["stat.anon", "stat.file"] rss = 0 all_stat_found = True for stat_label in stat_labels: