]> www.infradead.org Git - users/hch/misc.git/commitdiff
tools/delaytop: improve error handling for missing PSI support
authorFan Yu <fan.yu9@zte.com.cn>
Sat, 6 Sep 2025 16:14:17 +0000 (00:14 +0800)
committerAndrew Morton <akpm@linux-foundation.org>
Sun, 14 Sep 2025 00:32:56 +0000 (17:32 -0700)
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>
tools/accounting/delaytop.c

index 7bd1a1eeb354d22266ad12bd67ec61571f6ce645..72cc500b44b15807ed92686f6040ffdb727592d9 100644 (file)
 #include <linux/cgroupstats.h>
 #include <stddef.h>
 
-#define PSI_CPU_SOME "/proc/pressure/cpu"
-#define PSI_CPU_FULL   "/proc/pressure/cpu"
-#define PSI_MEMORY_SOME "/proc/pressure/memory"
-#define PSI_MEMORY_FULL "/proc/pressure/memory"
-#define PSI_IO_SOME "/proc/pressure/io"
-#define PSI_IO_FULL "/proc/pressure/io"
-#define PSI_IRQ_FULL   "/proc/pressure/irq"
+#define PSI_PATH       "/proc/pressure"
+#define PSI_CPU_PATH   "/proc/pressure/cpu"
+#define PSI_MEMORY_PATH        "/proc/pressure/memory"
+#define PSI_IO_PATH    "/proc/pressure/io"
+#define PSI_IRQ_PATH   "/proc/pressure/irq"
 
 #define NLA_NEXT(na)                   ((struct nlattr *)((char *)(na) + NLA_ALIGN((na)->nla_len)))
 #define NLA_DATA(na)                   ((void *)((char *)(na) + NLA_HDRLEN))
@@ -499,87 +497,134 @@ static int get_family_id(int sd)
        return id;
 }
 
-static void read_psi_stats(void)
+static int read_psi_stats(void)
 {
        FILE *fp;
        char line[256];
        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 */
        memset(&psi, 0, sizeof(psi));
+
        /* CPU pressure */
-       fp = fopen(PSI_CPU_SOME, "r");
+       fp = fopen(PSI_CPU_PATH, "r");
        if (fp) {
                while (fgets(line, sizeof(line), fp)) {
                        if (strncmp(line, "some", 4) == 0) {
                                ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
                                                        &psi.cpu_some_avg10, &psi.cpu_some_avg60,
                                                        &psi.cpu_some_avg300, &psi.cpu_some_total);
-                               if (ret != 4)
+                               if (ret != 4) {
                                        fprintf(stderr, "Failed to parse CPU some PSI data\n");
+                                       error_count++;
+                               }
                        } else if (strncmp(line, "full", 4) == 0) {
                                ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
                                                &psi.cpu_full_avg10, &psi.cpu_full_avg60,
                                                &psi.cpu_full_avg300, &psi.cpu_full_total);
-                               if (ret != 4)
+                               if (ret != 4) {
                                        fprintf(stderr, "Failed to parse CPU full PSI data\n");
+                                       error_count++;
+                               }
                        }
                }
                fclose(fp);
+       } else {
+               fprintf(stderr, "Warning: Failed to open %s\n", PSI_CPU_PATH);
+               error_count++;
        }
+
        /* Memory pressure */
-       fp = fopen(PSI_MEMORY_SOME, "r");
+       fp = fopen(PSI_MEMORY_PATH, "r");
        if (fp) {
                while (fgets(line, sizeof(line), fp)) {
                        if (strncmp(line, "some", 4) == 0) {
                                ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
                                                &psi.memory_some_avg10, &psi.memory_some_avg60,
                                                &psi.memory_some_avg300, &psi.memory_some_total);
-                               if (ret != 4)
+                               if (ret != 4) {
                                        fprintf(stderr, "Failed to parse Memory some PSI data\n");
+                                       error_count++;
+                               }
                        } else if (strncmp(line, "full", 4) == 0) {
                                ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
                                                &psi.memory_full_avg10, &psi.memory_full_avg60,
                                                &psi.memory_full_avg300, &psi.memory_full_total);
-                       }
-                               if (ret != 4)
+                               if (ret != 4) {
                                        fprintf(stderr, "Failed to parse Memory full PSI data\n");
+                                       error_count++;
+                               }
+                       }
                }
                fclose(fp);
+       } else {
+               fprintf(stderr, "Warning: Failed to open %s\n", PSI_MEMORY_PATH);
+               error_count++;
        }
+
        /* IO pressure */
-       fp = fopen(PSI_IO_SOME, "r");
+       fp = fopen(PSI_IO_PATH, "r");
        if (fp) {
                while (fgets(line, sizeof(line), fp)) {
                        if (strncmp(line, "some", 4) == 0) {
                                ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
                                                &psi.io_some_avg10, &psi.io_some_avg60,
                                                &psi.io_some_avg300, &psi.io_some_total);
-                               if (ret != 4)
+                               if (ret != 4) {
                                        fprintf(stderr, "Failed to parse IO some PSI data\n");
+                                       error_count++;
+                               }
                        } else if (strncmp(line, "full", 4) == 0) {
                                ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
                                                &psi.io_full_avg10, &psi.io_full_avg60,
                                                &psi.io_full_avg300, &psi.io_full_total);
-                               if (ret != 4)
+                               if (ret != 4) {
                                        fprintf(stderr, "Failed to parse IO full PSI data\n");
+                                       error_count++;
+                               }
                        }
                }
                fclose(fp);
