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
#include
#include
#include
#include
#include
#include
#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, );
#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, );
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
#include
#include
#include
#include
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], , 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