[PATCH i-g-t 4/4] tools/displaytop: Add ftrace support to Display Top

Adith Narein T adith.narein.t at intel.com
Thu May 29 14:23:43 UTC 2025


This patch adds support for live tracing using ftrace in the DisplayTop
tool. It enables real-time monitoring with options for filtering, dumping,
and clearing the trace data.

Key features introduced:

- Live ftrace output visualization within the terminal UI
- Filter trace logs by register address for focused debugging
- Dump current trace buffer to a file for offline analysis
- Clear trace buffer on demand via the UI

Signed-off-by: Adith Narein T <adith.narein.t at intel.com>
---
 tools/displaytop/README.md                    |   2 +
 tools/displaytop/include/data.h               |   1 +
 tools/displaytop/include/display.h            |   5 +
 tools/displaytop/include/populate.h           |   1 +
 tools/displaytop/include/utils.h              |   4 +
 tools/displaytop/meson.build                  |   6 +
 tools/displaytop/src/display_dump_tracing.c   | 135 ++++++++
 tools/displaytop/src/display_filter_tracing.c | 318 ++++++++++++++++++
 tools/displaytop/src/display_ftrace.c         |  97 ++++++
 tools/displaytop/src/display_live_tracing.c   | 124 +++++++
 tools/displaytop/src/populate.c               |   1 +
 tools/displaytop/src/populate_ftrace.c        |  78 +++++
 tools/displaytop/src/utils_trace.c            |  67 ++++
 13 files changed, 839 insertions(+)
 create mode 100644 tools/displaytop/src/display_dump_tracing.c
 create mode 100644 tools/displaytop/src/display_filter_tracing.c
 create mode 100644 tools/displaytop/src/display_ftrace.c
 create mode 100644 tools/displaytop/src/display_live_tracing.c
 create mode 100644 tools/displaytop/src/populate_ftrace.c
 create mode 100644 tools/displaytop/src/utils_trace.c

diff --git a/tools/displaytop/README.md b/tools/displaytop/README.md
index 70563ad63..bda51b8c6 100644
--- a/tools/displaytop/README.md
+++ b/tools/displaytop/README.md
@@ -9,6 +9,8 @@ A terminal-based tool for monitoring and debugging the display pipeline.
 - Real-time display Configuration
 - view Live Display Debugfs in a terminal ui
 - Read & view DPCD register value & bitfield information
+- Formatted Live trace using Ftrace
+- filter the formatted ftrace by register address/range
 
 ---
 
diff --git a/tools/displaytop/include/data.h b/tools/displaytop/include/data.h
index f179fa374..f9b3e301c 100644
--- a/tools/displaytop/include/data.h
+++ b/tools/displaytop/include/data.h
@@ -48,5 +48,6 @@ typedef struct
 
 DP_mapping **get_dp_mapping_storage(void);
 int *get_dp_mapping_count_ptr(void);
+#define TRACE_PATH "/sys/kernel/debug/tracing/trace"
 
 #endif
\ No newline at end of file
diff --git a/tools/displaytop/include/display.h b/tools/displaytop/include/display.h
index b8f997c69..b3d457a25 100644
--- a/tools/displaytop/include/display.h
+++ b/tools/displaytop/include/display.h
@@ -45,5 +45,10 @@ void display_summary(WINDOW *pad, Node *node, int *content_line);
 
 void display_debugfs_file(WINDOW *pad, Node *node, int *content_line);
 void display_dpcd(WINDOW *pad, Node *node, int *content_line);
+void display_ftrace_options(WINDOW *pad, Node *node, int *content_line);
+void display_live_tracing(WINDOW *pad, Node *node, int *content_line);
+void display_dump_tracing(WINDOW *pad, Node *node, int *content_line);
+void display_filter_tracing(WINDOW *pad, Node *node, int *content_line);
+void display_clear_ftrace(WINDOW *pad, Node *node, int *content_line);
 
 #endif
