Index: /trunk/include/VBox/vmm/vm.h
===================================================================
--- /trunk/include/VBox/vmm/vm.h	(revision 91701)
+++ /trunk/include/VBox/vmm/vm.h	(revision 91702)
@@ -1346,5 +1346,5 @@
         struct NEM  s;
 #endif
-        uint8_t     padding[128];       /* multiple of 64 */
+        uint8_t     padding[256];       /* multiple of 64 */
     } nem;
 
@@ -1454,5 +1454,5 @@
 
     /** Padding for aligning the structure size on a page boundrary. */
-    uint8_t         abAlignment2[2136 - sizeof(PVMCPUR3) * VMM_MAX_CPU_COUNT];
+    uint8_t         abAlignment2[2008 - sizeof(PVMCPUR3) * VMM_MAX_CPU_COUNT];
 
     /* ---- end small stuff ---- */
Index: /trunk/include/VBox/vmm/vm.mac
===================================================================
--- /trunk/include/VBox/vmm/vm.mac	(revision 91701)
+++ /trunk/include/VBox/vmm/vm.mac	(revision 91702)
@@ -149,5 +149,5 @@
     .em                     resb 256
     alignb 64
-    .nem                    resb 128
+    .nem                    resb 256
     alignb 64
     .tm                     resb 10112
Index: /trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h	(revision 91701)
+++ /trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h	(revision 91702)
@@ -1607,4 +1607,5 @@
         Log5(("NEM GPA unmap all: %RGp (cMappedPages=%u)\n", GCPhys, pVM->nem.s.cMappedPages - 1));
         *pu2NemState = NEM_WIN_PAGE_STATE_UNMAPPED;
+        STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
     }
     else
@@ -1618,4 +1619,5 @@
 # endif
         *pu2NemState = NEM_WIN_PAGE_STATE_NOT_SET;
+        STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
     }
     if (pVM->nem.s.cMappedPages > 0)
@@ -1737,4 +1739,5 @@
                 if (RT_SUCCESS(rc))
                 {
+                    STAM_REL_COUNTER_INC(&pVM->nem.s.StatRemapPage);
                     pInfo->u2NemState = NEM_WIN_PAGE_STATE_WRITABLE;
                     pState->fDidSomething = true;
@@ -1743,4 +1746,6 @@
                           GCPhys, g_apszPageStates[u2State], pVM->nem.s.cMappedPages));
                 }
+                else
+                    STAM_REL_COUNTER_INC(&pVM->nem.s.StatRemapPageFailed);
             }
             else
@@ -1794,8 +1799,10 @@
         pState->fCanResume    = true;
         pInfo->u2NemState = NEM_WIN_PAGE_STATE_UNMAPPED;
+        STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
         uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
         Log5(("NEM GPA unmapped/exit: %RGp (was %s, cMappedPages=%u)\n", GCPhys, g_apszPageStates[u2State], cMappedPages));
         return VINF_SUCCESS;
     }
+    STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
 # ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
     LogRel(("nemHCWinHandleMemoryAccessPageCheckerCallback/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhys, rc));
@@ -1808,4 +1815,5 @@
     PGMPhysNemEnumPagesByState(pVM, pVCpu, NEM_WIN_PAGE_STATE_READABLE, nemHCWinUnmapOnePageCallback, NULL);
     Log(("nemHCWinHandleMemoryAccessPageCheckerCallback: Unmapped all (cMappedPages=%u)\n", pVM->nem.s.cMappedPages));
+    STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapAllPages);
 
     pState->fDidSomething = true;
@@ -4206,8 +4214,11 @@
          */
         uint32_t const cMappedPages = pVM->nem.s.cMappedPages;
-        if (cMappedPages >= 4000)
+        if (cMappedPages < pVM->nem.s.cMaxMappedPages)
+        { /* likely*/ }
+        else
         {
             PGMPhysNemEnumPagesByState(pVM, pVCpu, NEM_WIN_PAGE_STATE_READABLE, nemHCWinUnmapOnePageCallback, NULL);
             Log(("nemHCWinRunGC: Unmapped all; cMappedPages=%u -> %u\n", cMappedPages, pVM->nem.s.cMappedPages));
+            STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapAllPages);
         }
 # endif
