diff mbox

lib/igt_core.c: disable lowmemorykiller during tests

Message ID 1412166320-12775-1-git-send-email-tim.gore@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

tim.gore@intel.com Oct. 1, 2014, 12:25 p.m. UTC
From: Tim Gore <tim.gore@intel.com>

Several IGT tests cycle through a lot of GEM memory and
when running these tests on Android they tend to get
killed by the lowmemorykiller. The lowmemorykiller really
is not usefull in this context and is just preventing the
test from doing its job. This commit adds a function to
disable the lowmemorykiller by writing "9999" to its
oom adj parameter, which means it will never "select"
any process to kill. The normal linux oom killer is still
there to protect the kernel.
The low memory killer is disabled during the common
init function and then re-enabled by the exit handler.
To make this work for single tests the exit handler is now
installed in the common init function also so that it is
invoked for all tests.
This is just a hack to get round the fact that the i915
driver uses the concept of purgeable memory which is not
understood by the lowmemorykiller. If this ever gets
fixed then this patch can be removed.

Signed-off-by: Tim Gore <tim.gore@intel.com>
---
 lib/igt_core.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 81 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/lib/igt_core.c b/lib/igt_core.c
index 0269462..f07ca3b 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -292,6 +292,9 @@  void __igt_fixture_end(void)
 bool igt_exit_called;
 static void check_igt_exit(int sig)
 {
+	/* make sure the lowmemorykiller gets re-enabled if required */
+	low_mem_killer_disable(false);
+
 	/* When not killed by a signal check that igt_exit() has been properly
 	 * called. */
 	assert(sig != 0 || igt_exit_called);
@@ -326,6 +329,77 @@  static void print_usage(const char *help_str, bool output_on_stderr)
 		fprintf(f, "%s\n", help_str);
 }
 
+
+/* Some of the IGT tests put quite a lot of pressure on memory and when
+ * running on Android they are sometimes killed by the Android low memory killer.
+ * This seems to be due to some incompatibility between the kswapd free memory
+ * targets and the way the lowmemorykiller assesses free memory.
+ * The low memory killer really isn't usefull in this context and has no
+ * interaction with the gpu driver that we are testing, so the following
+ * function is used to disable it by modifying one of its module parameters.
+ * We still have the normal linux oom killer to protect the kernel.
+ * Apparently it is also possible for the lowmemorykiller to get included
+ * in some linux distributions; so rather than check for Android we directly
+ * check for the existence of the module parameter we want to adjust.
+ *
+ * In future, if we can get the lowmemorykiller to play nicely then we can
+ * remove this hack.
+ */
+void low_mem_killer_disable(bool disable)
+{
+	static const char* adj_fname="/sys/module/lowmemorykiller/parameters/adj";
+	static const char no_lowmem_killer[] = "9999";
+	int fd;
+	struct stat buf;
+	/* The following must persist across invocations */
+	static char prev_adj_scores[256];
+	static int adj_scores_len = 0;
+	static bool is_disabled = false;
+
+	/* check to see if there is something to do */
+	if (!(disable ^ is_disabled))
+		return;
+
+	/* capture the permissions bits for the lowmemkiller adj pseudo-file.
+	   Bail out if the stat fails; it probably means that there is no
+	   lowmemorykiller, but in any case we're doomed. */
+	if (stat (adj_fname, &buf))
+	{
+		igt_assert(errno == ENOENT);
+		return;
+	}
+	/* make sure the file can be read/written - by default it is write-only */
+	chmod (adj_fname, S_IRUSR | S_IWUSR);
+
+	if (disable)
+	{
+		/* read the current oom adj parameters for lowmemorykiller */
+		fd = open(adj_fname, O_RDWR);
+		igt_assert(fd != -1);
+		adj_scores_len = read(fd, (void*)prev_adj_scores, 255);
+		igt_assert(adj_scores_len > 0);
+
+		/* writing 9999 to this module parameter effectively diables the
+		 * low memory killer. This is not a real file, so we dont need to
+		 * seek to the start or truncate it */
+		write(fd, no_lowmem_killer, sizeof(no_lowmem_killer));
+		close(fd);
+		is_disabled = true;
+	}
+	else
+	{
+		/* just re-enstate the original settings */
+		fd = open(adj_fname, O_WRONLY);
+		igt_assert(fd != -1);
+		write(fd, prev_adj_scores, adj_scores_len);
+		close(fd);
+		is_disabled = false;
+	}
+
+	/* re-enstate the file permissions */
+	chmod (adj_fname, buf.st_mode);
+}
+
 static void oom_adjust_for_doom(void)
 {
 	int fd;
@@ -334,6 +408,11 @@  static void oom_adjust_for_doom(void)
 	fd = open("/proc/self/oom_score_adj", O_WRONLY);
 	igt_assert(fd != -1);
 	igt_assert(write(fd, always_kill, sizeof(always_kill)) == sizeof(always_kill));
+	close(fd);
+
+	/* disable the low memory killer (not oom) if present */
+	/* It can kill some tests that cycle through a lot of memory */
+	low_mem_killer_disable(true);
 }
 
 static int common_init(int argc, char **argv,
@@ -484,6 +563,8 @@  out:
 		oom_adjust_for_doom();
 	}
 
+	/* install exit handler, to ensure we clean up */
+	igt_install_exit_handler(check_igt_exit);
 	return ret;
 }
 
@@ -518,7 +599,6 @@  int igt_subtest_init_parse_opts(int argc, char **argv,
 	test_with_subtests = true;
 	ret = common_init(argc, argv, extra_short_opts, extra_long_opts,
 			  help_str, extra_opt_handler);
-	igt_install_exit_handler(check_igt_exit);
 
 	return ret;
 }