\ No newline at end of file
diff --git a/tools/displaytop/include/populate.h b/tools/displaytop/include/populate.h
index b164f2f78..dc0cbc5b2 100644
--- a/tools/displaytop/include/populate.h
+++ b/tools/displaytop/include/populate.h
@@ -35,5 +35,6 @@ void populate_data(void);
 void initialize_display_config(void);
 void initialize_display_debugfs(void);
 void initialize_DPCD(void);
+void initialize_ftrace(void);
 
 #endif
\ No newline at end of file
diff --git a/tools/displaytop/include/utils.h b/tools/displaytop/include/utils.h
index 1e06100c5..f363ee4a6 100644
--- a/tools/displaytop/include/utils.h
+++ b/tools/displaytop/include/utils.h
@@ -118,5 +118,9 @@ char *find_debugfs_dir(void);
 int read_dpcd_registers(const char *aux_path, unsigned char *buffer, size_t size, uint64_t offset);
 
 uint64_t parse_hex_address(const char *hex_str);
+/* utils_trace.c */
+void free_cache(void);
+int clear_ftrace(void);
+void ensure_tracing_on(void);
 
 #endif
\ No newline at end of file
diff --git a/tools/displaytop/meson.build b/tools/displaytop/meson.build
index ecf661a85..f8ee1ae4d 100644
--- a/tools/displaytop/meson.build
+++ b/tools/displaytop/meson.build
@@ -65,6 +65,12 @@ if have_displaytop
     'src/display_DPCD.c',
     'src/populate_DPCD.c',
     'src/utils_registers.c',
+    'src/utils_trace.c',
+    'src/populate_ftrace.c',
+    'src/display_ftrace.c',
+    'src/display_live_tracing.c',
+    'src/display_dump_tracing.c',
+    'src/display_filter_tracing.c',
   )
 
   if meson.is_subproject()
