[PATCH] lib/amd: add memleak functions

Zhang, Jesse(Jie) Jesse.Zhang at amd.com
Wed Feb 19 01:16:40 UTC 2025


[AMD Official Use Only - AMD Internal Distribution Only]

Hi Vitaly,

-----Original Message-----
From: vitaly.prosyak at amd.com <vitaly.prosyak at amd.com>
Sent: Tuesday, February 18, 2025 7:44 PM
To: igt-dev at lists.freedesktop.org
Cc: Prosyak, Vitaly <Vitaly.Prosyak at amd.com>; Koenig, Christian <Christian.Koenig at amd.com>; Deucher, Alexander <Alexander.Deucher at amd.com>; Zhang, Jesse(Jie) <Jesse.Zhang at amd.com>; Wentland, Harry <Harry.Wentland at amd.com>
Subject: [PATCH] lib/amd: add memleak functions

From: Vitaly Prosyak <vitaly.prosyak at amd.com>

refactor memory leak functions and add
them to the library for reuse across different tests.

Cc: Christian Koenig <christian.koenig at amd.com>
Cc: Alexander Deucher <alexander.deucher at amd.com>
Cc: Jesse Zhang <jesse.zhang at amd.com>
Cc: Harry Wentland <harry.wentland at amd.com>

Signed-off-by: Vitaly Prosyak <vitaly.prosyak at amd.com>
---
 lib/amdgpu/amd_mem_leak.c   | 112 ++++++++++++++++++++++++++++++++++++
 lib/amdgpu/amd_mem_leak.h   |  17 ++++++
 lib/meson.build             |   1 +
 tests/amdgpu/amd_mem_leak.c |  88 ++--------------------------
 4 files changed, 135 insertions(+), 83 deletions(-)  create mode 100644 lib/amdgpu/amd_mem_leak.c  create mode 100644 lib/amdgpu/amd_mem_leak.h

diff --git a/lib/amdgpu/amd_mem_leak.c b/lib/amdgpu/amd_mem_leak.c new file mode 100644 index 000000000..a367b4eab
--- /dev/null
+++ b/lib/amdgpu/amd_mem_leak.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ */
+
+#include <fcntl.h>
+#include "igt.h"
+#include "amd_mem_leak.h"
+
+
+enum mem_leak_cmd {
+       CMD_SCAN = 0, /* as index */
+       CMD_CLEAR = 1,
+       CMD_MAX,
+};
+
+/* return non zero fp write successfully or null if failure */ static
+FILE *mem_leak_cmd(enum mem_leak_cmd cmd) {
+       const struct mem_leak_cmd_arr {
+               const char *str_cmd;
+               enum mem_leak_cmd cmd;
+       } memleak_arr[] = {
+               {"scan",        CMD_SCAN        },
+               {"clear",       CMD_CLEAR       },
+               {"",            CMD_MAX         },
+               {NULL, 0}
+       };
+
+       FILE *fp;
+       int len;
+
+       fp = fopen("/sys/kernel/debug/kmemleak", "r+");
+       if (fp) {
+               len = strlen(memleak_arr[cmd].str_cmd);
+               if (fwrite(memleak_arr[cmd].str_cmd, 1, len, fp) != len) {
+                       fclose(fp);
+                       fp = NULL;
+               }
+       }
+
+       return fp;
+}
+
+/* return True if scan successfully written to kmemleak */ static bool
+send_scan_memleak(void) {
+       FILE *fp;
+
+       fp = mem_leak_cmd(CMD_SCAN);
+       if (fp != NULL) {
+               fclose(fp);
+               return true;
+       }
+       return false;
+}
+
+/* return True if clear successfully sent to kmemleak */ static bool
+send_clear_memleak(void) {
+       FILE *fp;
+
+       fp = mem_leak_cmd(CMD_CLEAR);
+       if (fp != NULL) {
+               fclose(fp);
+               return true;
+       }
+       return false;
+}
+
+/* return true if kmemleak is enabled and then clear earlier leak
+records */ bool clear_memleak(bool is_more_than_one) {
+       if (!send_scan_memleak() || !send_clear_memleak())
+               return false;
+
+       if (is_more_than_one == true) {
Maybe we can use if (is_more_than_one) directly,
Except that,  it is good for me:
Reviewed-by: "Jesse.zhang at amd.com"

+               if (!send_scan_memleak() || !send_clear_memleak())
+                       return false;
+       }
+
+       return true;
+}
+
+/* return true if kmemleak did not pick up any memory leaks */ bool
+is_no_memleak(void) {
+       FILE *fp;
+       const char *buf[1];
+       char read_buf[1024];
+
+       fp = mem_leak_cmd(CMD_SCAN);
+       if (fp != NULL) {
+               /* read back to see if any leak */
+               if (fread(buf, 1, 1, fp) == 0) {
+                       fclose(fp);
+                       return true;
+               }
+       }
+
+       /* Dump contents of kmemleak */
+       fseek(fp, 0L, SEEK_SET);
+       while (fgets(read_buf, sizeof(read_buf) - 1, fp) != NULL)
+               igt_info("MEM_LEAK: %s", read_buf);
+
+       fclose(fp);
+       return false;
+}
diff --git a/lib/amdgpu/amd_mem_leak.h b/lib/amdgpu/amd_mem_leak.h new file mode 100644 index 000000000..5de4045a9
--- /dev/null
+++ b/lib/amdgpu/amd_mem_leak.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: MIT
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ */
+#ifndef AMD_MEM_LEAK_H
+#define AMD_MEM_LEAK_H
+
+#include <stdio.h>
+#include <amdgpu.h>
+#include "amd_ip_blocks.h"
+
+/* return true if kmemleak is enabled and then clear earlier leak
+records */ bool clear_memleak(bool is_more_than_one);
+
+/* return true if kmemleak did not pick up any memory leaks */ bool
+is_no_memleak(void);
+
+#endif
diff --git a/lib/meson.build b/lib/meson.build index 9fffdd3c6..d01c90df9 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -164,6 +164,7 @@ if libdrm_amdgpu.found()
                'amdgpu/amd_shared_process.c',
                'amdgpu/xalloc.h',
                'amdgpu/amd_cp_dma.c',
