mirror of
https://github.com/torvalds/linux.git
synced 2025-12-01 07:26:02 +07:00
tools/delaytop: improve error handling for missing PSI support
Enhanced display logic to conditionally show PSI information only when successfully read, with helpful guidance for users to enable PSI support (psi=1 cmdline parameter). Link: https://lkml.kernel.org/r/20250907001417537vSx6nUsb3ILqI0iQ-WnGp@zte.com.cn Signed-off-by: Fan Yu <fan.yu9@zte.com.cn> Reviewed-by: xu xin <xu.xin16@zte.com.cn> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
@@ -44,13 +44,11 @@
|
|||||||
#include <linux/cgroupstats.h>
|
#include <linux/cgroupstats.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define PSI_CPU_SOME "/proc/pressure/cpu"
|
#define PSI_PATH "/proc/pressure"
|
||||||
#define PSI_CPU_FULL "/proc/pressure/cpu"
|
#define PSI_CPU_PATH "/proc/pressure/cpu"
|
||||||
#define PSI_MEMORY_SOME "/proc/pressure/memory"
|
#define PSI_MEMORY_PATH "/proc/pressure/memory"
|
||||||
#define PSI_MEMORY_FULL "/proc/pressure/memory"
|
#define PSI_IO_PATH "/proc/pressure/io"
|
||||||
#define PSI_IO_SOME "/proc/pressure/io"
|
#define PSI_IRQ_PATH "/proc/pressure/irq"
|
||||||
#define PSI_IO_FULL "/proc/pressure/io"
|
|
||||||
#define PSI_IRQ_FULL "/proc/pressure/irq"
|
|
||||||
|
|
||||||
#define NLA_NEXT(na) ((struct nlattr *)((char *)(na) + NLA_ALIGN((na)->nla_len)))
|
#define NLA_NEXT(na) ((struct nlattr *)((char *)(na) + NLA_ALIGN((na)->nla_len)))
|
||||||
#define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN))
|
#define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN))
|
||||||
@@ -499,87 +497,134 @@ static int get_family_id(int sd)
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_psi_stats(void)
|
static int read_psi_stats(void)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char line[256];
|
char line[256];
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int error_count = 0;
|
||||||
|
|
||||||
|
/* Check if PSI path exists */
|
||||||
|
if (access(PSI_PATH, F_OK) != 0) {
|
||||||
|
fprintf(stderr, "Error: PSI interface not found at %s\n", PSI_PATH);
|
||||||
|
fprintf(stderr, "Please ensure your kernel supports PSI (Pressure Stall Information)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Zero all fields */
|
/* Zero all fields */
|
||||||
memset(&psi, 0, sizeof(psi));
|
memset(&psi, 0, sizeof(psi));
|
||||||
|
|
||||||
/* CPU pressure */
|
/* CPU pressure */
|
||||||
fp = fopen(PSI_CPU_SOME, "r");
|
fp = fopen(PSI_CPU_PATH, "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
if (strncmp(line, "some", 4) == 0) {
|
if (strncmp(line, "some", 4) == 0) {
|
||||||
ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
||||||
&psi.cpu_some_avg10, &psi.cpu_some_avg60,
|
&psi.cpu_some_avg10, &psi.cpu_some_avg60,
|
||||||
&psi.cpu_some_avg300, &psi.cpu_some_total);
|
&psi.cpu_some_avg300, &psi.cpu_some_total);
|
||||||
if (ret != 4)
|
if (ret != 4) {
|
||||||
fprintf(stderr, "Failed to parse CPU some PSI data\n");
|
fprintf(stderr, "Failed to parse CPU some PSI data\n");
|
||||||
|
error_count++;
|
||||||
|
}
|
||||||
} else if (strncmp(line, "full", 4) == 0) {
|
} else if (strncmp(line, "full", 4) == 0) {
|
||||||
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
||||||
&psi.cpu_full_avg10, &psi.cpu_full_avg60,
|
&psi.cpu_full_avg10, &psi.cpu_full_avg60,
|
||||||
&psi.cpu_full_avg300, &psi.cpu_full_total);
|
&psi.cpu_full_avg300, &psi.cpu_full_total);
|
||||||
if (ret != 4)
|
if (ret != 4) {
|
||||||
fprintf(stderr, "Failed to parse CPU full PSI data\n");
|
fprintf(stderr, "Failed to parse CPU full PSI data\n");
|
||||||
|
error_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Warning: Failed to open %s\n", PSI_CPU_PATH);
|
||||||
|
error_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Memory pressure */
|
/* Memory pressure */
|
||||||
fp = fopen(PSI_MEMORY_SOME, "r");
|
fp = fopen(PSI_MEMORY_PATH, "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
if (strncmp(line, "some", 4) == 0) {
|
if (strncmp(line, "some", 4) == 0) {
|
||||||
ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
||||||
&psi.memory_some_avg10, &psi.memory_some_avg60,
|
&psi.memory_some_avg10, &psi.memory_some_avg60,
|
||||||
&psi.memory_some_avg300, &psi.memory_some_total);
|
&psi.memory_some_avg300, &psi.memory_some_total);
|
||||||
if (ret != 4)
|
if (ret != 4) {
|
||||||
fprintf(stderr, "Failed to parse Memory some PSI data\n");
|
fprintf(stderr, "Failed to parse Memory some PSI data\n");
|
||||||
|
error_count++;
|
||||||
|
}
|
||||||
} else if (strncmp(line, "full", 4) == 0) {
|
} else if (strncmp(line, "full", 4) == 0) {
|
||||||
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
||||||
&psi.memory_full_avg10, &psi.memory_full_avg60,
|
&psi.memory_full_avg10, &psi.memory_full_avg60,
|
||||||
&psi.memory_full_avg300, &psi.memory_full_total);
|
&psi.memory_full_avg300, &psi.memory_full_total);
|
||||||
}
|
if (ret != 4) {
|
||||||
if (ret != 4)
|
|
||||||
fprintf(stderr, "Failed to parse Memory full PSI data\n");
|
fprintf(stderr, "Failed to parse Memory full PSI data\n");
|
||||||
|
error_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Warning: Failed to open %s\n", PSI_MEMORY_PATH);
|
||||||
|
error_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IO pressure */
|
/* IO pressure */
|
||||||
fp = fopen(PSI_IO_SOME, "r");
|
fp = fopen(PSI_IO_PATH, "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
if (strncmp(line, "some", 4) == 0) {
|
if (strncmp(line, "some", 4) == 0) {
|
||||||
ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
||||||
&psi.io_some_avg10, &psi.io_some_avg60,
|
&psi.io_some_avg10, &psi.io_some_avg60,
|
||||||
&psi.io_some_avg300, &psi.io_some_total);
|
&psi.io_some_avg300, &psi.io_some_total);
|
||||||
if (ret != 4)
|
if (ret != 4) {
|
||||||
fprintf(stderr, "Failed to parse IO some PSI data\n");
|
fprintf(stderr, "Failed to parse IO some PSI data\n");
|
||||||
|
error_count++;
|
||||||
|
}
|
||||||
} else if (strncmp(line, "full", 4) == 0) {
|
} else if (strncmp(line, "full", 4) == 0) {
|
||||||
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
||||||
&psi.io_full_avg10, &psi.io_full_avg60,
|
&psi.io_full_avg10, &psi.io_full_avg60,
|
||||||
&psi.io_full_avg300, &psi.io_full_total);
|
&psi.io_full_avg300, &psi.io_full_total);
|
||||||
if (ret != 4)
|
if (ret != 4) {
|
||||||
fprintf(stderr, "Failed to parse IO full PSI data\n");
|
fprintf(stderr, "Failed to parse IO full PSI data\n");
|
||||||
|
error_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Warning: Failed to open %s\n", PSI_IO_PATH);
|
||||||
|
error_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IRQ pressure (only full) */
|
/* IRQ pressure (only full) */
|
||||||
fp = fopen(PSI_IRQ_FULL, "r");
|
fp = fopen(PSI_IRQ_PATH, "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
if (strncmp(line, "full", 4) == 0) {
|
if (strncmp(line, "full", 4) == 0) {
|
||||||
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
|
||||||
&psi.irq_full_avg10, &psi.irq_full_avg60,
|
&psi.irq_full_avg10, &psi.irq_full_avg60,
|
||||||
&psi.irq_full_avg300, &psi.irq_full_total);
|
&psi.irq_full_avg300, &psi.irq_full_total);
|
||||||
if (ret != 4)
|
if (ret != 4) {
|
||||||
fprintf(stderr, "Failed to parse IRQ full PSI data\n");
|
fprintf(stderr, "Failed to parse IRQ full PSI data\n");
|
||||||
|
error_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Warning: Failed to open %s\n", PSI_IRQ_PATH);
|
||||||
|
error_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return error count: 0 means success, >0 means warnings, -1 means fatal error */
|
||||||
|
if (error_count > 0) {
|
||||||
|
fprintf(stderr, "PSI stats reading completed with %d warnings\n", error_count);
|
||||||
|
return error_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_comm(int pid, char *comm_buf, size_t buf_size)
|
static int read_comm(int pid, char *comm_buf, size_t buf_size)
|
||||||
@@ -820,7 +865,7 @@ static void get_container_stats(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Display results to stdout or log file */
|
/* Display results to stdout or log file */
|
||||||
static void display_results(void)
|
static void display_results(int psi_ret)
|
||||||
{
|
{
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
struct tm *tm_now = localtime(&now);
|
struct tm *tm_now = localtime(&now);
|
||||||
@@ -833,7 +878,10 @@ static void display_results(void)
|
|||||||
suc &= BOOL_FPRINT(out, "\033[H\033[J");
|
suc &= BOOL_FPRINT(out, "\033[H\033[J");
|
||||||
|
|
||||||
/* PSI output (one-line, no cat style) */
|
/* PSI output (one-line, no cat style) */
|
||||||
suc &= BOOL_FPRINT(out, "System Pressure Information: (avg10/avg60/avg300/total)\n");
|
suc &= BOOL_FPRINT(out, "System Pressure Information: (avg10/avg60vg300/total)\n");
|
||||||
|
if (psi_ret) {
|
||||||
|
suc &= BOOL_FPRINT(out, " PSI not found: check if psi=1 enabled in cmdline\n");
|
||||||
|
} else {
|
||||||
suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
|
suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
|
||||||
"CPU some:",
|
"CPU some:",
|
||||||
psi.cpu_some_avg10,
|
psi.cpu_some_avg10,
|
||||||
@@ -876,6 +924,7 @@ static void display_results(void)
|
|||||||
psi.irq_full_avg60,
|
psi.irq_full_avg60,
|
||||||
psi.irq_full_avg300,
|
psi.irq_full_avg300,
|
||||||
psi.irq_full_total / 1000);
|
psi.irq_full_total / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
if (cfg.container_path) {
|
if (cfg.container_path) {
|
||||||
suc &= BOOL_FPRINT(out, "Container Information (%s):\n", cfg.container_path);
|
suc &= BOOL_FPRINT(out, "Container Information (%s):\n", cfg.container_path);
|
||||||
@@ -1017,6 +1066,7 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
const struct field_desc *field;
|
const struct field_desc *field;
|
||||||
int iterations = 0;
|
int iterations = 0;
|
||||||
|
int psi_ret = 0;
|
||||||
char keypress;
|
char keypress;
|
||||||
|
|
||||||
/* Parse command line arguments */
|
/* Parse command line arguments */
|
||||||
@@ -1054,7 +1104,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Read PSI statistics */
|
/* Read PSI statistics */
|
||||||
read_psi_stats();
|
psi_ret = read_psi_stats();
|
||||||
|
|
||||||
/* Get container stats if container path provided */
|
/* Get container stats if container path provided */
|
||||||
if (cfg.container_path)
|
if (cfg.container_path)
|
||||||
@@ -1067,7 +1117,7 @@ int main(int argc, char **argv)
|
|||||||
sort_tasks();
|
sort_tasks();
|
||||||
|
|
||||||
/* Display results to stdout or log file */
|
/* Display results to stdout or log file */
|
||||||
display_results();
|
display_results(psi_ret);
|
||||||
|
|
||||||
/* Check for iterations */
|
/* Check for iterations */
|
||||||
if (cfg.iterations > 0 && ++iterations >= cfg.iterations)
|
if (cfg.iterations > 0 && ++iterations >= cfg.iterations)
|
||||||
|
|||||||
Reference in New Issue
Block a user