From cff66a9903460b9377fbde380f8c56e8e5250212 Mon Sep 17 00:00:00 2001 From: LeandroTreu Date: Mon, 22 Apr 2024 16:46:51 +0200 Subject: [PATCH] cpu util plot --- profile_parser/parse.js | 6 +- profile_parser/parse.ts | 7 +- profile_parser/plot_cpu_util.js | 73 ++++++++++++++++++ profile_parser/plot_cpu_util.ts | 88 ++++++++++++++++++++++ profile_parser/plot_frametime_histogram.js | 13 +++- profile_parser/plot_frametime_histogram.ts | 13 +++- 6 files changed, 186 insertions(+), 14 deletions(-) create mode 100644 profile_parser/plot_cpu_util.js create mode 100644 profile_parser/plot_cpu_util.ts diff --git a/profile_parser/parse.js b/profile_parser/parse.js index 11d1052..2260b65 100644 --- a/profile_parser/parse.js +++ b/profile_parser/parse.js @@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = __importDefault(require("fs")); // Take tasks as framtimes if they are at least this long in microseconds. // Very short tasks (< 2ms) don't correspond to frames drawn. -const MIN_TASK_DURATION = 2000; +const MIN_FRAME_DURATION = 2000; const files_in_directory = fs_1.default.readdirSync("traces"); for (let i = 0; i < files_in_directory.length; ++i) { const filename = files_in_directory[i]; @@ -41,8 +41,8 @@ for (let i = 0; i < files_in_directory.length; ++i) { let event = traceEvents[i]; if (event.pid === main_renderer_pid && event.tid === main_renderer_tid && event.name === "RunTask" && event.ph === "X") { - if (event.dur > MIN_TASK_DURATION) { - frametimeEvents.tasks.push(event); + frametimeEvents.tasks.push(event); + if (event.dur > MIN_FRAME_DURATION) { frametimes.push(event.dur / 1000); } } diff --git a/profile_parser/parse.ts b/profile_parser/parse.ts index 7cb80ac..3becf58 100644 --- a/profile_parser/parse.ts +++ b/profile_parser/parse.ts @@ -2,7 +2,7 @@ import fs from 'fs'; // Take tasks as framtimes if they are at least this long in microseconds. // Very short tasks (< 2ms) don't correspond to frames drawn. -const MIN_TASK_DURATION = 2000; +const MIN_FRAME_DURATION = 2000; const files_in_directory = fs.readdirSync("traces"); @@ -53,8 +53,9 @@ for (let i = 0; i < files_in_directory.length; ++i) { if (event.pid === main_renderer_pid && event.tid === main_renderer_tid && event.name === "RunTask" && event.ph === "X") { - if (event.dur > MIN_TASK_DURATION) { - frametimeEvents.tasks.push(event); + frametimeEvents.tasks.push(event); + + if (event.dur > MIN_FRAME_DURATION) { frametimes.push(event.dur / 1000); } } diff --git a/profile_parser/plot_cpu_util.js b/profile_parser/plot_cpu_util.js new file mode 100644 index 0000000..abebf98 --- /dev/null +++ b/profile_parser/plot_cpu_util.js @@ -0,0 +1,73 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs_1 = __importDefault(require("fs")); +const nodeplotlib_1 = require("nodeplotlib"); +const PLOT_FILES_IN_ONE_GRAPH = true; +const CPU_UTIL_SAMPLE_WINDOW_SIZE_MS = 500; // Adjust for sampling resolution / smoothing +const files_in_directory = fs_1.default.readdirSync("results"); +let data = []; +const layout = { + title: "CPU Utilization", + xaxis: { title: "Time (s)" }, + yaxis: { title: "Utilization (%)", range: [0, 100] }, +}; +for (let i = 0; i < files_in_directory.length; ++i) { + const filename = files_in_directory[i]; + const filenamejsonsuffix = filename.substring(filename.length - 5, filename.length); + if (filenamejsonsuffix === ".json") { + const file_path = "results/" + filename; + console.log("Parsing file %s ...", filename); + const file_data = fs_1.default.readFileSync(file_path, { encoding: 'utf8' }); + const json_data = JSON.parse(file_data); + const tasks = json_data.tasks; + // Sort tasks by timestamps + tasks.sort((a, b) => a.ts - b.ts); + // All units in microseconds + let cpu_util_samples = []; + let x_axis = []; + const total_duration = tasks[tasks.length - 1].ts + tasks[tasks.length - 1].dur - tasks[0].ts; + const window_size = CPU_UTIL_SAMPLE_WINDOW_SIZE_MS * 1000; + let window_start = tasks[0].ts; + let window_end = window_start + window_size; + const n_samples = Math.floor(total_duration / window_size); + for (let i = 0; i < n_samples; ++i) { + let sample_cpu_idle_time = window_size; + for (let j = 0; j < tasks.length; ++j) { + const event = tasks[j]; + if (event.ts <= window_end && event.ts + event.dur >= window_start) { + const clipped_task_time = Math.min(event.dur, window_end - event.ts, event.ts + event.dur - window_start); + sample_cpu_idle_time -= clipped_task_time; + } + } + if (sample_cpu_idle_time < 0) { + sample_cpu_idle_time = 0; + } + let sample_cpu_util = 1 - (sample_cpu_idle_time / window_size); + sample_cpu_util = Math.round(10000 * sample_cpu_util) / 10000; + cpu_util_samples.push(sample_cpu_util * 100); + x_axis.push((window_start - tasks[0].ts) / 1000000); + window_start = window_start + window_size; + window_end = window_start + window_size; + } + const line = { + x: x_axis, + y: cpu_util_samples, + type: 'scatter', + name: filename, + mode: 'lines', + line: { + width: 1 + } + }; + data.push(line); + if (!PLOT_FILES_IN_ONE_GRAPH) { + (0, nodeplotlib_1.plot)(data, layout); + } + } +} +if (PLOT_FILES_IN_ONE_GRAPH) { + (0, nodeplotlib_1.plot)(data, layout); +} diff --git a/profile_parser/plot_cpu_util.ts b/profile_parser/plot_cpu_util.ts new file mode 100644 index 0000000..87516b8 --- /dev/null +++ b/profile_parser/plot_cpu_util.ts @@ -0,0 +1,88 @@ +import fs from 'fs'; +import { plot, Plot } from 'nodeplotlib'; + +const PLOT_FILES_IN_ONE_GRAPH = true; +const CPU_UTIL_SAMPLE_WINDOW_SIZE_MS = 500; // Adjust for sampling resolution / smoothing + +const files_in_directory = fs.readdirSync("results"); + +let data: Plot[] = []; +const layout = { + title: "CPU Utilization", + xaxis: {title: "Time (s)"}, + yaxis: {title: "Utilization (%)", range: [0, 100]}, +} + +for (let i = 0; i < files_in_directory.length; ++i) { + const filename = files_in_directory[i]; + const filenamejsonsuffix = filename.substring(filename.length - 5, filename.length) + + if (filenamejsonsuffix === ".json") { + + const file_path = "results/" + filename; + console.log("Parsing file %s ...", filename); + const file_data = fs.readFileSync(file_path, { encoding: 'utf8' }); + + const json_data = JSON.parse(file_data); + const tasks = json_data.tasks as Array; + + // Sort tasks by timestamps + tasks.sort((a, b) => a.ts - b.ts); + + // All units in microseconds + let cpu_util_samples = []; + let x_axis = []; + const total_duration = tasks[tasks.length-1].ts + tasks[tasks.length-1].dur - tasks[0].ts; + const window_size = CPU_UTIL_SAMPLE_WINDOW_SIZE_MS * 1000; + let window_start = tasks[0].ts; + let window_end = window_start + window_size; + const n_samples = Math.floor(total_duration / window_size); + + for (let i = 0; i < n_samples; ++i) { + + let sample_cpu_idle_time = window_size; + for (let j = 0; j < tasks.length; ++j) { + + const event = tasks[j]; + if (event.ts <= window_end && event.ts + event.dur >= window_start) { + const clipped_task_time = Math.min(event.dur, window_end - event.ts, event.ts + event.dur - window_start); + sample_cpu_idle_time -= clipped_task_time; + } + } + if (sample_cpu_idle_time < 0) { + sample_cpu_idle_time = 0; + } + + let sample_cpu_util = 1 - (sample_cpu_idle_time / window_size); + sample_cpu_util = Math.round(10000 * sample_cpu_util) / 10000; + cpu_util_samples.push(sample_cpu_util * 100); + x_axis.push((window_start - tasks[0].ts) / 1000000); + + window_start = window_start + window_size; + window_end = window_start + window_size; + } + + + const line: Plot = { + x: x_axis, + y: cpu_util_samples, + type: 'scatter', + name: filename, + mode: 'lines', + line: { + width: 1 + } + }; + data.push(line); + if (!PLOT_FILES_IN_ONE_GRAPH) { + plot(data, layout); + } + + } + +} + +if (PLOT_FILES_IN_ONE_GRAPH) { + plot(data, layout); +} + diff --git a/profile_parser/plot_frametime_histogram.js b/profile_parser/plot_frametime_histogram.js index 9a358f7..4f47bff 100644 --- a/profile_parser/plot_frametime_histogram.js +++ b/profile_parser/plot_frametime_histogram.js @@ -5,6 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = __importDefault(require("fs")); const nodeplotlib_1 = require("nodeplotlib"); +// Take tasks as framtimes if they are at least this long in microseconds. +// Very short tasks (< 2ms) don't correspond to frames drawn. +const MIN_FRAME_DURATION = 2000; const MAX_BIN_X_VALUE = 200; const files_in_directory = fs_1.default.readdirSync("results"); for (let i = 0; i < files_in_directory.length; ++i) { @@ -20,11 +23,13 @@ for (let i = 0; i < files_in_directory.length; ++i) { let x_array = []; for (let i = 0; i < frames.length; ++i) { const event = frames[i]; - let event_dur_ms = event.dur / 1000; - if (event_dur_ms > MAX_BIN_X_VALUE) { - event_dur_ms = MAX_BIN_X_VALUE; + if (event.dur > MIN_FRAME_DURATION) { + let event_dur_ms = event.dur / 1000; + if (event_dur_ms > MAX_BIN_X_VALUE) { + event_dur_ms = MAX_BIN_X_VALUE; + } + x_array.push(event_dur_ms); } - x_array.push(event_dur_ms); } const hist = { x: x_array, diff --git a/profile_parser/plot_frametime_histogram.ts b/profile_parser/plot_frametime_histogram.ts index 56d7db3..5f1f481 100644 --- a/profile_parser/plot_frametime_histogram.ts +++ b/profile_parser/plot_frametime_histogram.ts @@ -1,6 +1,9 @@ import fs from 'fs'; import { plot, Plot } from 'nodeplotlib'; +// Take tasks as framtimes if they are at least this long in microseconds. +// Very short tasks (< 2ms) don't correspond to frames drawn. +const MIN_FRAME_DURATION = 2000; const MAX_BIN_X_VALUE = 200; const files_in_directory = fs.readdirSync("results"); @@ -21,11 +24,13 @@ for (let i = 0; i < files_in_directory.length; ++i) { let x_array: number[] = []; for (let i = 0; i < frames.length; ++i) { const event = frames[i]; - let event_dur_ms = event.dur / 1000; - if (event_dur_ms > MAX_BIN_X_VALUE) { - event_dur_ms = MAX_BIN_X_VALUE; + if (event.dur > MIN_FRAME_DURATION) { + let event_dur_ms = event.dur / 1000; + if (event_dur_ms > MAX_BIN_X_VALUE) { + event_dur_ms = MAX_BIN_X_VALUE; + } + x_array.push(event_dur_ms); } - x_array.push(event_dur_ms); } const hist: Plot = { x: x_array,