+       } else {
+               fprintf(stderr, "Warning: Failed to open %s\n", PSI_IO_PATH);
+               error_count++;
        }
+
        /* IRQ pressure (only full) */
-       fp = fopen(PSI_IRQ_FULL, "r");
+       fp = fopen(PSI_IRQ_PATH, "r");
        if (fp) {
                while (fgets(line, sizeof(line), fp)) {
                        if (strncmp(line, "full", 4) == 0) {
                                ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
                                                &psi.irq_full_avg10, &psi.irq_full_avg60,
                                                &psi.irq_full_avg300, &psi.irq_full_total);
-                               if (ret != 4)
+                               if (ret != 4) {
                                        fprintf(stderr, "Failed to parse IRQ full PSI data\n");
+                                       error_count++;
+                               }
                        }
                }
                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)
@@ -820,7 +865,7 @@ static void get_container_stats(void)
 }
 
 /* Display results to stdout or log file */
-static void display_results(void)
+static void display_results(int psi_ret)
 {
        time_t now = time(NULL);
        struct tm *tm_now = localtime(&now);
@@ -833,49 +878,53 @@ static void display_results(void)
        suc &= BOOL_FPRINT(out, "\033[H\033[J");
 
        /* PSI output (one-line, no cat style) */
-       suc &= BOOL_FPRINT(out, "System Pressure Information: (avg10/avg60/avg300/total)\n");
-       suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
-               "CPU some:",
-               psi.cpu_some_avg10,
-               psi.cpu_some_avg60,
-               psi.cpu_some_avg300,
-               psi.cpu_some_total / 1000);
-       suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
-               "CPU full:",
-               psi.cpu_full_avg10,
-               psi.cpu_full_avg60,
-               psi.cpu_full_avg300,
-               psi.cpu_full_total / 1000);
-       suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
-               "Memory full:",
-               psi.memory_full_avg10,
-               psi.memory_full_avg60,
-               psi.memory_full_avg300,
-               psi.memory_full_total / 1000);
-       suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
-               "Memory some:",
-               psi.memory_some_avg10,
-               psi.memory_some_avg60,
-               psi.memory_some_avg300,
-               psi.memory_some_total / 1000);
-       suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
-               "IO full:",
-               psi.io_full_avg10,
-               psi.io_full_avg60,
-               psi.io_full_avg300,
-               psi.io_full_total / 1000);
-       suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
-               "IO some:",
-               psi.io_some_avg10,
-               psi.io_some_avg60,
-               psi.io_some_avg300,
-               psi.io_some_total / 1000);
-       suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
-               "IRQ full:",
-               psi.irq_full_avg10,
-               psi.irq_full_avg60,
-               psi.irq_full_avg300,
-               psi.irq_full_total / 1000);
+       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,
+                       "CPU some:",
+                       psi.cpu_some_avg10,
+                       psi.cpu_some_avg60,
+                       psi.cpu_some_avg300,
+                       psi.cpu_some_total / 1000);
+               suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+                       "CPU full:",
+                       psi.cpu_full_avg10,
+                       psi.cpu_full_avg60,
+                       psi.cpu_full_avg300,
+                       psi.cpu_full_total / 1000);
+               suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+                       "Memory full:",
+                       psi.memory_full_avg10,
+                       psi.memory_full_avg60,
+                       psi.memory_full_avg300,
+                       psi.memory_full_total / 1000);
+               suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+                       "Memory some:",
+                       psi.memory_some_avg10,
+                       psi.memory_some_avg60,
+                       psi.memory_some_avg300,
+                       psi.memory_some_total / 1000);
+               suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+                       "IO full:",
+                       psi.io_full_avg10,
+                       psi.io_full_avg60,
+                       psi.io_full_avg300,
+                       psi.io_full_total / 1000);
+               suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+                       "IO some:",
+                       psi.io_some_avg10,
+                       psi.io_some_avg60,
+                       psi.io_some_avg300,
+                       psi.io_some_total / 1000);
+               suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+                       "IRQ full:",
+                       psi.irq_full_avg10,
+                       psi.irq_full_avg60,
+                       psi.irq_full_avg300,
+                       psi.irq_full_total / 1000);
+       }
 
        if (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;
        int iterations = 0;
+       int psi_ret = 0;
        char keypress;
 
        /* Parse command line arguments */
@@ -1054,7 +1104,7 @@ int main(int argc, char **argv)
                }
 
                /* Read PSI statistics */
-               read_psi_stats();
+               psi_ret = read_psi_stats();
 
                /* Get container stats if container path provided */
                if (cfg.container_path)
@@ -1067,7 +1117,7 @@ int main(int argc, char **argv)
                sort_tasks();
 
                /* Display results to stdout or log file */
-               display_results();
+               display_results(psi_ret);
 
                /* Check for iterations */
                if (cfg.iterations > 0 && ++iterations >= cfg.iterations)