diff --git a/tools/displaytop/src/display_dump_tracing.c b/tools/displaytop/src/display_dump_tracing.c
new file mode 100644
index 000000000..9e5ff6ecf
--- /dev/null
+++ b/tools/displaytop/src/display_dump_tracing.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright © 2025 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "display.h"
+#include "utils.h"
+
+void display_dump_tracing(WINDOW *pad, Node *node, int *content_line)
+{
+    int line = 0;
+    FILE *trace_fp = NULL, *dump_fp = NULL;
+    char buffer[512];
+    time_t now;
+    struct tm *t = NULL;
+    char dump_file_path[256];
+    int width, col_widths[6];
+    int total_count = 0;
+    WINDOW *progress_win = NULL;
+    size_t log_count = 0;
+    int current_count = 0;
+
+    now = time(NULL);
+    t = localtime(&now);
+    log_message(LOG_INFO, "Dumping trace logs for node: %s", node->name);
+    snprintf(dump_file_path, sizeof(dump_file_path), DUMP_DIR "/Ftrace_dump_");
+    strftime(dump_file_path + strlen(dump_file_path), sizeof(dump_file_path) - strlen(dump_file_path), "%Y-%m-%d-%H.%M.%S.txt", t);
+
+    ensure_tracing_on();
+    ensure_dump_directory();
+
+    trace_fp = fopen(TRACE_PATH, "r");
+    if (!trace_fp)
+    {
+        log_message(LOG_ERROR, "Error opening trace file: %s", strerror(errno));
+        *content_line = line;
+        return;
+    }
+
+    dump_fp = fopen(dump_file_path, "w");
+    if (!dump_fp)
+    {
+        log_message(LOG_ERROR, "Error creating dump file: %s", strerror(errno));
+        fclose(trace_fp);
+        *content_line = line;
+        return;
+    }
+    chmod(dump_file_path, 0777);
+
+    width = getmaxx(pad) - 8;
+
+    col_widths[0] = width * 0.10f;
+    col_widths[1] = width * 0.05f;
+    col_widths[2] = width * 0.10f;
+    col_widths[3] = width * 0.08f;
+    col_widths[4] = width * 0.10f;
+    col_widths[5] = width * 0.25f;
+
+    wclear(pad);
+    wattron(pad, A_BOLD);
+    mvwprintw(pad, line++, 1, "Ftrace Formatted & Dumped!");
+    wattroff(pad, A_BOLD);
+
+    while (fgets(buffer, sizeof(buffer), trace_fp) != NULL)
+    {
+        if (strstr(buffer, "i915_reg_rw") != NULL)
+            total_count++;
+    }
+    rewind(trace_fp);
+
+    progress_win = newwin(getmaxy(stdscr), getmaxx(stdscr), 0, 0);
+    wbkgd(progress_win, COLOR_PAIR(6));
+    wclear(progress_win);
+    box(progress_win, 0, 0);
+    print_bold_text(progress_win, 8, 2, "DUMPING IS IN PROGRESS :)");
+    wrefresh(progress_win);
+
+    while (fgets(buffer, sizeof(buffer), trace_fp) != NULL)
+    {
+        char process[32], op[8];
+        int pid, cpu, reg, val1, val2, len;
+        double timestamp;
+        char value_str[64];
+
+        if (strstr(buffer, "i915_reg_rw") == NULL)
+            continue;
+
+        if (sscanf(buffer, "%31[^-]-%d  [%d] %*s %lf: i915_reg_rw: %7s reg=0x%x, len=%d, val=(0x%x, 0x%x)",
+                   process, &pid, &cpu, &timestamp, op, &reg, &len, &val1, &val2) == 9)
+        {
+            strip_whitespace(process);
+            strip_whitespace(op);
+
+            snprintf(value_str, sizeof(value_str), "(0x%X, 0x%X)", val1, val2);
+
+            fprintf(dump_fp, "| %-*s | %-*d | %-*.6f | %-*s | 0x%-*X | %-*s |\n",
+                    col_widths[0], process,
+                    col_widths[1], cpu,
+                    col_widths[2], timestamp,
+                    col_widths[3], op,
+                    col_widths[4] - 2, reg,
+                    col_widths[5], value_str);
+
+            log_count++;
+            current_count++;
+            render_progress_bar(progress_win, log_count, total_count);
+        }
+    }
+
+    mvwprintw(pad, line + 2, 1, "Dump saved to: %s", dump_file_path);
+    *content_line = line;
+
+    fclose(trace_fp);
+    fclose(dump_fp);
+
+    delwin(progress_win);
+}
\ No newline at end of file
diff --git a/tools/displaytop/src/display_filter_tracing.c b/tools/displaytop/src/display_filter_tracing.c
new file mode 100644
index 000000000..66837457f
--- /dev/null
+++ b/tools/displaytop/src/display_filter_tracing.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright © 2025 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <form.h>
+
+#include "display.h"
+#include "utils.h"
+
+static char *get_range_input(void)
+{
+    int rows, cols;
+    WINDOW *overlay;
+    FIELD *fields[2];
+    FORM *form;
+    char *input_buffer;
+    int ch, pos;
+
+    rows = cols = 0;
+    overlay = NULL;
+    fields[0] = fields[1] = NULL;
+    form = NULL;
+    input_buffer = NULL;
+    ch = pos = 0;
+
+    wclear(stdscr);
+    wrefresh(stdscr);
+    getmaxyx(stdscr, rows, cols);
+    overlay = newwin(rows, cols, 0, 0);
+    wbkgd(overlay, COLOR_PAIR(6));
+    keypad(overlay, TRUE);
+    box(overlay, 0, 0);
+    wrefresh(overlay);
+
+    print_bold_text(overlay, 1, 1, "Trace Log Filtering - Instructions");
+    mvwprintw(overlay, 3, 2, "1. Enter a single register address (e.g., 0x40000)");
+    mvwprintw(overlay, 4, 2, "2. Enter an address range (e.g., 0x40000-0x40400)");
+    mvwprintw(overlay, 5, 2, "3. Press ENTER to apply filter, ESC to exit.");
+    mvwhline(overlay, 6, 1, 0, cols - 2);
+
+    fields[0] = new_field(1, cols - 4, 1, 1, 0, 0);
+    fields[1] = NULL;
+
+    set_field_back(fields[0], A_UNDERLINE);
+    field_opts_off(fields[0], O_AUTOSKIP);
+
+    form = new_form(fields);
+    set_form_win(form, overlay);
+    set_form_sub(form, derwin(overlay, 3, cols - 2, 7, 1));
+
+    wbkgd(form_sub(form), COLOR_PAIR(7));
+    box(form_sub(form), 0, 0);
+    post_form(form);
+    wrefresh(overlay);
+
+    input_buffer = malloc(256);
+    if (!input_buffer)
+    {
+        log_message(LOG_ERROR, "Memory allocation failed for input buffer");
+        return NULL;
+    }
+    memset(input_buffer, 0, 256);
+
+    pos = 0;
+
+    while ((ch = getch()) != 27)
+    {
+        switch (ch)
+        {
+        case KEY_BACKSPACE:
+        case 127:
+        case 8:
+            if (pos > 0)
+            {
+                pos--;
+                input_buffer[pos] = '\0';
+                form_driver(form, REQ_DEL_PREV);
+            }
+            break;
+        case '\n':
+            if (pos > 0)
+            {
+                unpost_form(form);
+                free_form(form);
+                free_field(fields[0]);
+                wclear(overlay);
+                wrefresh(overlay);
+                delwin(overlay);
+                return input_buffer;
+            }
+            break;
+        default:
+            if (pos < 255)
+            {
+                input_buffer[pos++] = ch;
+                input_buffer[pos] = '\0';
+                form_driver(form, ch);
+            }
+            break;
+        }
+        wrefresh(overlay);
+    }
+
+    if (form)
+        unpost_form(form), free_form(form);
+    if (fields[0])
+        free_field(fields[0]);
+    if (overlay)
+        wclear(overlay), wrefresh(overlay), delwin(overlay);
+    if (input_buffer)
+        free(input_buffer);
+
+    return NULL;
+}
+void display_filter_tracing(WINDOW *pad, Node *node, int *content_line)
+{
+    int line = 0;
+    char buffer[512];
+    size_t log_count = 0;
+    time_t now = time(NULL);
+    uint32_t start_addr = 0, end_addr = 0;
+    FILE *trace_fp = NULL;
+    FILE *dump_fp = NULL;
+    char dump_file_path[256];
+    char *input_buffer = NULL;
+    int width = getmaxx(pad) - 9;
+    int col_widths[6];
+    int total_count = 0;
+    int current_count = 0;
+    WINDOW *progress_win = NULL;
+    struct tm *t = NULL;
+
+    col_widths[0] = width * 0.12f;
+    col_widths[1] = width * 0.06f;
+    col_widths[2] = width * 0.13f;
+    col_widths[3] = width * 0.10f;
+    col_widths[4] = width * 0.15f;
+    col_widths[5] = width * 0.44f;
+
+    t = localtime(&now);
+    ensure_dump_directory();
+    strftime(dump_file_path, sizeof(dump_file_path), DUMP_DIR "/filtered_trace_dump_%Y-%m-%d_%H.%M.%S.txt", t);
+
+    *content_line = line;
+    line = 3;
+
+    ensure_tracing_on();
+
+    print_bold_text(pad, line++, 1, "%s", node->name);
+    line++;
+
+    input_buffer = get_range_input();
+    if (!input_buffer || strlen(input_buffer) == 0)
+    {
+        log_message(LOG_ERROR, "Failed to get range input");
+        free(input_buffer);
+        return;
+    }
+
+    if (strchr(input_buffer, '-') != NULL)
+    {
+        if (sscanf(input_buffer, "0x%x-0x%x", &start_addr, &end_addr) != 2)
+        {
+            print_bold_text(pad, line++, 2, "Error: Invalid address range! Please retry.");
+            free(input_buffer);
+            return;
+        }
+        if (start_addr > end_addr)
+        {
+            print_bold_text(pad, line++, 2, "Error: Invalid range! Please retry.");
+            free(input_buffer);
+            return;
+        }
+    }
+    else
+    {
+        if (sscanf(input_buffer, "0x%x", &start_addr) != 1)
+        {
+            print_bold_text(pad, line++, 2, "Error: Invalid address! Please retry.");
+            free(input_buffer);
+            return;
+        }
+        end_addr = start_addr;
+    }
+
+    trace_fp = fopen(TRACE_PATH, "r");
+    if (!trace_fp)
+    {
+        log_message(LOG_ERROR, "Error opening trace file: %s", strerror(errno));
+        goto cleanup;
+    }
+
+    dump_fp = fopen(dump_file_path, "w");
+    if (!dump_fp)
+    {
+        log_message(LOG_ERROR, "Error creating dump file: %s", strerror(errno));
+        goto cleanup;
+    }
+
+    wclear(pad);
+    wattron(pad, A_BOLD);
+    mvwprintw(pad, line++, 1, "| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s |",
+              col_widths[0], "Process",
+              col_widths[1], "CPU",
+              col_widths[2], "Timestamp",
+              col_widths[3], "R/W",
+              col_widths[4], "Reg",
+              col_widths[5], "Value");
+    wattroff(pad, A_BOLD);
+
+    while (fgets(buffer, sizeof(buffer), trace_fp) != NULL)
+    {
+        if (strstr(buffer, "i915_reg_rw") != NULL)
+            total_count++;
+    }
+    rewind(trace_fp);
+
+    progress_win = newwin(getmaxy(stdscr), getmaxx(stdscr), 0, 0);
+    wbkgd(progress_win, COLOR_PAIR(6));
+    wclear(progress_win);
+    box(progress_win, 0, 0);
+    print_bold_text(progress_win, 8, 2, "FILTERING IS IN PROGRESS :)");
+    wrefresh(progress_win);
+
+    while (fgets(buffer, sizeof(buffer), trace_fp) != NULL)
+    {
+        uint32_t reg;
+        double timestamp;
+        char value_str[64];
+        char process[32], op[8];
+        int pid, cpu, val1, val2, len;
+
+        if (strstr(buffer, "i915_reg_rw") == NULL)
+            continue;
+
+        if (sscanf(buffer, "%31[^-]-%d  [%d] %*s %lf: i915_reg_rw: %7s reg=0x%x, len=%d, val=(0x%x, 0x%x)",
+                   process, &pid, &cpu, &timestamp, op, &reg, &len, &val1, &val2) == 9)
+        {
+            strip_whitespace(process);
+            strip_whitespace(op);
+
+            snprintf(value_str, sizeof(value_str), "(0x%X, 0x%X)", val1, val2);
+
+            if (reg >= start_addr && reg <= end_addr)
+            {
+                log_count++;
+
+                mvwprintw(pad, line++, 1, "| %-*s | %-*d | %-*.2f | %-*s | 0x%-*X | %-*s |",
+                          col_widths[0], process,
+                          col_widths[1], cpu,
+                          col_widths[2], timestamp,
+                          col_widths[3], op,
+                          col_widths[4] - 2, reg,
+                          col_widths[5], value_str);
+
+                fprintf(dump_fp, "| %-*s | %-*d | %-*.2f | %-*s | 0x%-*X | %-*s |\n",
+                        col_widths[0], process,
+                        col_widths[1], cpu,
+                        col_widths[2], timestamp,
+                        col_widths[3], op,
+                        col_widths[4] - 2, reg,
+                        col_widths[5], value_str);
+            }
+
+            if (line >= getmaxy(pad) - 2)
+            {
+                wscrl(pad, 1);
+                line--;
+            }
+
+            current_count++;
+            render_progress_bar(progress_win, current_count, total_count);
+        }
+    }
+
+    wattron(pad, A_BOLD | COLOR_PAIR(2));
+    mvwprintw(pad, 1, 1, "Filtered range: 0x%X - 0x%X, Hits: %zu", start_addr, end_addr, log_count);
+    wattroff(pad, A_BOLD | COLOR_PAIR(2));
+
+    if (log_count == 0)
+    {
+        remove(dump_file_path);
+        mvwprintw(pad, line + 2, 1, "No matching logs found. Dump file not created.");
+    }
+    else
+    {
+        mvwprintw(pad, line + 2, 1, "Dump saved to: %s", dump_file_path);
+    }
+
+    *content_line = line;
+
+cleanup:
+    if (trace_fp)
+        fclose(trace_fp);
+    if (dump_fp)
+        fclose(dump_fp);
+    if (input_buffer)
+        free(input_buffer);
+}
diff --git a/tools/displaytop/src/display_ftrace.c b/tools/displaytop/src/display_ftrace.c
new file mode 100644
index 000000000..779f8b347
--- /dev/null
+++ b/tools/displaytop/src/display_ftrace.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2025 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "node.h"
+#include "utils.h"
+#include "display.h"
+
+void display_ftrace_options(WINDOW *pad, Node *node, int *content_line)
+{
+    int line = 0;
+    int size = getmaxx(pad) - 2;
+
+    print_bold_text(pad, line++, 1, "%s Menu", node->name);
+    line++;
+
+    print_bold_text(pad, line++, 1, "1. Live Tracing");
+    wattron(pad, A_DIM);
+    print_wrapped_text(pad, &line, 1, size, "Formats and displays the LAST 1000 lines of the ftrace logs, refresh (key r) to see the changes updated", false);
+    wattroff(pad, A_DIM);
+    line++;
+
+    print_bold_text(pad, line++, 1, "2. Dump Tracing");
+    wattron(pad, A_DIM);
+    print_wrapped_text(pad, &line, 1, size, "Formats and displays the FIRST 1000 lines but also dumps the entire formatted ", false);
+    wattroff(pad, A_DIM);
+    line++;
+
+    print_bold_text(pad, line++, 1, "3. Register Range Tracing");
+    wattron(pad, A_DIM);
+    print_wrapped_text(pad, &line, 1, size, "Filters & formats your desired register range, displays the first 1000 lines in Display Top. FILTERED RESULTS ARE DUMPED BY DEFAULT", false);
+    wattroff(pad, A_DIM);
+    line++;
+
+    print_bold_text(pad, line++, 1, "4. Clear Ftrace");
+    wattron(pad, A_DIM);
+    print_wrapped_text(pad, &line, 1, size, "Clears the ftrace buffer", false);
+    wattroff(pad, A_DIM);
+    line++;
+
+    *content_line = line;
+}
+
+/**
+ * @brief Clears the Ftrace buffer and updates the display with the result.
+ *
+ * This function is responsible for clearing the Ftrace buffer by calling
+ * the `clear_ftrace` function. It updates the provided `pad` window with
+ * messages indicating the success or failure of the operation. The number
+ * of lines written to the `pad` is updated in the `content_line` parameter.
+ *
+ * @param pad A pointer to the `WINDOW` object where the messages will be displayed.
+ * @param node A pointer to a `Node` object (currently unused in this function).
+ * @param content_line A pointer to an integer that will be updated with the
+ *                     number of lines written to the `pad`.
+ */
+void display_clear_ftrace(WINDOW *pad, Node *node, int *content_line)
+{
+    int line = 0;
+    int status;
+
+    print_bold_text(pad, line++, 1, "%s Menu", node->name);
+
+    line++;
+    status = clear_ftrace();
+    if (status == 0)
+    {
+        print_green_text(pad, line++, 2, "Ftrace cleared successfully.");
+    }
+    else
+    {
+        print_red_text(pad, line++, 2, "Failed to clear Ftrace.");
+    }
+    line++;
+
+    wrefresh(pad);
+    *content_line = line;
+}
\ No newline at end of file
diff --git a/tools/displaytop/src/display_live_tracing.c b/tools/displaytop/src/display_live_tracing.c
new file mode 100644
index 000000000..bd4b8ac5e
--- /dev/null
+++ b/tools/displaytop/src/display_live_tracing.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright © 2025 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "display.h"
+
+void display_live_tracing(WINDOW *pad, Node *node, int *content_line)
+{
+    int line = 0;
+    FILE *trace;
+    char buffer[256];
+    int width;
+    int col_widths[6];
+    char *log_lines[1000];
+    size_t log_count = 0;
+
+    print_bold_text(pad, line++, 1, "%s", node->name);
+    line++;
+
+    trace = popen("cat /sys/kernel/debug/tracing/trace", "r");
+    if (!trace)
+    {
+        log_message(LOG_ERROR, "Failed to open trace file: %s", strerror(errno));
+        *content_line = line;
+        return;
+    }
+
+    width = getmaxx(pad) - 2 - 6;
+
+    col_widths[0] = (int)(width * 0.10f) - 2;
+    col_widths[1] = (int)(width * 0.05f) - 2;
+    col_widths[2] = (int)(width * 0.12f) - 2;
+    col_widths[3] = (int)(width * 0.06f) - 2;
+    col_widths[4] = (int)(width * 0.10f) - 2;
+    col_widths[5] = (int)(width * 0.40f) - 2;
+
+    while (fgets(buffer, sizeof(buffer), trace) != NULL)
+    {
+        char process[32], op[8], value_str[64];
+        double timestamp;
+        int pid, cpu, reg, val1, val2, len;
+        char *log_line;
+
+        if (strstr(buffer, "i915_reg_rw") == NULL)
+            continue;
+
+        if (sscanf(buffer, "%31[^-]-%d  [%d] %*[^0-9] %lf: i915_reg_rw: %7s reg=0x%x, len=%d, val=(0x%x, 0x%x)",
+                   process, &pid, &cpu, &timestamp, op, &reg, &len, &val1, &val2) == 9)
+        {
+            strip_whitespace(process);
+            strip_whitespace(op);
+
+            snprintf(value_str, sizeof(value_str), "(0x%X, 0x%X)", val1, val2);
+
+            log_line = malloc(1024);
+            snprintf(log_line, 1024, "| %-*s | %-*d | %-*.6f | %-*s | 0x%-*X | %-*s |",
+                     col_widths[0], process,
+                     col_widths[1], cpu,
+                     col_widths[2], timestamp,
+                     col_widths[3], op,
+                     col_widths[4] - 2, reg,
+                     col_widths[5], value_str);
+
+            if (log_count < 1000)
+            {
+                log_lines[log_count++] = log_line;
+            }
+            else
+            {
+                free(log_lines[0]);
+                memmove(log_lines, log_lines + 1, (999) * sizeof(char *));
+                log_lines[999] = log_line;
+            }
+        }
+    }
+
+    wclear(pad);
+    line = 0;
+
+    wattron(pad, A_BOLD);
+    mvwprintw(pad, line++, 1, "| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s |",
+              col_widths[0], "Process",
+              col_widths[1], "CPU",
+              col_widths[2], "Timestamp",
+              col_widths[3], "Op",
+              col_widths[4], "Reg",
+              col_widths[5], "Value");
+    wattroff(pad, A_BOLD);
+
+    for (size_t i = 0; i < log_count; i++)
+    {
+        mvwprintw(pad, line++, 1, "%s", log_lines[i]);
+    }
+
+    wrefresh(pad);
+
+    for (size_t i = 0; i < log_count; i++)
+    {
+        free(log_lines[i]);
+    }
+
+    pclose(trace);
+
+    *content_line = line;
+}
\ No newline at end of file
diff --git a/tools/displaytop/src/populate.c b/tools/displaytop/src/populate.c
index 312ac0fd9..5a6607f71 100644
--- a/tools/displaytop/src/populate.c
+++ b/tools/displaytop/src/populate.c
@@ -31,4 +31,5 @@ void populate_data(void)
     initialize_display_config();
     initialize_display_debugfs();
     initialize_DPCD();
