[libvirt] [PATCH 4/4] Introduce new OOM testing support
Eric Blake
eblake at redhat.com
Wed Sep 25 18:40:08 UTC 2013
On 09/25/2013 11:23 AM, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange" <berrange at redhat.com>
>
> The previous OOM testing support would re-run the entire "main"
> method each iteration, failing a different malloc each time.
> When a test suite has 'n' allocations, the number of repeats
> requires is (n * (n + 1) ) / 2. This gets very large, very
> quickly.
>
> This new OOM testing support instead integrates at the
> virtTestRun level, so each individual test case gets repeated,
> instead of the entire test suite. This means the values of
> 'n' are orders of magnitude smaller.
Still O(n^2) - but yes, a smaller n makes for a NOTICEABLE speedup [that
is, 30 alloc's per test on a main() that runs 30 tests is much nicer
than 900 alloc's per main()] :)
>
> The simple usage is
>
> $ VIR_TEST_OOM=1 ./qemuxml2argvtest
> ...
> 29) QEMU XML-2-ARGV clock-utc ... OK
> Test OOM for nalloc=36 .................................... OK
> 30) QEMU XML-2-ARGV clock-localtime ... OK
> Test OOM for nalloc=36 .................................... OK
> 31) QEMU XML-2-ARGV clock-france ... OK
> Test OOM for nalloc=38 ...................................... OK
> ...
>
> the second lines reports how many mallocs have to be failed, and thus
> how many repeats of the test wil be run.
s/wil/will/
>
> If it crashes, then running under valgrind will often show the problem
>
> $ VIR_TEST_OOM=1 ../run valgrind ./qemuxml2argvtest
>
> When debugging problems it is also helpful to select an individual
> test case
>
> $ VIR_TEST_RANGE=30 VIR_TEST_OOM=1 ../run valgrind ./qemuxml2argvtest
>
> When things get really tricky, it is possible to request that just
> specific allocs are failed. eg to fail allocs 5 -> 12, use
>
> $ VIR_TEST_RANGE=30 VIR_TEST_OOM=1:5-12 ../run valgrind ./qemuxml2argvtest
Please document VIR_TEST_OOM in docs/hacking.html.in (and thus HACKING).
Does it require building with './configure --enable-test-oom'?
>
> In the worse case, you might want to know the stack trace of the
> alloc which was failed then VIR_TEST_OOM_TRACE can be set. If it
> is set to 1 then it will only print if it things a mistake happened.
s/things/thinks/
> This is often not reliable, so setting it to 2 will make it print
> the stack trace for every alloc that is failed.
>
> $ VIR_TEST_OOM_TRACE=2 VIR_TEST_RANGE=30 VIR_TEST_OOM=1:5-5 ../run valgrind ./qemuxml2argvtest
> 30) QEMU XML-2-ARGV clock-localtime ... OK
> Test OOM for nalloc=36 !virAllocN
> /home/berrange/src/virt/libvirt/src/util/viralloc.c:180
> virHashCreateFull
> /home/berrange/src/virt/libvirt/src/util/virhash.c:144
> virDomainDefParseXML
> /home/berrange/src/virt/libvirt/src/conf/domain_conf.c:11745
> virDomainDefParseNode
> /home/berrange/src/virt/libvirt/src/conf/domain_conf.c:12646
> virDomainDefParse
> /home/berrange/src/virt/libvirt/src/conf/domain_conf.c:12590
> testCompareXMLToArgvFiles
> /home/berrange/src/virt/libvirt/tests/qemuxml2argvtest.c:106
> virtTestRun
> /home/berrange/src/virt/libvirt/tests/testutils.c:250
> mymain
> /home/berrange/src/virt/libvirt/tests/qemuxml2argvtest.c:418 (discriminator 2)
> virtTestMain
> /home/berrange/src/virt/libvirt/tests/testutils.c:750
> ??
> ??:0
> _start
> ??:?
> FAILED
>
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> ---
> tests/cputest.c | 3 +-
> tests/qemuargv2xmltest.c | 14 ++--
> tests/qemuxml2argvtest.c | 12 ++-
> tests/qemuxmlnstest.c | 18 +++--
> tests/testutils.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++-
> tests/testutils.h | 2 +
> 6 files changed, 216 insertions(+), 22 deletions(-)
>
> diff --git a/tests/cputest.c b/tests/cputest.c
> index 8e3640b..17cb6af 100644
> --- a/tests/cputest.c
> +++ b/tests/cputest.c
> @@ -476,7 +476,8 @@ cpuTestRun(const char *name, const struct data *data)
> if (virTestGetDebug()) {
> char *log;
> if ((log = virtTestLogContentAndReset()) &&
> - strlen(log) > 0)
> + log != NULL &&
> + strlen(log) > 0)
Spurious change adding dead code. You already checked that log was
non-null in the left half of the &&.
> +++ b/tests/testutils.c
> @@ -47,6 +47,9 @@
> #include "virprocess.h"
> #include "virstring.h"
>
> +#include <dlfcn.h>
> +#include <execinfo.h>
Needs to be conditional (these are not universal headers; gnulib won't
help you).
> +#ifdef TEST_OOM
> +static unsigned int testOOM = 0;
> +static unsigned int testOOMStart = -1;
> +static unsigned int testOOMEnd = -1;
> +static unsigned int testOOMTrace = 0;
> +# ifdef TEST_OOM_TRACE
Why the two conditions? Or is TEST_OOM_TRACE based on whether
<execinfo.h> is present?
> +virTestShowTrace(void)
> +{
> + size_t j;
> + for (j = 2; j < ntestAllocStack; j++) {
> + Dl_info info;
> + char *cmd;
> +
> + dladdr(testAllocStack[j], &info);
> + if (info.dli_fname &&
> + strstr(info.dli_fname, ".so")) {
> + if (virAsprintf(&cmd, "addr2line -f -e %s %p",
> + info.dli_fname,
> + ((void*)((unsigned long long)testAllocStack[j]
> + - (unsigned long long)info.dli_fbase))) < 0)
> + continue;
> + } else {
> + if (virAsprintf(&cmd, "addr2line -f -e %s %p",
> + (char*)(info.dli_fname ? info.dli_fname : "<unknown>"),
> + testAllocStack[j]) < 0)
> + continue;
> + }
> + ignore_value(system(cmd));
configure.ac defined TEST_OOM_TRACE solely based on whether
'backtrace()' exists; but as you are also using addr2line and looking
for .so files, which starts to feel specific to Linux, is it more
conservative to disable this option on non-Linux?
> @@ -168,7 +226,7 @@ virtTestRun(const char *title,
> !((testCounter-1) % 40)) {
> fprintf(stderr, " %-3zu\n", (testCounter-1));
> fprintf(stderr, " ");
> - }
> + }
Missed in patch 3/4?
> + testOOMActive = true;
> + for (i = start; i < end; i++) {
> + bool missingFail = false;
> +# ifdef TEST_OOM_TRACE
> + memset(testAllocStack, 0, ARRAY_CARDINALITY(testAllocStack));
> + ntestAllocStack = 0;
> +# endif
> + virAllocTestOOM(i+1, 1);
spaces around +
> + oomret = body(data);
> +
> + /* fprintf() disabled because XML parsing APIs don't allow
> + * distinguish between element / attribute not present
> + * in the XML (which is non-fatal), vs OOM / malformed
> + * which should be fatal. Thus error reporting for
> + * optionally present XML is mostly broken.
> + */
> + if (oomret == 0) {
> + missingFail = true;
> +# if 0
> + fprintf(stderr, " alloc %zu failed but no err status\n", i + 1);
> +# endif
> + } else {
> + virErrorPtr lerr = virGetLastError();
> + if (!lerr) {
> +# if 0
> + fprintf(stderr, " alloc %zu failed but no error report\n", i + 1);
> +# endif
> + missingFail = true;
> + }
> + }
> + if ((missingFail && testOOMTrace) || (testOOMTrace > 1)) {
Safe to drop () around 'testOOMTrace > 1'
> + fprintf(stderr, "%s", "!");
> +# ifdef TEST_OOM_TRACE
> + virTestShowTrace();
> +# endif
> + ret = -1;
> + } else {
> + fprintf(stderr, "%s", ".");
> + }
> + }
> + testOOMActive = false;
> + if (ret == 0)
> + fprintf(stderr, " OK\n");
> + else
> + fprintf(stderr, " FAILED\n");
> + virAllocTestInit();
> + }
> +#endif /* TEST_OOM */
> +
> return ret;
> }
>
> @@ -205,7 +334,7 @@ virtTestLoadFile(const char *file, char **buf)
> tmplen = buflen = st.st_size + 1;
>
> if (VIR_ALLOC_N(*buf, buflen) < 0) {
> - fprintf(stderr, "%s: larger than available memory (> %d)\n", file, buflen);
> + //fprintf(stderr, "%s: larger than available memory (> %d)\n", file, buflen);
Is this hunk intentional?
> VIR_FORCE_FCLOSE(fp);
> return -1;
> }
> @@ -481,7 +610,8 @@ virtTestLogOutput(virLogSource source ATTRIBUTE_UNUSED,
> {
> struct virtTestLogData *log = data;
> virCheckFlags(VIR_LOG_STACK_TRACE,);
> - virBufferAsprintf(&log->buf, "%s: %s", timestamp, str);
> + if (!testOOMActive)
> + virBufferAsprintf(&log->buf, "%s: %s", timestamp, str);
> }
>
> static void
> @@ -550,6 +680,9 @@ int virtTestMain(int argc,
> int ret;
> bool abs_srcdir_cleanup = false;
> char *testRange = NULL;
> +#ifdef TEST_OOM
> + char *oomstr;
> +#endif
>
> abs_srcdir = getenv("abs_srcdir");
> if (!abs_srcdir) {
> @@ -610,6 +743,56 @@ int virtTestMain(int argc,
> }
> }
>
> +#ifdef TEST_OOM
> + if ((oomstr = getenv("VIR_TEST_OOM")) != NULL) {
> + char *next;
> + if (testDebug == -1)
> + testDebug = 1;
> + testOOM = 1;
> + if (oomstr[0] != '\0' &&
> + oomstr[1] == ':') {
> + if (virStrToLong_ui(oomstr + 2, &next, 10, &testOOMStart) < 0) {
> + fprintf(stderr, "Cannot parse range %s\n", oomstr);
> + return EXIT_FAILURE;
> + }
> + if (*next != '-') {
> + fprintf(stderr, "Cannot parse range %s\n", oomstr);
> + return EXIT_FAILURE;
> + }
Worth accepting VIR_TEST_OOM=1:1 as shorthand for 1:1-1?
I like where it's headed.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 621 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20130925/57aa7fde/attachment-0001.sig>
More information about the libvir-list
mailing list