[CRIU] [PATCH v3 6/6] log_dirty: count dirty pages for one pid in pagemap
Pavel Tikhomirov
ptikhomirov at virtuozzo.com
Fri May 27 03:01:39 PDT 2016
read lines from /proc/<pid>/maps and for each memory region
check PME_SOFT_DIRTY for every page using /proc/<pid>/pagemap
and summup pages and dirty pages.
v3: fix print format for uint64_t
https://travis-ci.org/criupatchwork/criu/builds/133319285
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
criu/dirty-logger.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
diff --git a/criu/dirty-logger.c b/criu/dirty-logger.c
index 811be23..d50e0d3 100644
--- a/criu/dirty-logger.c
+++ b/criu/dirty-logger.c
@@ -1,9 +1,12 @@
#include <pthread.h>
#include <sys/time.h>
+#include <unistd.h>
#include "imgset.h"
#include "pstree.h"
#include "protobuf.h"
+#include "util.h"
+#include "mem.h"
#include "images/stats.pb-c.h"
@@ -23,13 +26,98 @@ static int sleep_us(long us) {
return 0;
}
+void fd_cleanup(void *arg)
+{
+ close(*(int *)arg);
+}
+
+void fp_cleanup(void *arg)
+{
+ fclose((FILE *)arg);
+}
+
void img_cleanup(void *arg)
{
close_image((struct cr_img *)arg);
}
+#define MAPS_PATH "/proc/%d/maps"
+#define MAX_MAPS_PATH 50
+#define BUFF_SIZE 500000
+#define LINELEN 256
+
static int pid_log_dirty_total(pid_t pid, long *total_pages, long *total_dirty_pages)
{
+ char maps_path[MAX_MAPS_PATH];
+ FILE * maps;
+ int pagemap_fd;
+
+ u64 pfn[BUFF_SIZE];
+ char line[LINELEN];
+
+ sprintf(maps_path, MAPS_PATH, pid);
+ maps = fopen(maps_path, "r");
+ if (maps == NULL) {
+ pr_perror("Can't open pid %d maps", pid);
+ return -1;
+ }
+ pthread_cleanup_push(fp_cleanup, (void *)maps);
+
+ pagemap_fd = open_proc(pid, "pagemap");
+ if (pagemap_fd < 0) {
+ pr_perror("Can't open pid %d pagemap", pid);
+ return -1;
+ }
+ pthread_cleanup_push(fd_cleanup, (void *)&pagemap_fd);
+
+ /*
+ * For each line in maps
+ */
+ while (fgets(line, LINELEN, maps) != NULL) {
+ char * pend;
+ uint64_t start, end;
+ off_t off;
+ long j;
+ int ret;
+
+ start = strtoul(line, &pend, 16);
+ end = strtoul(pend + 1, NULL, 16);
+ if (start >= end)
+ continue;
+
+ off = (start / PAGE_SIZE) * sizeof(u64);
+ pr_debug("Read pagemap from %"PRIx64" to %"PRIx64"\n", start, end);
+ if (lseek (pagemap_fd, off, SEEK_SET) != off) {
+ pr_perror("Failed to seek address %"PRIx64"\n", off);
+ return -1;
+ }
+
+ if ((end - start) / PAGE_SIZE > BUFF_SIZE) {
+ pr_err("Buffer overflow for pid %d\n", pid);
+ return -1;
+ }
+
+ ret = read(pagemap_fd, pfn, ((end - start) / PAGE_SIZE) * sizeof(u64));
+ if (ret != ((end - start) / PAGE_SIZE) * sizeof(u64)) {
+ if (ret == 0) {
+ pr_debug("Can't read because of EOF\n");
+ continue;
+ }
+ pr_perror("Can't read pme for pid %d", pid);
+ return -1;
+ }
+
+ *total_pages += ret/sizeof(u64);
+ for (j = 0; j < ret/sizeof(u64); j++) {
+ if (pfn[j] & PME_SOFT_DIRTY) {
+ (*total_dirty_pages)++;
+ }
+ }
+ pr_debug("Pid %d: %ld pages read, %ld dirty\n", pid, *total_pages, *total_dirty_pages);
+ }
+
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
return 0;
}
--
2.5.5
More information about the CRIU
mailing list