From 2e22f23bde0ad6630a29d06ce164b6db8395f72c Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 5 Mar 2012 14:52:07 -0700 Subject: [PATCH] xml: allow scaled memory on input Output is still in kibibytes, but input can now be in different scales for ease of typing. * src/conf/domain_conf.c (virDomainParseMemory): New helper. (virDomainDefParseXML): Use it when parsing. * docs/schemas/domaincommon.rng: Expand XML; rename memoryKBElement to memoryElement and update callers. * docs/formatdomain.html.in (elementsMemoryAllocation): Document scaling. * tests/qemuxml2argvdata/qemuxml2argv-memtune.xml: Adjust test. * tests/qemuxml2xmltest.c: Likewise. * tests/qemuxml2xmloutdata/qemuxml2xmlout-memtune.xml: New file. --- docs/formatdomain.html.in | 43 +++++++-- docs/schemas/domaincommon.rng | 23 ++--- src/conf/domain_conf.c | 93 +++++++++++++++---- .../qemuxml2argvdata/qemuxml2argv-memtune.xml | 6 +- .../qemuxml2xmlout-memtune.xml | 31 +++++++ tests/qemuxml2xmltest.c | 2 +- 6 files changed, 148 insertions(+), 50 deletions(-) create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-memtune.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index b7cfb388a0..7710c5bb4d 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -415,8 +415,8 @@
 <domain>
   ...
-  <memory>524288</memory>
-  <currentMemory>524288</currentMemory>
+  <memory unit='KiB'>524288</memory>
+  <currentMemory unit='KiB'>524288</currentMemory>
   ...
 </domain>
 
