Hi,
I have recently become concerned about obtaining accurate (non-drifting) and precise (fine-grained) timestamps within a Windows guest VM running on ESXi 4.0. I felt like I need to read real time from host machine instead of apparent time, and it seems that accessing Pseudoperformance Counters described in the official Timekeeping in VMware VMs whitepaper should do the trick. I followed the instructions provided in the whitepaper, but I can’t get the rdpmc instruction to work.
I added the line “monitor_control.pseudo_perfctr = TRUE” to the .vmx config file, and then tried to assemble the following code using masm32, but I keep on getting the error “rdpmc-test.asm(35) : error A2085: instruction or register not accepted in current CPU mode” (this is the line with rdpmc invocation). I am using VMware ESXi 4.0, and the same problem occurs on Windows XP 32-bit as well as Windows 7 32-bit guest machines. What am I doing wrong?
(rdpmc-test.asm)
include \masm32\include\masm32rt.inc
.data?
value dd ?
.data
item dd 0
.code
start:
call main
inkey
exit
main proc
print "rdpmc-test",13,10
pusha
mov ecx,10001H
rdpmc
;print str$(eax),13,10
popa
ret
main endp
end start
(makeit.bat)
@echo off
if exist "rdpmc-test.obj" del "rdpmc-test.obj"
if exist "rdpmc-test.exe" del "rdpmc-test.exe"\masm32\bin\ml /c /coff "rdpmc-test.asm"
if errorlevel 1 goto errasm\masm32\bin\PoLink /SUBSYSTEM:CONSOLE "rdpmc-test.obj"
if errorlevel 1 goto errlink
dir "rdpmc-test.*"
goto TheEnd:errlink
echo _
echo Link error
goto TheEnd:errasm
echo _
echo Assembly Error
goto TheEnd
:TheEndpause
(Error output)
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997. All rights reserved.Assembling: rdpmc-test.asm
rdpmc-test.asm(35) : error A2085: instruction or register not accepted in current CPU mode
_
Assembly ErrorPress any key to continue . . .
Thanks
Tomasz Szreder
The problem reading VMware Pseudo-Performance Counters is gone: in order to obtain an accurate timestamp provided by one of the counters, you can use the following code:
unsigned int performanceCounterValueHighPart;
unsigned int performanceCounterValueLowPart;
__asm { /* Try to poll VMware Pseudo-Performance Counter #0x10001 ("real time in ns") */
mov performanceCounterValueHighPart, 0
mov performanceCounterValueLowPart, 0
CPUID // Used for serialization
mov ecx, 0x10001 /* "Elapsed real time in ns":
* special pseudo-performance counter provided by VMware.
* Can only be used if the virtual machine
* has in .vmx configuration the following option:
* "monitor_control.pseudo_perfctr" = "TRUE"
* This allows to read timer count from the underlying host physical machine,
* effectively getting rid of the timekeeping problem.
* Read more at:
* http://www.vmware.com/files/pdf/Timekeeping-In-VirtualMachines.pdf
*/
RDPMC
mov performanceCounterValueHighPart, edx
mov performanceCounterValueLowPart, eax
}
The trick is to use either inline assembly (RDPMC) or compiler intrinsics (__readpmc()) and compile with Visual Studio rather than plain MASM32.
Hope this helps somebody.
Regards
Tomasz Szreder