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;
}

Attachment: signature.asc
Description: PGP signature

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

Reply via email to