@@ -424,12 +424,31 @@
memory
The maximum allocation of memory for the guest at boot time. - The units for this value are kibibytes (i.e. blocks of 1024 bytes)
+ The units for this value are determined by the optional + atttribute unit, which defaults to "KiB" + (kibibytes, 210 or blocks of 1024 bytes). Valid + units are "b" or "bytes" for bytes, "KB" for kilobytes + (103 or 1,000 bytes), "k" or "KiB" for kibibytes + (1024 bytes), "MB" for megabytes (106 or 1,000,000 + bytes), "M" or "MiB" for mebibytes (220 or + 1,048,576 bytes), "GB" for gigabytes (109 or + 1,000,000,000 bytes), "G" or "GiB" for gibibytes + (230 or 1,073,741,824 bytes), "TB" for terabytes + (1012 or 1,000,000,000,000 bytes), or "T" or "TiB" + for tebibytes (240 or 1,099,511,627,776 bytes). + However, the value will be rounded up to the nearest kibibyte + by libvirt, and may be further rounded to the granularity + supported by the hypervisor. Some hypervisors also enforce a + minimum, such as + 4000KiB. unit since + 0.9.11
currentMemory
The actual allocation of memory for the guest. This value can be less than the maximum allocation, to allow for ballooning up the guests memory on the fly. If this is omitted, it defaults - to the same value as the memory element
+ to the same value as the memory element. + The unit attribute behaves the same as + for memory.
@@ -460,10 +479,10 @@ <domain> ... <memtune> - <hard_limit>1048576</hard_limit> - <soft_limit>131072</soft_limit> - <swap_hard_limit>2097152</swap_hard_limit> - <min_guarantee>65536</min_guarantee> + <hard_limit unit='G'>1</hard_limit> + <soft_limit unit='M'>128</soft_limit> + <swap_hard_limit unit='G'>2</swap_hard_limit> + <min_guarantee unit='bytes'>67108864</min_guarantee> </memtune> ... </domain> @@ -477,7 +496,13 @@ parameters are applied to the QEMU process as a whole. Thus, when counting them, one needs to add up guest RAM, guest video RAM, and some memory overhead of QEMU itself. The last piece is hard to - determine so one needs guess and try. + determine so one needs guess and try. For each tunable, it + is possible to designate which unit the number is in on + input, using the same values as + for <memory>. For backwards + compatibility, output is always in + KiB. unit + since 0.9.11
hard_limit
The optional hard_limit element is the maximum memory the guest can use. The units for this value are kibibytes (i.e. blocks diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 0d97044a08..073ad37d66 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -412,11 +412,11 @@ - + - + @@ -461,25 +461,25 @@ - + - + - + - + @@ -3132,17 +3132,6 @@ [0-9]+ - - - - - KiB - - - - [0-9]+ - - diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b1dd00d623..601dc8b525 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7491,6 +7491,60 @@ static int virDomainDefMaybeAddController(virDomainDefPtr def, return 0; } + +/* Parse a memory element located at XPATH within CTXT, and store the + * result into MEM. If REQUIRED, then the value must exist; + * otherwise, the value is optional. The value is in blocks of 1024. + * Return 0 on success, -1 on failure after issuing error. */ +static int +virDomainParseMemory(const char *xpath, xmlXPathContextPtr ctxt, + unsigned long long *mem, bool required) +{ + char *xpath_full = NULL; + char *unit = NULL; + int ret = -1; + unsigned long long bytes; + unsigned long long max; + + *mem = 0; + if (virAsprintf(&xpath_full, "string(%s)", xpath) < 0) { + virReportOOMError(); + goto cleanup; + } + if (virXPathULongLong(xpath_full, ctxt, &bytes) < 0) { + if (required) + virDomainReportError(VIR_ERR_XML_ERROR, + "%s", _("missing memory element")); + else + ret = 0; + goto cleanup; + } + VIR_FREE(xpath_full); + + if (virAsprintf(&xpath_full, "string(%s/@unit)", xpath) < 0) { + virReportOOMError(); + goto cleanup; + } + unit = virXPathString(xpath_full, ctxt); + /* On 32-bit machines, our bound is 0xffffffff * KiB. On 64-bit + * machines, our bound is off_t (2^63). */ + if (sizeof(unsigned long) < sizeof(long long)) + max = 1024ull * ULONG_MAX; + else + max = LLONG_MAX; + if (virScaleInteger(&bytes, unit, 1024, max) < 0) + goto cleanup; + + /* Yes, we really do use kibibytes for our internal sizing. */ + *mem = VIR_DIV_UP(bytes, 1024); + ret = 0; +cleanup: + VIR_FREE(xpath_full); + VIR_FREE(unit); + return ret; +} + + static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, xmlDocPtr xml, xmlNodePtr root, @@ -7614,22 +7668,21 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, goto error; /* Extract domain memory */ - if (virXPathULongLong("string(./memory[1])", ctxt, - &def->mem.max_balloon) < 0) { - virDomainReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing memory element")); + if (virDomainParseMemory("./memory[1]", ctxt, + &def->mem.max_balloon, true) < 0) goto error; - } - if (virXPathULongLong("string(./currentMemory[1])", ctxt, - &def->mem.cur_balloon) < 0) - def->mem.cur_balloon = def->mem.max_balloon; + if (virDomainParseMemory("./currentMemory[1]", ctxt, + &def->mem.cur_balloon, false) < 0) + goto error; if (def->mem.cur_balloon > def->mem.max_balloon) { virDomainReportError(VIR_ERR_XML_ERROR, _("current memory '%lluk' exceeds maximum '%lluk'"), def->mem.cur_balloon, def->mem.max_balloon); goto error; + } else if (def->mem.cur_balloon == 0) { + def->mem.cur_balloon = def->mem.max_balloon; } node = virXPathNode("./memoryBacking/hugepages", ctxt); @@ -7668,21 +7721,21 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, VIR_FREE(nodes); /* Extract other memory tunables */ - if (virXPathULongLong("string(./memtune/hard_limit)", ctxt, - &def->mem.hard_limit) < 0) - def->mem.hard_limit = 0; + if (virDomainParseMemory("./memtune/hard_limit[1]", ctxt, + &def->mem.hard_limit, false) < 0) + goto error; - if (virXPathULongLong("string(./memtune/soft_limit[1])", ctxt, - &def->mem.soft_limit) < 0) - def->mem.soft_limit = 0; + if (virDomainParseMemory("./memtune/soft_limit[1]", ctxt, + &def->mem.soft_limit, false) < 0) + goto error; - if (virXPathULongLong("string(./memtune/min_guarantee[1])", ctxt, - &def->mem.min_guarantee) < 0) - def->mem.min_guarantee = 0; + if (virDomainParseMemory("./memtune/min_guarantee[1]", ctxt, + &def->mem.min_guarantee, false) < 0) + goto error; - if (virXPathULongLong("string(./memtune/swap_hard_limit[1])", ctxt, - &def->mem.swap_hard_limit) < 0) - def->mem.swap_hard_limit = 0; + if (virDomainParseMemory("./memtune/swap_hard_limit[1]", ctxt, + &def->mem.swap_hard_limit, false) < 0) + goto error; n = virXPathULong("string(./vcpu[1])", ctxt, &count); if (n == -2) { diff --git a/tests/qemuxml2argvdata/qemuxml2argv-memtune.xml b/tests/qemuxml2argvdata/qemuxml2argv-memtune.xml index b6c8c95ba8..ee087539ac 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-memtune.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-memtune.xml @@ -1,12 +1,12 @@ QEMUGuest1 c7a5fdbd-edaf-9455-926a-d65c16db1809 - 219136 + 214 219136 512000 - 128000 - 1024000 + 131071999 + 1048576 1 diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-memtune.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-memtune.xml new file mode 100644 index 0000000000..b6c8c95ba8 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-memtune.xml @@ -0,0 +1,31 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + + 512000 + 128000 + 1024000 + + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + +
+ + + + + + diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 03c75f81d1..3f749d277a 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -195,7 +195,7 @@ mymain(void) DO_TEST("pci-rom"); DO_TEST("encrypted-disk"); - DO_TEST("memtune"); + DO_TEST_DIFFERENT("memtune"); DO_TEST("blkiotune"); DO_TEST("blkiotune-device"); DO_TEST("cputune");