To measure how many dirty pages a domU creates within a timeframe the attached tool was created, based on code from xc_domain_save. Once the domU touches many pages the reported dirty rate is high, but after a few seconds the rate drops down from thousands to just a few dozen.
I wonder if the usage of xc_shadow_control is correct. The testing was done with a xen-4.4 based dom0, I will verify with staging once I find the time. Olaf
/* gcc -Wall -o logdirty -O -lxenctrl logdirty.c */ #include <unistd.h> #include <errno.h> #include <inttypes.h> #include <stdlib.h> #include <stdio.h> #include <xenctrl.h> #include <signal.h> #define PAGE_SHIFT XC_PAGE_SHIFT #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1)) #define NRPAGES(x) (ROUNDUP(x, PAGE_SHIFT) >> PAGE_SHIFT) #define BITS_PER_LONG (sizeof(unsigned long) * 8) #define ORDER_LONG (sizeof(unsigned long) == 4 ? 5 : 6) static unsigned int domid = 0; static xc_interface *xch; static unsigned long xdmg(xc_interface *c, unsigned int d) { unsigned long r; #if XEN_DOMCTL_INTERFACE_VERSION < 0x0b r = xc_domain_maximum_gpfn(c, d); #else xen_pfn_t gpfns = 0; r = xc_domain_maximum_gpfn(c, d, &gpfns); #endif return r + 1; } static void sigint_handler(int sig) { int rc; fprintf(stderr, "User aborted\n"); rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_OFF, NULL, 0, NULL, 0, NULL); if (rc < 0) perror("XEN_DOMCTL_SHADOW_OP_OFF hypercall failed\n"); exit(1); } static inline int bitmap_size(int nr_bits) { int nr_long, nr_bytes; nr_long = (nr_bits + BITS_PER_LONG - 1) >> ORDER_LONG; nr_bytes = nr_long * sizeof(unsigned long); return nr_bytes; } int main(int argc, char *argv[]) { int rc, ret = 1, i, runs = 42; unsigned int lflags; xentoollog_level lvl; xentoollog_logger *l; DECLARE_HYPERCALL_BUFFER(unsigned long, to_skip); unsigned long p2m_size; xc_shadow_op_stats_t stats; errno = EINVAL; if (argc > 1) domid = atoi(argv[1]); if (!domid) goto out; errno = 0; lvl = XTL_DEBUG; lflags = XTL_STDIOSTREAM_SHOW_PID | XTL_STDIOSTREAM_HIDE_PROGRESS; l = (xentoollog_logger *) xtl_createlogger_stdiostream(stderr, lvl, lflags); if (!l) goto out; xch = xc_interface_open(l, 0, 0); if (!xch) goto out; p2m_size = xdmg(xch, domid); if (!p2m_size) goto out; to_skip = xc_hypercall_buffer_alloc_pages(xch, to_skip, NRPAGES(bitmap_size(p2m_size))); if (!to_skip) goto out; signal(SIGINT, sigint_handler); rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY, NULL, 0, NULL, 0, NULL); if (rc < 0) { rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_OFF, NULL, 0, NULL, 0, NULL); if (rc < 0) goto out; rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY, NULL, 0, NULL, 0, NULL); if (rc < 0) goto out; } rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_CLEAN, NULL, 0, NULL, 0, NULL); if (rc < 0) goto out; for (i = 0; i < runs; i++) { sleep(1); if (1) rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_CLEAN, HYPERCALL_BUFFER(to_skip), p2m_size, NULL, 0, &stats); if (rc < 0) goto out; printf("%d: faults= %" PRIu32 " dirty= %" PRIu32 "\n", i, stats.fault_count, stats.dirty_count); } rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_OFF, NULL, 0, NULL, 0, NULL); if (rc < 0) goto out; errno = ret = 0; out: perror(argv[0]); return ret; }
/* gcc -Wall -o memdirty memdirty.c */ #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> static void usage(const char *prog, FILE * out) { fprintf(out, "usage: %s allocsize\n", prog); fprintf(out, " allocsize is kbytes, or number[KMGP] (P = pages)\n"); exit(out == stderr); } int main(int argc, char *argv[]) { long long kbtotal = 0, pages, i; unsigned offset; char *mem, *tmp; if (argc == 2) { char *end = NULL; kbtotal = strtoull(argv[1], &end, 0); switch (*end) { case 'g': case 'G': kbtotal *= 1024; case 'm': case 'M': kbtotal *= 1024; case '\0': case 'k': case 'K': break; case 'p': case 'P': kbtotal *= 4; break; default: usage(argv[0], stderr); break; } } if (argc != 2 || kbtotal == 0) usage(argv[0], stderr); pages = kbtotal / 4; errno = 0; printf("[%d] allocating %lld kbytes, %lld pages\n", getpid(), kbtotal, pages); mem = calloc(pages, 4096); perror("calloc"); if (mem == NULL) exit(1); offset = 0; while (1) { for (i = 0; i < pages; i++) { tmp = (mem + (i * 4096)) + (offset++ & (4096 - 1)); *tmp = *tmp + 1; } } return 0; }
signature.asc
Description: PGP signature
_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel