[CRIU] [PATCH] Add test case for code page sharing

Christopher Covington cov at codeaurora.org
Tue Mar 31 10:51:53 PDT 2015


We've observed at least one scenario where processes originally
sharing physical memory no longer do so after dump and restore.
This increases memory usage and degrades performance. Here is a
test case (created outside of the ZDTM framework for expedience)
that demonstrates the issue. The test fails with CRIU 1.4. Run
`make && ./test_sharing.sh` to build and run the test.

Acked-by: Aaron Lindsay <alindsay at qti.qualcomm.com>
Signed-off-by: Christopher Covington <cov at codeaurora.org>

Change-Id: If0cacb7ed8c12c7dee2dff7d6016fbddf1d13157
---
 test/code-sharing/Makefile        | 11 +++++
 test/code-sharing/test_sharing.c  | 90 +++++++++++++++++++++++++++++++++++++++
 test/code-sharing/test_sharing.sh | 63 +++++++++++++++++++++++++++
 3 files changed, 164 insertions(+)
 create mode 100644 test/code-sharing/Makefile
 create mode 100644 test/code-sharing/test_sharing.c
 create mode 100755 test/code-sharing/test_sharing.sh

diff --git a/test/code-sharing/Makefile b/test/code-sharing/Makefile
new file mode 100644
index 0000000..e30d6f3
--- /dev/null
+++ b/test/code-sharing/Makefile
@@ -0,0 +1,11 @@
+OBJS=test_sharing
+
+all: $(OBJS)
+.PHONY: all
+
+run: all
+	./test_sharing.sh
+
+clean:
+	rm -f $(OBJS) test-*.out
+.PHONY: clean
diff --git a/test/code-sharing/test_sharing.c b/test/code-sharing/test_sharing.c
new file mode 100644
index 0000000..43553e3
--- /dev/null
+++ b/test/code-sharing/test_sharing.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <signal.h>
+
+/*
+ * This binary sleeps continuously, but prints the current physical address for
+ * main() to a file (in the current directory, named like test-$pid.out) every
+ * time it receives SIGTERM.
+ */
+
+FILE *out;
+
+int main(int argc, char *argv);
+
+void error(char *error) {
+	fprintf(out, "ERROR %d: %s\n", errno, error);
+	printf("ERROR %d: %s\n", errno, error);
+	fflush(out);
+	exit(1);
+}
+
+void print_pa(int signal) {
+	int fd;
+	uint64_t entry;
+
+	//ensure main()'s page is present
+	fd = open("/proc/self/mem", O_RDONLY);
+	if (!fd)
+		error("Failed to open /proc/self/mem");
+	if (lseek(fd, (unsigned long) &main, SEEK_SET) == -1)
+		error("Failed to seek in /proc/self/mem");
+	if (read(fd, &entry, sizeof(entry)) != sizeof(entry))
+		error("Failed to read in /proc/self/mem");
+	close(fd);
+
+	//read PA for main()
+	fd = open("/proc/self/pagemap", O_RDONLY);
+	if (!fd)
+		error("Failed to open /proc/self/pagemap");
+	if (lseek64(fd, ((long long) &main / getpagesize()) * sizeof(entry), SEEK_SET) == -1)
+		error("Failed to seek in /proc/self/pagemap");
+	if (read(fd, &entry, sizeof(entry)) != sizeof(entry))
+		error("Failed to read in /proc/self/pagemap");
+	close(fd);
+
+	fprintf(out, "PA for main() in pid %d: 0x%" PRIx64 "\n", getpid(), entry & 0x3fffffffffffff);
+	fflush(out);
+}
+
+int main(int argc, char *argv) {
+	char out_filename[50];
+	struct sigaction sig = {
+		.sa_handler = print_pa
+	};
+
+	if (sprintf(out_filename, "test-%d.out", getpid()) < 0) {
+		printf("ERROR: Unable to write log filename\n");
+		return 1;
+	}
+	out = fopen(out_filename, "a");
+	if (!out) {
+		printf("ERROR: Unable to open log file\n");
+		return 1;
+	}
+
+	sigaction(SIGTERM, &sig, NULL);
+
+	while (1) {
+		sleep(1);
+	}
+}
diff --git a/test/code-sharing/test_sharing.sh b/test/code-sharing/test_sharing.sh
new file mode 100755
index 0000000..1c4233b
--- /dev/null
+++ b/test/code-sharing/test_sharing.sh
@@ -0,0 +1,63 @@
+# Copyright (c) 2015, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+set -ex
+
+if [[ -f ./test_sharing ]]; then
+  cp ./test_sharing /tmp/test_sharing
+elif [[ ! -f /tmp/test_sharing ]]; then
+  echo "ERROR: Please copy the test_sharing binary from test/code-sharing to" \
+    "/tmp/test_sharing if not running from the build directory"
+  exit 1
+fi
+chmod +x /tmp/test_sharing
+
+# Start pid0 (will never be criu dumped)
+cat /dev/null | setsid /tmp/test_sharing &> /dev/null &
+pid0=$!
+
+# Start pid1 (will be the first process criu dumped)
+cat /dev/null | setsid /tmp/test_sharing &> /dev/null &
+pid1=$!
+
+mkdir /tmp/criudump-$pid1
+criu dump -t $pid1 -v4 -o dump-$pid1.log -D /tmp/criudump-$pid1 || echo "Error: 'criu dump' exited with nonzero exit code!"
+
+# Start pid2 (will be the second process criu dumped)
+cat /dev/null | setsid /tmp/test_sharing &> /dev/null &
+pid2=$!
+
+mkdir /tmp/criudump-$pid2
+criu dump -t $pid2 -v4 -o dump-$pid2.log -D /tmp/criudump-$pid2 || echo "Error: 'criu dump' exited with nonzero exit code!"
+
+criu restore -v2 -d -R -D /tmp/criudump-$pid1
+criu restore -v2 -d -R -D /tmp/criudump-$pid2
+
+# Start pid3 (is not criu dumped)
+cat /dev/null | setsid /tmp/test_sharing &> /dev/null &
+pid3=$!
+
+sleep 1s #ensure pid3 is started before sending SIGTERM
+# Sent SIGTERM to cause all processes to write out the PA of main()
+kill -SIGTERM $pid0 $pid1 $pid2 $pid3
+sleep 1s
+
+set +x
+echo "pid0: $(cat test-$pid0.out)"
+echo "pid1: $(cat test-$pid1.out)"
+echo "pid2: $(cat test-$pid2.out)"
+echo "pid3: $(cat test-$pid3.out)"
+
+echo "We would expect that pid's 0, 1, 2, 3 would all have the same PA, as they" \
+  "would if they were not criu dumped (note that pids 0 and 3 share the same" \
+  "PA since they were not)."
+
+kill -SIGKILL $pid0 $pid1 $pid2 $pid3
-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



More information about the CRIU mailing list