Index: /trunk/src/VBox/Storage/testcase/tstVDIo.cpp
===================================================================
--- /trunk/src/VBox/Storage/testcase/tstVDIo.cpp	(revision 40708)
+++ /trunk/src/VBox/Storage/testcase/tstVDIo.cpp	(revision 40709)
@@ -53,4 +53,16 @@
     /** Flag whether the file is write locked. */
     bool           fWriteLock;
+    /** Statistics: Number of reads. */
+    unsigned       cReads;
+    /** Statistics: Number of writes. */
+    unsigned       cWrites;
+    /** Statistics: Number of flushes. */
+    unsigned       cFlushes;
+    /** Statistics: Number of async reads. */
+    unsigned       cAsyncReads;
+    /** Statistics: Number of async writes. */
+    unsigned       cAsyncWrites;
+    /** Statistics: Number of async flushes. */
+    unsigned       cAsyncFlushes;
 } VDFILE, *PVDFILE;
 
@@ -315,4 +327,6 @@
 static DECLCALLBACK(int) vdScriptHandlerDumpDiskInfo(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
 static DECLCALLBACK(int) vdScriptHandlerPrintMsg(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
+static DECLCALLBACK(int) vdScriptHandlerShowStatistics(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
+static DECLCALLBACK(int) vdScriptHandlerResetStatistics(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
 
 /* create action */
@@ -320,10 +334,11 @@
 {
     /* pcszName    chId enmType                          fFlags */
-    {"disk",       'd', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
-    {"mode",       'm', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
-    {"name",       'n', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
-    {"type",       't', VDSCRIPTARGTYPE_STRING,          0},
-    {"backend",    'b', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
-    {"size",       's', VDSCRIPTARGTYPE_UNSIGNED_NUMBER, VDSCRIPTARGDESC_FLAG_MANDATORY | VDSCRIPTARGDESC_FLAG_SIZE_SUFFIX}
+    {"disk",        'd', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
+    {"mode",        'm', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
+    {"name",        'n', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
+    {"type",        't', VDSCRIPTARGTYPE_STRING,          0},
+    {"backend",     'b', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
+    {"size",        's', VDSCRIPTARGTYPE_UNSIGNED_NUMBER, VDSCRIPTARGDESC_FLAG_MANDATORY | VDSCRIPTARGDESC_FLAG_SIZE_SUFFIX},
+    {"ignoreflush", 'f', VDSCRIPTARGTYPE_BOOL,            0}
 };
 
@@ -332,11 +347,12 @@
 {
     /* pcszName    chId enmType                          fFlags */
-    {"disk",       'd', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
-    {"name",       'n', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
-    {"backend",    'b', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
-    {"async",      'a', VDSCRIPTARGTYPE_BOOL,            0},
-    {"shareable",  's', VDSCRIPTARGTYPE_BOOL,            0},
-    {"readonly",   'r', VDSCRIPTARGTYPE_BOOL,            0},
-    {"discard",    'i', VDSCRIPTARGTYPE_BOOL,            0},
+    {"disk",        'd', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
+    {"name",        'n', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
+    {"backend",     'b', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
+    {"async",       'a', VDSCRIPTARGTYPE_BOOL,            0},
+    {"shareable",   's', VDSCRIPTARGTYPE_BOOL,            0},
+    {"readonly",    'r', VDSCRIPTARGTYPE_BOOL,            0},
+    {"discard",     'i', VDSCRIPTARGTYPE_BOOL,            0},
+    {"ignoreflush", 'f', VDSCRIPTARGTYPE_BOOL,            0},
 };
 
@@ -513,4 +529,18 @@
     /* pcszName    chId enmType                          fFlags */
     {"msg",        'm', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
+};
+
+/* Show statistics */
+const VDSCRIPTARGDESC g_aArgShowStatistics[] =
+{
+    /* pcszName    chId enmType                          fFlags */
+    {"file",       'f', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
+};
+
+/* Reset statistics */
+const VDSCRIPTARGDESC g_aArgResetStatistics[] =
+{
+    /* pcszName    chId enmType                          fFlags */
+    {"file",       'f', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
 };
 
@@ -540,5 +570,7 @@
     {"comparedisks",               g_aArgCompareDisks,                RT_ELEMENTS(g_aArgCompareDisks),               vdScriptHandlerCompareDisks},
     {"dumpdiskinfo",               g_aArgDumpDiskInfo,                RT_ELEMENTS(g_aArgDumpDiskInfo),               vdScriptHandlerDumpDiskInfo},
-    {"print",                      g_aArgPrintMsg,                    RT_ELEMENTS(g_aArgPrintMsg),                   vdScriptHandlerPrintMsg}
+    {"print",                      g_aArgPrintMsg,                    RT_ELEMENTS(g_aArgPrintMsg),                   vdScriptHandlerPrintMsg},
+    {"showstatistics",             g_aArgShowStatistics,              RT_ELEMENTS(g_aArgShowStatistics),             vdScriptHandlerShowStatistics},
+    {"resetstatistics",            g_aArgResetStatistics,             RT_ELEMENTS(g_aArgResetStatistics),            vdScriptHandlerResetStatistics}
 };
 
@@ -584,4 +616,5 @@
     bool fBase = false;
     bool fDynamic = true;
+    bool fIgnoreFlush = false;
 
     for (unsigned i = 0; i < cScriptArgs; i++)
@@ -635,4 +668,9 @@
                 break;
             }
+            case 'f':
+            {
+                fIgnoreFlush = true;
+                break;
+            }
             default:
                 AssertMsgFailed(("Invalid argument given!\n"));
@@ -648,13 +686,17 @@
         if (pDisk)
         {
+            unsigned fOpenFlags = VD_OPEN_FLAGS_ASYNC_IO;
             unsigned fImageFlags = VD_IMAGE_FLAGS_NONE;
 
             if (!fDynamic)
                 fImageFlags |= VD_IMAGE_FLAGS_FIXED;
+
+            if (fIgnoreFlush)
+                fOpenFlags |= VD_OPEN_FLAGS_IGNORE_FLUSH;
 
             if (fBase)
                 rc = VDCreateBase(pDisk->pVD, pcszBackend, pcszImage, cbSize, fImageFlags, NULL,
                                   &pDisk->PhysGeom, &pDisk->LogicalGeom,
-                                  NULL, VD_OPEN_FLAGS_ASYNC_IO, pGlob->pInterfacesImages, NULL);
+                                  NULL, fOpenFlags, pGlob->pInterfacesImages, NULL);
             else
                 rc = VDCreateDiff(pDisk->pVD, pcszBackend, pcszImage, fImageFlags, NULL, NULL, NULL, VD_OPEN_FLAGS_ASYNC_IO,
@@ -679,4 +721,5 @@
     bool fAsyncIo  = true;
     bool fDiscard  = false;
+    bool fIgnoreFlush = false;
 
     for (unsigned i = 0; i < cScriptArgs; i++)
@@ -742,4 +785,6 @@
             if (fDiscard)
                 fOpenFlags |= VD_OPEN_FLAGS_DISCARD;
+            if (fIgnoreFlush)
+                fOpenFlags |= VD_OPEN_FLAGS_IGNORE_FLUSH;
 
             rc = VDOpen(pDisk->pVD, pcszBackend, pcszImage, fOpenFlags, pGlob->pInterfacesImages);
@@ -2412,4 +2457,97 @@
 }
 
+static DECLCALLBACK(int) vdScriptHandlerShowStatistics(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs)
+{
+    int rc = VINF_SUCCESS;
+    const char *pcszFile = NULL;
+
+    for (unsigned i = 0; i < cScriptArgs; i++)
+    {
+        switch (paScriptArgs[i].chId)
+        {
+            case 'f':
+            {
+                pcszFile = paScriptArgs[i].u.pcszString;
+                break;
+            }
+            default:
+                AssertMsgFailed(("Invalid argument given!\n"));
+        }
+    }
+
+    /* Check for the file. */
+    PVDFILE pIt = NULL;
+    bool fFound = false;
+    RTListForEach(&pGlob->ListFiles, pIt, VDFILE, Node)
+    {
+        if (!RTStrCmp(pIt->pszName, pcszFile))
+        {
+            fFound = true;
+            break;
+        }
+    }
+
+    if (fFound)
+    {
+        RTPrintf("Statistics %s: \n"
+                 "               sync  reads=%u writes=%u flushes=%u\n"
+                 "               async reads=%u writes=%u flushes=%u\n",
+                 pcszFile,
+                 pIt->cReads, pIt->cWrites, pIt->cFlushes,
+                 pIt->cAsyncReads, pIt->cAsyncWrites, pIt->cAsyncFlushes);
+    }
+    else
+        rc = VERR_FILE_NOT_FOUND;
+
+    return rc;
+}
+
+static DECLCALLBACK(int) vdScriptHandlerResetStatistics(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs)
+{
+    int rc = VINF_SUCCESS;
+    const char *pcszFile = NULL;
+
+    for (unsigned i = 0; i < cScriptArgs; i++)
+    {
+        switch (paScriptArgs[i].chId)
+        {
+            case 'f':
+            {
+                pcszFile = paScriptArgs[i].u.pcszString;
+                break;
+            }
+            default:
+                AssertMsgFailed(("Invalid argument given!\n"));
+        }
+    }
+
+    /* Check for the file. */
+    PVDFILE pIt = NULL;
+    bool fFound = false;
+    RTListForEach(&pGlob->ListFiles, pIt, VDFILE, Node)
+    {
+        if (!RTStrCmp(pIt->pszName, pcszFile))
+        {
+            fFound = true;
+            break;
+        }
+    }
+
+    if (fFound)
+    {
+        pIt->cReads   = 0;
+        pIt->cWrites  = 0;
+        pIt->cFlushes = 0;
+
+        pIt->cAsyncReads   = 0;
+        pIt->cAsyncWrites  = 0;
+        pIt->cAsyncFlushes = 0;
+    }
+    else
+        rc = VERR_FILE_NOT_FOUND;
+
+    return rc;
+}
+
 static DECLCALLBACK(int) tstVDIoFileOpen(void *pvUser, const char *pszLocation,
                                          uint32_t fOpen,
@@ -2624,5 +2762,8 @@
     rc = VDMemDiskWrite(pIoStorage->pFile->pMemDisk, uOffset, cbBuffer, &SgBuf);
     if (RT_SUCCESS(rc) && pcbWritten)
+    {
+        pIoStorage->pFile->cWrites++;
         *pcbWritten = cbBuffer;
+    }
 
     return rc;
@@ -2643,5 +2784,8 @@
     rc = VDMemDiskRead(pIoStorage->pFile->pMemDisk, uOffset, cbBuffer, &SgBuf);
     if (RT_SUCCESS(rc) && pcbRead)
+    {
+        pIoStorage->pFile->cReads++;
         *pcbRead = cbBuffer;
+    }
 
     return rc;
@@ -2650,5 +2794,6 @@
 static DECLCALLBACK(int) tstVDIoFileFlushSync(void *pvUser, void *pStorage)
 {
-    /* nothing to do. */
+    PVDSTORAGE pIoStorage = (PVDSTORAGE)pStorage;
+    pIoStorage->pFile->cFlushes++;
     return VINF_SUCCESS;
 }
@@ -2666,5 +2811,8 @@
                                 cbRead, paSegments, cSegments, pIoStorage->pfnComplete, pvCompletion);
     if (RT_SUCCESS(rc))
+    {
+        pIoStorage->pFile->cAsyncReads++;
         rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
+    }
 
     return rc;
@@ -2683,5 +2831,8 @@
                                 cbWrite, paSegments, cSegments, pIoStorage->pfnComplete, pvCompletion);
     if (RT_SUCCESS(rc))
+    {
+        pIoStorage->pFile->cAsyncWrites++;
         rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
+    }
 
     return rc;
@@ -2698,5 +2849,8 @@
                                 0, NULL, 0, pIoStorage->pfnComplete, pvCompletion);
     if (RT_SUCCESS(rc))
+    {
+        pIoStorage->pFile->cAsyncFlushes++;
         rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
+    }
 
     return rc;
@@ -2826,5 +2980,5 @@
 
                 Assert(idx != -1);
-                pIoReq->off = idx * pIoTest->cbBlkIo;
+                pIoReq->off = (uint64_t)idx * pIoTest->cbBlkIo;
                 pIoTest->u.Rnd.cBlocksLeft--;
                 if (!pIoTest->u.Rnd.cBlocksLeft)