@@ -4534,4 +4545,5 @@
 # endif
         {
+            STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
             uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
             Log5(("NEM GPA unmapped/A20: %RGp (was %s, cMappedPages=%u)\n", GCPhys, g_apszPageStates[pInfo->u2NemState], cMappedPages));
@@ -4540,4 +4552,5 @@
         else
         {
+            STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
 # ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
             LogRel(("nemHCWinUnsetForA20CheckerCallback/unmap: GCPhys=%RGp rc=%Rrc\n", GCPhys, rc));
@@ -4636,9 +4649,13 @@
             {
                 *pu2State = NEM_WIN_PAGE_STATE_UNMAPPED;
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
                 uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
                 Log5(("NEM GPA unmapped/set: %RGp (was %s, cMappedPages=%u)\n", GCPhysDst, g_apszPageStates[u2OldState], cMappedPages));
             }
             else
+            {
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
                 AssertLogRelMsgFailed(("nemHCNativeSetPhysPage/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
+            }
         }
         else
@@ -4655,4 +4672,5 @@
             {
                 *pu2State = NEM_WIN_PAGE_STATE_WRITABLE;
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPage);
                 uint32_t cMappedPages = u2OldState <= NEM_WIN_PAGE_STATE_UNMAPPED
                                       ? ASMAtomicIncU32(&pVM->nem.s.cMappedPages) : pVM->nem.s.cMappedPages;
@@ -4661,5 +4679,8 @@
             }
             else
+            {
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPageFailed);
                 AssertLogRelMsgFailed(("nemHCNativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
+            }
         }
         else
@@ -4675,4 +4696,5 @@
             {
                 *pu2State = NEM_WIN_PAGE_STATE_READABLE;
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPage);
                 uint32_t cMappedPages = u2OldState <= NEM_WIN_PAGE_STATE_UNMAPPED
                                       ? ASMAtomicIncU32(&pVM->nem.s.cMappedPages) : pVM->nem.s.cMappedPages;
@@ -4681,5 +4703,8 @@
             }
             else
+            {
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPageFailed);
                 AssertLogRelMsgFailed(("nemHCNativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
+            }
         }
         else
@@ -4710,4 +4735,5 @@
             {
                 *pu2State = NEM_WIN_PAGE_STATE_UNMAPPED;
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
                 uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
                 if (u2NewState == NEM_WIN_PAGE_STATE_UNMAPPED)
@@ -4720,4 +4746,5 @@
             else
             {
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
                 LogRel(("nemHCNativeSetPhysPage/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
                 return rc;
@@ -4728,4 +4755,5 @@
             {
                 *pu2State = NEM_WIN_PAGE_STATE_UNMAPPED;
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
                 uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
                 if (u2NewState == NEM_WIN_PAGE_STATE_UNMAPPED)
@@ -4738,4 +4766,5 @@
             else
             {
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
                 LogRel(("nemHCNativeSetPhysPage/unmap: GCPhysDst=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
                         GCPhysDst, hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
@@ -4759,4 +4788,5 @@
         {
             *pu2State = NEM_WIN_PAGE_STATE_WRITABLE;
+            STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPage);
             uint32_t cMappedPages = ASMAtomicIncU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
             Log5(("NEM GPA mapped/set: %RGp %s (was %s, cMappedPages=%u)\n",
@@ -4764,4 +4794,5 @@
             return VINF_SUCCESS;
         }
+        STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPageFailed);
         LogRel(("nemHCNativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
         return rc;
@@ -4776,4 +4807,5 @@
             {
                 *pu2State = NEM_WIN_PAGE_STATE_WRITABLE;
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPage);
                 uint32_t cMappedPages = ASMAtomicIncU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
                 Log5(("NEM GPA mapped/set: %RGp %s (was %s, cMappedPages=%u)\n",
@@ -4781,4 +4813,5 @@
                 return VINF_SUCCESS;
             }
+            STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPageFailed);
             LogRel(("nemHCNativeSetPhysPage/writable: GCPhysDst=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
                     GCPhysDst, hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
@@ -4799,4 +4832,5 @@
         {
             *pu2State = NEM_WIN_PAGE_STATE_READABLE;
+            STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPage);
             uint32_t cMappedPages = ASMAtomicIncU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
             Log5(("NEM GPA mapped/set: %RGp %s (was %s, cMappedPages=%u)\n",
@@ -4804,4 +4838,5 @@
             return VINF_SUCCESS;
         }
+        STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPageFailed);
         LogRel(("nemHCNativeSetPhysPage/readonly: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
         return rc;
@@ -4816,4 +4851,5 @@
             {
                 *pu2State = NEM_WIN_PAGE_STATE_READABLE;
+                STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPage);
                 uint32_t cMappedPages = ASMAtomicIncU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
                 Log5(("NEM GPA mapped/set: %RGp %s (was %s, cMappedPages=%u)\n",
@@ -4821,4 +4857,5 @@
                 return VINF_SUCCESS;
             }
+            STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPageFailed);
             LogRel(("nemHCNativeSetPhysPage/readonly: GCPhysDst=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
                     GCPhysDst, hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
@@ -4853,4 +4890,5 @@
     if (RT_SUCCESS(rc))
     {
+        STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
         uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
         Log5(("NEM GPA unmapped/just: %RGp (was %s, cMappedPages=%u)\n", GCPhysDst, g_apszPageStates[*pu2State], cMappedPages));
@@ -4858,10 +4896,13 @@
         return VINF_SUCCESS;
     }
+    STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
     LogRel(("nemHCJustUnmapPageFromHyperV/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
     return rc;
+
 #elif defined(IN_RING3)
     HRESULT hrc = WHvUnmapGpaRange(pVM->nem.s.hPartition, GCPhysDst & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK, X86_PAGE_SIZE);
     if (SUCCEEDED(hrc))
     {
+        STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
         uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
         *pu2State = NEM_WIN_PAGE_STATE_UNMAPPED;
@@ -4869,4 +4910,5 @@
         return VINF_SUCCESS;
     }
+    STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
     LogRel(("nemHCJustUnmapPageFromHyperV(%RGp): failed! hrc=%Rhrc (%#x) Last=%#x/%u\n",
             GCPhysDst, hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
Index: /trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 91701)
+++ /trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 91702)
@@ -1287,4 +1287,11 @@
 #endif
 
+#ifndef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
+    /** Some guess working here. */
+    pVM->nem.s.cMaxMappedPages = 4000;
+    if (g_uBuildNo >= 22000)
+        pVM->nem.s.cMaxMappedPages = _64K; /* seems it can do lots more even */
+#endif
+
     /*
      * Error state.
@@ -1334,4 +1341,24 @@
 
                         /* Register release statistics */
+                        STAMR3Register(pVM, (void *)&pVM->nem.s.cMappedPages, STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
+                                       "/NEM/PagesCurrentlyMapped", STAMUNIT_PAGES, "Number guest pages currently mapped by the VM");
+                        STAMR3Register(pVM, (void *)&pVM->nem.s.StatMapPage, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
+                                       "/NEM/PagesMapCalls", STAMUNIT_PAGES, "Calls to WHvMapGpaRange/HvCallMapGpaPages");
+                        STAMR3Register(pVM, (void *)&pVM->nem.s.StatMapPageFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
+                                       "/NEM/PagesMapFails", STAMUNIT_PAGES, "Calls to WHvMapGpaRange/HvCallMapGpaPages that failed");
+                        STAMR3Register(pVM, (void *)&pVM->nem.s.StatUnmapPage, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
+                                       "/NEM/PagesUnmapCalls", STAMUNIT_PAGES, "Calls to WHvUnmapGpaRange/HvCallUnmapGpaPages");
+                        STAMR3Register(pVM, (void *)&pVM->nem.s.StatUnmapPageFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
+                                       "/NEM/PagesUnmapFails", STAMUNIT_PAGES, "Calls to WHvUnmapGpaRange/HvCallUnmapGpaPages that failed");
+#ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
+                        STAMR3Register(pVM, (void *)&pVM->nem.s.StatRemapPage, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
+                                       "/NEM/PagesRemapCalls", STAMUNIT_PAGES, "Calls to HvCallMapGpaPages for changing page protection");
+                        STAMR3Register(pVM, (void *)&pVM->nem.s.StatRemapPage, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
+                                       "/NEM/PagesRemapFails", STAMUNIT_PAGES, "Calls to HvCallMapGpaPages for changing page protection failed");
+#else
+                        STAMR3Register(pVM, (void *)&pVM->nem.s.StatUnmapAllPages, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
+                                       "/NEM/PagesUnmapAll", STAMUNIT_PAGES, "Times we had to unmap all the pages");
+#endif
+
                         for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
                         {
@@ -2026,4 +2053,5 @@
 #endif
         {
+            STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
             uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
             Log5(("NEM GPA unmapped/A20: %RGp (was %s, cMappedPages=%u)\n", GCPhys, g_apszPageStates[pInfo->u2NemState], cMappedPages));
@@ -2032,4 +2060,5 @@
         else
         {
+            STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
 #ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
             LogRel(("nemR3WinUnsetForA20CheckerCallback/unmap: GCPhys=%RGp rc=%Rrc\n", GCPhys, rc));
Index: /trunk/src/VBox/VMM/include/NEMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/NEMInternal.h	(revision 91701)
+++ /trunk/src/VBox/VMM/include/NEMInternal.h	(revision 91702)
@@ -192,4 +192,18 @@
     /** Number of currently mapped pages. */
     uint32_t volatile           cMappedPages;
+#  ifndef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
+    /** Max number of pages we dare map at once. */
+    uint32_t                    cMaxMappedPages;
+#  endif
+    STAMCOUNTER                 StatMapPage;
+    STAMCOUNTER                 StatUnmapPage;
+#  ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
+    STAMCOUNTER                 StatRemapPage;
+    STAMCOUNTER                 StatRemapPageFailed;
+#  else
+    STAMCOUNTER                 StatUnmapAllPages;
+#  endif
+    STAMCOUNTER                 StatMapPageFailed;
+    STAMCOUNTER                 StatUnmapPageFailed;
 
 #  ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
