627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync/* $Id$ */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync/** @file
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * SUP Testcase - Global Info Page TSC Delta Measurement Utility.
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync/*
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * Copyright (C) 2015 Oracle Corporation
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync *
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * available from http://www.virtualbox.org. This file is free software;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * you can redistribute it and/or modify it under the terms of the GNU
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * General Public License (GPL) as published by the Free Software
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync *
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * The contents of this file may alternatively be used under the terms
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * of the Common Development and Distribution License Version 1.0
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * VirtualBox OSE distribution, in which case the provisions of the
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * CDDL are applicable instead of those of the GPL.
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync *
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * You may elect to license modified versions of this file under the
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * terms and conditions of either the GPL or the CDDL or both.
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync/*******************************************************************************
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync* Header Files *
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync*******************************************************************************/
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync#include <VBox/sup.h>
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync#include <VBox/err.h>
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync#include <iprt/assert.h>
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync#include <iprt/stream.h>
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync#include <iprt/string.h>
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync#include <iprt/getopt.h>
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync#include <iprt/test.h>
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync#include <iprt/thread.h>
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsyncint main(int argc, char **argv)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync{
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTTEST hTest;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTEXITCODE rcExit = RTTestInitExAndCreate(argc, &argv, 0 /*fRtInit*/, "tstSupTscDelta", &hTest);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (rcExit != RTEXITCODE_SUCCESS)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync return rcExit;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync /*
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * Parse args
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync static const RTGETOPTDEF g_aOptions[] =
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync { "--iterations", 'i', RTGETOPT_REQ_INT32 },
5a75426ab5888277b03a02aba637765e2a582206vboxsync { "--delay", 'd', RTGETOPT_REQ_INT32 },
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync };
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync uint32_t cIterations = 0; /* Currently 0 so that it doesn't upset testing. */
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync uint32_t cMsSleepBetweenIterations = 10;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync int ch;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTGETOPTUNION ValueUnion;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTGETOPTSTATE GetState;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTGetOptInit(&GetState, argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync while ((ch = RTGetOpt(&GetState, &ValueUnion)))
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync switch (ch)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
5a75426ab5888277b03a02aba637765e2a582206vboxsync case 'd':
5a75426ab5888277b03a02aba637765e2a582206vboxsync cMsSleepBetweenIterations = ValueUnion.u32;
5a75426ab5888277b03a02aba637765e2a582206vboxsync break;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync case 'i':
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync cIterations = ValueUnion.u32;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync break;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync default:
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync return RTGetOptPrintError(ch, &ValueUnion);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (!cIterations)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync return RTTestSkipAndDestroy(hTest, "Nothing to do. The --iterations argument is 0 or not given.");
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync /*
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * Init
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync PSUPDRVSESSION pSession = NIL_RTR0PTR;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync int rc = SUPR3Init(&pSession);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (RT_SUCCESS(rc))
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (pGip)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (pGip->enmUseTscDelta < SUPGIPUSETSCDELTA_PRACTICALLY_ZERO)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync return RTTestSkipAndDestroy(hTest, "No deltas to play with: enmUseTscDelta=%d\n", pGip->enmUseTscDelta);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync /*
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync * Init stats.
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync struct
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync int64_t iLowest;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync int64_t iHighest;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync int64_t iTotal;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync uint64_t uAbsMin;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync uint64_t uAbsMax;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync uint64_t uAbsTotal;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync } aCpuStats[RTCPUSET_MAX_CPUS];
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RT_ZERO(aCpuStats);
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync for (uint32_t i = 0; i < pGip->cCpus; i++)
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync {
dcf81268c0d74399723a43820403ca2412138571vboxsync aCpuStats[i].iLowest = INT64_MAX;
dcf81268c0d74399723a43820403ca2412138571vboxsync aCpuStats[i].iHighest = INT64_MIN;
dcf81268c0d74399723a43820403ca2412138571vboxsync aCpuStats[i].uAbsMin = UINT64_MAX;
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync /*
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync * Do the work.
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync for (uint32_t iIteration = 0; ; iIteration++)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync /*
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * Display the current deltas and gather statistics.
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTPrintf("tstSupTscDelta: Iteration #%u results:", iIteration);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync for (uint32_t iCpu = 0; iCpu < pGip->cCpus; iCpu++)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync int64_t iTscDelta = pGip->aCPUs[iCpu].i64TSCDelta;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync /* print */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if ((iCpu % 4) == 0)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTPrintf("\ntstSupTscDelta:");
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (pGip->aCPUs[iCpu].enmState != SUPGIPCPUSTATE_ONLINE)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTPrintf(" %02x: offline ", iCpu, iTscDelta);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync else if (iTscDelta != INT64_MAX)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTPrintf(" %02x: %-12lld", iCpu, iTscDelta);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync else
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTPrintf(" %02x: INT64_MAX ", iCpu);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync /* stats */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if ( iTscDelta != INT64_MAX
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync && pGip->aCPUs[iCpu].enmState == SUPGIPCPUSTATE_ONLINE)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (aCpuStats[iCpu].iLowest > iTscDelta)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].iLowest = iTscDelta;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (aCpuStats[iCpu].iHighest < iTscDelta)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].iHighest = iTscDelta;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].iTotal += iTscDelta;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync uint64_t uAbsTscDelta = iTscDelta >= 0 ? (uint64_t)iTscDelta : (uint64_t)-iTscDelta;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (aCpuStats[iCpu].uAbsMin > uAbsTscDelta)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].uAbsMin = uAbsTscDelta;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (aCpuStats[iCpu].uAbsMax < uAbsTscDelta)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].uAbsMax = uAbsTscDelta;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].uAbsTotal += uAbsTscDelta;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (((pGip->cCpus - 1) % 4) != 0)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTPrintf("\n");
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync /*
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * Done?
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (iIteration + 1 >= cIterations)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync break;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync /*
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * Force a new measurement.
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync */
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync RTThreadSleep(cMsSleepBetweenIterations);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync for (uint32_t iCpu = 0; iCpu < pGip->cCpus; iCpu++)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (pGip->aCPUs[iCpu].enmState == SUPGIPCPUSTATE_ONLINE)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
b377749db3dc9bc2591eba6a69cc313c04c82467vboxsync rc = SUPR3TscDeltaMeasure(pGip->aCPUs[iCpu].idCpu, false /*fAsync*/, true /*fForce*/, 64, 16 /*ms*/);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (RT_FAILURE(rc))
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTTestFailed(hTest, "SUPR3TscDeltaMeasure failed on %#x: %Rrc", pGip->aCPUs[iCpu].idCpu, rc);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync /*
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync * Display statistics that we've gathered.
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync */
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTPrintf("tstSupTscDelta: Results:\n");
dcf81268c0d74399723a43820403ca2412138571vboxsync int64_t iLowest = INT64_MAX;
dcf81268c0d74399723a43820403ca2412138571vboxsync int64_t iHighest = INT64_MIN;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync int64_t iTotal = 0;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync uint32_t cTotal = 0;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync for (uint32_t iCpu = 0; iCpu < pGip->cCpus; iCpu++)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (pGip->aCPUs[iCpu].enmState != SUPGIPCPUSTATE_ONLINE)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTPrintf("tstSupTscDelta: %02x: offline\n", iCpu);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync else
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync {
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTPrintf("tstSupTscDelta: %02x: lowest=%-12lld highest=%-12lld average=%-12lld spread=%-12lld\n",
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync iCpu,
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].iLowest,
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].iHighest,
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].iTotal / cIterations,
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].iHighest - aCpuStats[iCpu].iLowest);
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync RTPrintf( "tstSupTscDelta: absmin=%-12llu absmax=%-12llu absavg=%-12llu idCpu=%#4x idApic=%#4x\n",
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].uAbsMin,
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync aCpuStats[iCpu].uAbsMax,
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync aCpuStats[iCpu].uAbsTotal / cIterations,
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync pGip->aCPUs[iCpu].idCpu,
af8198c38cf9e9ae20d0ce6f66757f6db41793a1vboxsync pGip->aCPUs[iCpu].idApic);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (iLowest > aCpuStats[iCpu].iLowest)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync iLowest = aCpuStats[iCpu].iLowest;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync if (iHighest < aCpuStats[iCpu].iHighest)
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync iHighest = aCpuStats[iCpu].iHighest;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync iTotal += aCpuStats[iCpu].iHighest;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync cTotal += cIterations;
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTPrintf("tstSupTscDelta: all: lowest=%-12lld highest=%-12lld average=%-12lld spread=%-12lld\n",
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync iLowest, iHighest, iTotal / cTotal, iHighest - iLowest);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync else
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTTestFailed(hTest, "g_pSUPGlobalInfoPage is NULL");
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync SUPR3Term(false /*fForced*/);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync }
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync else
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync RTTestFailed(hTest, "SUPR3Init failed: %Rrc", rc);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync return RTTestSummaryAndDestroy(hTest);
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync}
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync
627d6508e4164c14daf4e6abee063d8dd988e57bvboxsync