[CRIU] [RFC 2/2] mem: Start using pagemap cache

Cyrill Gorcunov gorcunov at openvz.org
Thu Feb 13 01:26:14 PST 2014


With use of ppagemap cache I notice significant improvement
in speed of dumping procedure. Here are results for a custom
program which creates 1024 small VMAs (each 40K length) and
a standart mmaps00 test case. Sure for standart test case the
results are not that impressive but still it's faster.

  | Big number of small VMAs
  | ------------------------
  |
  | dump: {			standart
  | 	freezing_time: 438
  | 	frozen_time: 60099
  | 	memdump_time: 9094
  | 	memwrite_time: 789
  | 	pages_scanned: 13487
  | 	pages_skipped_parent: 0
  | 	pages_written: 62
  | 	irmap_resolve: 0
  | }
  |
  | dump: {			pagecache
  | 	freezing_time: 202
  | 	frozen_time: 40514
  | 	memdump_time: 3357
  | 	memwrite_time: 645
  | 	pages_scanned: 13487
  | 	pages_skipped_parent: 0
  | 	pages_written: 62
  | 	irmap_resolve: 0
  | }
  |
  | Regular maps00 test
  | -------------------
  |
  | dump: {			standart
  | 	freezing_time: 106
  | 	frozen_time: 12745
  | 	memdump_time: 262
  | 	memwrite_time: 147
  | 	pages_scanned: 1094
  | 	pages_skipped_parent: 0
  | 	pages_written: 32
  | 	irmap_resolve: 0
  | }
  |
  | dump: {			pagecache
  | 	freezing_time: 79
  | 	frozen_time: 9050
  | 	memdump_time: 229
  | 	memwrite_time: 138
  | 	pages_scanned: 1094
  | 	pages_skipped_parent: 0
  | 	pages_written: 32
  | 	irmap_resolve: 0
  | }

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 mem.c | 64 +++++++++++++++++++++++++++++-----------------------------------
 1 file changed, 29 insertions(+), 35 deletions(-)

diff --git a/mem.c b/mem.c
index 65a1b7a7d337..3c0458c5d145 100644
--- a/mem.c
+++ b/mem.c
@@ -19,6 +19,7 @@
 #include "pstree.h"
 #include "restorer.h"
 #include "files-reg.h"
+#include "pagemap-cache.h"
 
 #include "protobuf.h"
 #include "protobuf/pagemap.pb-c.h"
@@ -105,29 +106,29 @@ static inline bool page_in_parent(u64 pme)
  * the memory contents is present in the pagent image set.
  */
 