+               'amdgpu/amd_mem_leak.c',
                'amdgpu/amd_mmd_shared.c'
        ]
        if libdrm_amdgpu.version().version_compare('> 2.4.99') diff --git a/tests/amdgpu/amd_mem_leak.c b/tests/amdgpu/amd_mem_leak.c index e4a4b5c47..74f887bf9 100644
--- a/tests/amdgpu/amd_mem_leak.c
+++ b/tests/amdgpu/amd_mem_leak.c
@@ -23,6 +23,7 @@
 #include "igt.h"
 #include "igt_amd.h"
 #include <fcntl.h>
+#include "lib/amdgpu/amd_mem_leak.h"

 IGT_TEST_DESCRIPTION("Test checking memory leaks with suspend-resume and connector hotplug");

@@ -78,85 +79,6 @@ static void test_fini(data_t *data)
        igt_display_reset(&data->display);
 }

-/* return True if scan successfully written to kmemleak */ -static bool send_scan_memleak(void) -{
-       FILE *fp;
-       const char *cmd = "scan";
-
-       fp = fopen("/sys/kernel/debug/kmemleak", "r+");
-       if (!fp) return false;
-
-       if(fwrite(cmd, 1, strlen(cmd), fp) != strlen(cmd))  {
-               fclose(fp);
-               return false;
-       }
-       fclose(fp);
-       return true;
-}
-
-/* return True if clear successfully sent to kmemleak */ -static bool send_clear_memleak(void) -{
-       FILE *fp;
-       const char *cmd = "clear";
-
-       fp = fopen("/sys/kernel/debug/kmemleak", "r+");
-       if (!fp) return false;
-
-       if(fwrite(cmd, 1, strlen(cmd), fp) != strlen(cmd))  {
-               fclose(fp);
-               return false;
-       }
-       fclose(fp);
-       return true;
-}
-
-/* return true if kmemleak is enabled and then clear earlier leak records */ -static bool clear_memleak(data_t *data) -{
-       /* Need to scan + clear twice to properly clear buffer or else leaks
-        * from modprobe or other tests may appear
-        */
-       if (!send_scan_memleak() | !send_clear_memleak())
-               return false;
-       if (!send_scan_memleak() | !send_clear_memleak())
-               return false;
-
-       return true;
-}
-
-/* return true if kmemleak did not pick up any memory leaks */ -static bool check_memleak(data_t *data) -{
-       FILE *fp;
-       const char *buf[1];
-       const char *cmd = "scan";
-       char read_buf[1024];
-
-       fp = fopen("/sys/kernel/debug/kmemleak", "r+");
-       igt_assert_f(fp, "cannot open /sys/kernel/debug/kmemleak for reading\n");
-
-       /* trigger an immediate scan on memory leak */
-       igt_assert_f(fwrite(cmd, 1, strlen(cmd), fp) == strlen(cmd),
-                       "fail to trigger a scan for memory leak\n");
-
-       /* read back to see if any leak */
-       if (fread(buf, 1, 1, fp) == 0) {
-               fclose(fp);
-               return true;
-       }
-
-       /* Dump contents of kmemleak */
-       fseek(fp, 0L, SEEK_SET);
-       while (fgets(read_buf, sizeof(read_buf), fp) != NULL) {
-               igt_info("%s", read_buf);
-       }
-
-       fclose(fp);
-       return false;
-}
-
 static void test_suspend_resume(data_t *data)  {
        igt_display_t *display = &data->display; @@ -164,7 +86,7 @@ static void test_suspend_resume(data_t *data)

        test_init(data);

-       if(!clear_memleak(data)) {
+       if(!clear_memleak(true)) {
                igt_skip("kmemleak is not enabled for this kernel\n");
        }

@@ -174,7 +96,7 @@ static void test_suspend_resume(data_t *data)

        igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE);

-       igt_assert_f(check_memleak(data), "memory leak detected\n");
+       igt_assert_f(is_no_memleak(), "memory leak detected\n");

        igt_remove_fb(data->fd, &rfb);
        test_fini(data);
@@ -189,7 +111,7 @@ static void test_hotplug(data_t *data)

        igt_amd_require_hpd(&data->display, data->fd);

-       if(!clear_memleak(data)) {
+       if(!clear_memleak(true)) {
                igt_skip("kmemleak is not enabled for this kernel\n");
        }

@@ -199,7 +121,7 @@ static void test_hotplug(data_t *data)

        igt_amd_trigger_hotplug(data->fd, data->output->name);

-       igt_assert_f(check_memleak(data), "memory leak detected\n");
+       igt_assert_f(is_no_memleak(), "memory leak detected\n");

        igt_remove_fb(data->fd, &rfb);
        test_fini(data);
--
2.34.1



More information about the igt-dev mailing list