Skip to content

Commit

Permalink
Don't dump pages which only contain zero bytes
Browse files Browse the repository at this point in the history
Signed-off-by: Volker Simonis <[email protected]>
  • Loading branch information
simonis committed Jan 15, 2024
1 parent cda1c5c commit 9bdc424
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 4 deletions.
1 change: 1 addition & 0 deletions criu/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd,
{ "ms", no_argument, 0, 1054 },
BOOL_OPT("track-mem", &opts.track_mem),
BOOL_OPT("auto-dedup", &opts.auto_dedup),
BOOL_OPT("zero-pages", &opts.zero_pages),
{ "libdir", required_argument, 0, 'L' },
{ "cpu-cap", optional_argument, 0, 1057 },
BOOL_OPT("force-irmap", &opts.force_irmap),
Expand Down
6 changes: 6 additions & 0 deletions criu/crtools.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,12 @@ int main(int argc, char *argv[], char *envp[])
" pages images of previous dump\n"
" when used on restore, as soon as page is restored, it\n"
" will be punched from the image\n"
" --zero-pages don't dump pages containing only zero bytes. This is a\n"
" potentially expensive operation because it checks for\n"
" every single process page if it contains only zeros but\n"
" it can significantly decrease the image size if many\n"
" such pages exist. It effectively replaces such pages\n"
" which the kernel's zero-page on restore.\n"
" --pre-dump-mode splice - parasite based pre-dumping (default)\n"
" read - process_vm_readv syscall based pre-dumping\n"
"\n"
Expand Down
1 change: 1 addition & 0 deletions criu/include/cr_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ struct cr_options {
int track_mem;
char *img_parent;
int auto_dedup;
int zero_pages;
unsigned int cpu_cap;
int force_irmap;
char **exec_cmd;
Expand Down
50 changes: 47 additions & 3 deletions criu/mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/prctl.h>
#include <sys/uio.h>

#include "types.h"
#include "cr_options.h"
Expand All @@ -31,6 +33,7 @@
#include "prctl.h"
#include "compel/infect-util.h"
#include "pidfd-store.h"
#include "xmalloc.h"

#include "protobuf.h"
#include "images/pagemap.pb-c.h"
Expand Down Expand Up @@ -172,17 +175,58 @@ static int generate_iovs(struct pstree_item *item, struct vma_area *vma, struct
unsigned long pages[3] = {};
int ret = 0;

static char *ZERO_PAGE = NULL;
static char *REMOTE_PAGE = NULL;
int zero = 0;
struct iovec local[2];
struct iovec remote[1];
int nread = 0;
if (opts.zero_pages && ZERO_PAGE == NULL) {
ZERO_PAGE = xmalloc(PAGE_SIZE);
REMOTE_PAGE = xmalloc(PAGE_SIZE);
if (ZERO_PAGE == NULL || REMOTE_PAGE == NULL) {
pr_warn("Can't allocate memory - disabling --zero-pages");
opts.zero_pages = 0;
} else {
memzero(ZERO_PAGE, PAGE_SIZE);
local[0].iov_base = REMOTE_PAGE;
local[0].iov_len = PAGE_SIZE;
remote[0].iov_base = (void *) 0x0;
remote[0].iov_len = PAGE_SIZE;
}
}

nr_to_scan = (vma_area_len(vma) - *off) / PAGE_SIZE;

for (pfn = 0; pfn < nr_to_scan; pfn++) {
unsigned long vaddr;
unsigned int ppb_flags = 0;
int st;

if (!should_dump_page(vma->e, at[pfn]))
continue;

vaddr = vma->e->start + *off + pfn * PAGE_SIZE;
/*
* If should_dump_page() returns true, it means the page is in the dumpees resident memory
* (i.e. bit 63 of the page frame number 'at[pfn]' is set) but it is not the zero-page.
*/
if (should_dump_page(vma->e, at[pfn])) {
if (opts.zero_pages) {
remote[0].iov_base = (void*)vaddr;
nread = process_vm_readv(item->pid->real, local, 1, remote, 1, 0);
if (nread == PAGE_SIZE) {
zero = memcmp(ZERO_PAGE, REMOTE_PAGE, PAGE_SIZE);
/*
* If the page contains just zeros we can treat it like the zero page and skip it.
* At restore it will be replaced by a reference to the zero page and COWed if accessed.
*/
if (zero == 0) {
pr_info("Zero page detected at virtual addr = %p\n", (void*)vaddr);
continue;
}
}
}
} else {
continue;
}

if (vma_entry_can_be_lazy(vma->e) && !is_stack(item, vaddr))
ppb_flags |= PPB_LAZY;
Expand Down
1 change: 1 addition & 0 deletions test/javaTests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<!-- Suite testng xml file to consider for test execution -->
<suiteXmlFiles>
<suiteXmlFile>test.xml</suiteXmlFile>
<suiteXmlFile>test-zero.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public void runtest(String testName, String checkpointOpt, String restoreOpt) th
String pid;
int exitCode;

System.out.println("======= Testing " + testName + " ========");
System.out.println("======= Testing " + testName + " " + checkpointOpt + " ========");

testSetup(testName);

Expand Down
89 changes: 89 additions & 0 deletions test/javaTests/test-zero.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name = "Suite2">
<parameter name="checkpointOpt" value="--zero-pages"/>
<parameter name="restoreOpt" value=""/>

<test name = "test1-FileRead">
<parameter name="testname" value="FileRead"/>
<classes>
<class name = "org.criu.java.tests.CheckpointRestore"/>
</classes>
</test>

<test name = "test2-ReadWrite">
<parameter name="testname" value="ReadWrite"/>
<classes>
<class name = "org.criu.java.tests.CheckpointRestore"/>
</classes>
</test>

<test name = "test3-MemoryMappings">
<parameter name="testname" value="MemoryMappings"/>
<classes>
<class name = "org.criu.java.tests.CheckpointRestore"/>
</classes>
</test>

<test name = "test4-MultipleFileRead">
<parameter name="testname" value="MultipleFileRead"/>
<classes>
<class name = "org.criu.java.tests.CheckpointRestore"/>
</classes>
</test>

<test name = "test5-MultipleFileWrite">
<parameter name="testname" value="MultipleFileWrite"/>
<classes>
<class name = "org.criu.java.tests.CheckpointRestore"/>
</classes>
</test>

<test name = "test6-Sockets">
<parameter name="testname" value="Sockets"/>
<parameter name="checkpointOpt" value="--tcp-established --zero-pages"/>
<parameter name="restoreOpt" value="--tcp-established"/>
<classes>
<class name = "org.criu.java.tests.CheckpointRestore"/>
</classes>
</test>

<test name = "test7-SocketsListen">
<parameter name="testname" value="SocketsListen"/>
<parameter name="checkpointOpt" value="--tcp-established --zero-pages"/>
<parameter name="restoreOpt" value="--tcp-established"/>
<classes>
<class name = "org.criu.java.tests.CheckpointRestore"/>
</classes>
</test>

<test name = "test8-SocketsConnect">
<parameter name="testname" value="SocketsConnect"/>
<parameter name="checkpointOpt" value="--tcp-established --zero-pages"/>
<parameter name="restoreOpt" value="--tcp-established"/>
<classes>
<class name = "org.criu.java.tests.CheckpointRestore"/>
</classes>
</test>

<test name = "test9-SocketsMultiple">
<parameter name="testname" value="SocketsMultiple"/>
<parameter name="checkpointOpt" value="--tcp-established --zero-pages"/>
<parameter name="restoreOpt" value="--tcp-established"/>
<classes>
<class name = "org.criu.java.tests.CheckpointRestore"/>
</classes>
</test>

<test name = "test10-SocketsData">
<parameter name="testname" value="SocketsData"/>
<parameter name="checkpointOpt" value="--tcp-established --zero-pages"/>
<parameter name="restoreOpt" value="--tcp-established"/>
<classes>
<class name = "org.criu.java.tests.CheckpointRestore"/>
</classes>

</test>

</suite>

0 comments on commit 9bdc424

Please sign in to comment.