[PATCH] lib/amd: add memleak functions
vitaly.prosyak at amd.com
vitaly.prosyak at amd.com
Tue Feb 18 11:43:41 UTC 2025
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) {
+ 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