-static int generate_iovs(struct vma_area *vma, int pagemap,
-			 struct page_pipe *pp, u64 *map, u64 *off)
+static int generate_iovs(pmc_t *pmc, struct vma_area *vma,
+			 unsigned long *last_vaddr,
+			 struct page_pipe *pp)
 {
-	unsigned long pfn, nr_to_scan;
+	unsigned long vaddr = *last_vaddr;
+	unsigned long nr_to_scan;
 	unsigned long pages[2] = {};
-	u64 from, len;
+	u64 pme;
 
-	nr_to_scan = (vma_area_len(vma) - *off) / PAGE_SIZE;
-	from = (vma->e->start + *off) / PAGE_SIZE * sizeof(*map);
-	len = nr_to_scan * sizeof(*map);
-	if (pread(pagemap, map, len, from) != len) {
-		pr_perror("Can't read pagemap file");
-		return -1;
-	}
+	nr_to_scan = PAGEMAP_PFN(vma->e->end - vaddr);
 
-	for (pfn = 0; pfn < nr_to_scan; pfn++) {
-		unsigned long vaddr;
+	for (; vaddr < vma->e->end; vaddr += PAGE_SIZE) {
 		int ret;
 
-		if (!should_dump_page(vma->e, map[pfn]))
-			continue;
+		pme = pmc_get_pme(pmc, vaddr);
+		if (pme == PAGEMAP_PME_ERR) {
+			pr_err("Failed obtain PME for %p\n", (void *)vaddr);
+			*last_vaddr = vaddr;
+			return -1;
+		}
 
-		vaddr = vma->e->start + *off + pfn * PAGE_SIZE;
+		if (!should_dump_page(vma->e, pme))
+			continue;
 
 		/*
 		 * If we're doing incremental dump (parent images
@@ -136,7 +137,7 @@ static int generate_iovs(struct vma_area *vma, int pagemap,
 		 * page. The latter would be checked in page-xfer.
 		 */
 
-		if (page_in_parent(map[pfn])) {
+		if (page_in_parent(pme)) {
 			ret = page_pipe_add_hole(pp, vaddr);
 			pages[0]++;
 		} else {
@@ -145,12 +146,12 @@ static int generate_iovs(struct vma_area *vma, int pagemap,
 		}
 
 		if (ret) {
-			*off += (pfn - 1) * PAGE_SIZE;
+			*last_vaddr = vaddr - PAGE_SIZE;
 			return ret;
 		}
 	}
 
-	*off += pfn * PAGE_SIZE;
+	*last_vaddr = vaddr;
 
 	cnt_add(CNT_PAGES_SCANNED, nr_to_scan);
 	cnt_add(CNT_PAGES_SKIPPED_PARENT, pages[0]);
@@ -236,13 +237,13 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
 		struct vm_area_list *vma_area_list,
 		struct page_pipe **pp_ret)
 {
-	u64 *map;
-	int pagemap;
 	struct page_pipe *pp;
 	struct vma_area *vma_area;
 	struct page_xfer xfer;
 	int ret = -1;
 
+	pmc_t pmc;
+
 	pr_info("\n");
 	pr_info("Dumping pages (type: %d pid: %d)\n", CR_FD_PAGES, ctl->pid.real);
 	pr_info("----------------------------------------\n");
@@ -254,23 +255,19 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
 	pr_debug("   Private vmas %lu/%lu pages\n",
 			vma_area_list->longest, vma_area_list->priv_size);
 
+
 	/*
 	 * Step 0 -- prepare
 	 */
 
-	map = xmalloc(vma_area_list->longest * sizeof(*map));
-	if (!map)
-		goto out;
-
-	ret = pagemap = open_proc(ctl->pid.real, "pagemap");
-	if (ret < 0)
-		goto out_free;
+	if (pmc_init(&pmc, ctl->pid.real, &vma_area_list->h))
+		return -1;
 
 	ret = -1;
 	pp = create_page_pipe(vma_area_list->priv_size / 2,
 				pargs_iovs(args), pp_ret == NULL);
 	if (!pp)
-		goto out_close;
+		goto out;
 
 	if (pp_ret == NULL) {
 		ret = open_page_xfer(&xfer, CR_FD_PAGEMAP, ctl->pid.virt);
@@ -283,12 +280,12 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
 	 */
 	args->off = 0;
 	list_for_each_entry(vma_area, &vma_area_list->h, list) {
-		u64 off = 0;
+		unsigned long last_vaddr = vma_area->e->start;
 
 		if (!privately_dump_vma(vma_area))
 			continue;
 again:
-		ret = generate_iovs(vma_area, pagemap, pp, map, &off);
+		ret = generate_iovs(&pmc, vma_area, &last_vaddr, pp);
 		if (ret == -EAGAIN) {
 			BUG_ON(pp_ret);
 
@@ -322,11 +319,8 @@ out_xfer:
 out_pp:
 	if (ret || !pp_ret)
 		destroy_page_pipe(pp);
-out_close:
-	close(pagemap);
-out_free:
-	xfree(map);
 out:
+	pmc_fini(&pmc);
 	pr_info("----------------------------------------\n");
 	return ret;
 }
-- 
1.8.3.1



More information about the CRIU mailing list