+    initialize_ftrace();
 }
diff --git a/tools/displaytop/src/populate_ftrace.c b/tools/displaytop/src/populate_ftrace.c
new file mode 100644
index 000000000..cd963d141
--- /dev/null
+++ b/tools/displaytop/src/populate_ftrace.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2025 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "data.h"
+#include "display.h"
+#include "populate.h"
+
+void initialize_ftrace(void)
+{
+    Node *ftrace;
+    Node *live_tracing;
+    Node *dump_tracing;
+    Node *filter_tracing;
+    Node *clear_ftrace;
+
+    ftrace = create_node("Ftrace", display_ftrace_options, root);
+    if (!ftrace)
+    {
+        log_message(LOG_ERROR, "Failed to create Ftrace node");
+        return;
+    }
+
+    live_tracing = create_node("Live Tracing", display_live_tracing, ftrace);
+    if (!live_tracing)
+    {
+        log_message(LOG_ERROR, "Failed to create Live Tracing node");
+        return;
+    }
+    add_child(ftrace, live_tracing);
+
+    dump_tracing = create_node("Dump Tracing", display_dump_tracing, ftrace);
+    if (!dump_tracing)
+    {
+        log_message(LOG_ERROR, "Failed to create Dump Tracing node");
+        return;
+    }
+    add_child(ftrace, dump_tracing);
+
+    filter_tracing = create_node("Filter Tracing", display_filter_tracing, ftrace);
+    if (!filter_tracing)
+    {
+        log_message(LOG_ERROR, "Failed to create Register Range Tracing node");
+        return;
+    }
+    add_child(ftrace, filter_tracing);
+
+    clear_ftrace = create_node("Clear Ftrace", display_clear_ftrace, ftrace);
+    if (!clear_ftrace)
+    {
+        log_message(LOG_ERROR, "Failed to create Clear Ftrace node");
+        return;
+    }
+    add_child(ftrace, clear_ftrace);
+
+    add_child(root, ftrace);
+
+    return;
+}
\ No newline at end of file
diff --git a/tools/displaytop/src/utils_trace.c b/tools/displaytop/src/utils_trace.c
new file mode 100644
index 000000000..a04f5e090
--- /dev/null
+++ b/tools/displaytop/src/utils_trace.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2025 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "utils.h"
+#include "display.h"
+
+void ensure_tracing_on(void)
+{
+    FILE *fp;
+
+    fp = fopen("/sys/kernel/debug/tracing/events/i915/i915_reg_rw/enable", "w");
+    if (fp == NULL || fprintf(fp, "1") < 0 || fclose(fp) != 0)
+    {
+        log_message(LOG_ERROR, "Error enabling i915_reg_rw event\n");
+    }
+
+    fp = fopen("/sys/kernel/debug/tracing/current_tracer", "w");
+    if (fp == NULL || fprintf(fp, "nop") < 0 || fclose(fp) != 0)
+    {
+        log_message(LOG_ERROR, "Error setting current tracer to nop\n");
+    }
+
+    fp = fopen("/sys/kernel/debug/tracing/tracing_on", "w");
+    if (fp == NULL || fprintf(fp, "1") < 0 || fclose(fp) != 0)
+    {
+        log_message(LOG_ERROR, "Error enabling tracing\n");
+    }
+
+    log_message(LOG_INFO, "Tracing enabled\n");
+}
+
+int clear_ftrace(void)
+{
+    FILE *fp;
+
+    fp = NULL;
+
+    fp = fopen(TRACE_PATH, "w");
+    if (fp == NULL || fprintf(fp, " ") < 0 || fclose(fp) != 0)
+    {
+        log_message(LOG_ERROR, "Error clearing trace\n");
+        return -1;
+    }
+
+    log_message(LOG_INFO, "Trace cleared\n");
+    return 0;
+}
\ No newline at end of file
-- 
2.43.0



More information about the igt-dev mailing list