|
If you're seeing 15ms then I'm pretty sure that's the thread 'quantum' of Windows scheduling. It used to be 10ms on Windows NT 4.0
I've encountered this problem too. The best you can do is to not bother with the high perf counters, as they're still at the mercy of scheduler. All I do is get the average of about 3-5 readings, but the trick seems to be to put the thread to sleep until the next exact second (1000-current_millisecond) and repeat with timing durations less than the scheduling quantum. Which means it will take 3 - 4 seconds to get your average. Put thread into realtime priority, which should reduce preemption. (if you're confident that your timing-code is free of bugs)
sleep until msec:000, timing loop < 15ms
repeat as many times as you need to, the cpu scaling of some processors creates problems with initial result, so be prepared to discard the first and second result or ramp up the cpu to 100%.
If it's any consolation it's the same problem with any pre-emptive OS, but also disappointing to know that xGHz machines can't give you a reliable reading from within a modern OS. Linux calculates the timing before it boots.
"It's true that hard work never killed anyone. But I figure, why take the chance." - Ronald Reagan
That's what machines are for.
Got a problem?
Sleep on it.
modified 19-Mar-13 7:12am.
|
|
|
|
|
Thanks that does explain one glitch I got with GetTickCount and timeGetTime.
With the HPC though after dealing with the core changing issues, then it wasn't doing any sudden big jumps. Just measuring the time wrong.
I'm doing this to measure musical notes. But I've found a solution at last .
The key was discovery of yet another MS Windows timing routine, KeQueryUnbiasedInterruptTime which looked like the type of precise timing I need, but unfortunately only accessible in kernel mode
KeQueryUnbiasedInterruptTime[^]
However, then I found, that there is a little known structure called KUSER_SHARED_DATA which is added to the process address space of every user mode process at the address 0x7FFE0000 which is a system wide shared memory location. It is volatile, and gets updated with the kernel interrupt time continuously. This means that to check the kernel interrupt time, all you need to do is to look at the correct address location in your process address space.
This apparently is a hardware timer, not affected by changes in cycle rate of the processor cores. It might be using either the RTC or the HPET though I don't know which it is. And since it is just a memory look up then there is far less overhead involved than in any of the other timers used in Windows.
Combining this with the code I have already, which does a sleep that stops slightly short of the desired time followed by a busy wait time checking loop at real time time critical mode until the time is reached - and you get sub microsecond "sample perfect" timing of midi in Windows.
Here is the code:
typedef struct _KSYSTEM_TIME
{
UINT32 LowPart;
INT32 High1Time;
INT32 High2Time;
} KSYSTEM_TIME, *PKSYSTEM_TIME;
typedef struct _KUSER_SHARED_DATA
{
volatile ULONG TickCountLow;
UINT32 TickCountMultiplier;
volatile KSYSTEM_TIME InterruptTime;
volatile KSYSTEM_TIME SystemTime;
volatile KSYSTEM_TIME TimeZoneBias;
} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;
#define MM_SHARED_USER_DATA_VA 0x7FFE0000
#define USER_SHARED_DATA ((KUSER_SHARED_DATA * const)MM_SHARED_USER_DATA_VA)
double dInterruptTimer(void)
{
union
{
KSYSTEM_TIME SysTime;
__int64 CurrTime;
} ts;
ts.SysTime.High1Time = USER_SHARED_DATA->InterruptTime.High1Time;
ts.SysTime.LowPart = USER_SHARED_DATA->InterruptTime.LowPart;
return ts.CurrTime/(double)10000;
}
I got this by modifying source code available here
_glue.c[^]
which is part of Microsoft's "Invisible computing" real time operating system also known as MMLite. Microsoft Invisible Computing[^]
So it is documented Microsoft code and not just a hack using undocumented structures. It requires Windows NT or later.
This is an actual recording made in real time using my program to play the notes via midi on the Microsoft GS Wavetable synth:
This is a test of the use of the Windows interrupt timer to time notes in Bounce Metronome.[^]
Here is a screen shot of the recording where you can see the sample precise alignment of the notes. You can tell it is sample precise because all the details of the waveform are exactly the same - all the irregularities that you get which will look slightly different if you move the waveform by a sample or so and then look at it zoomed out like this.
screen shot of recording with sample precise timing[^]
This also seems like a great way to do performance testing too, without all that averaging we are used to, and with almost no overhead.
|
|
|
|
|
Glad you've finally solved it.
I was going to suggest the multimedia timers as another option. Kernel mode stuff is a bit beyond me to be quite honest.
I'd still like to find out why the timing stuff sometimes appear to go backward. It's not just windows, I've had similar problems with the Java VM.
Thanks for the invisible computing links, I'm always interested in Microsoft Research projects with accompanying source code.
"It's true that hard work never killed anyone. But I figure, why take the chance." - Ronald Reagan
That's what machines are for.
Got a problem?
Sleep on it.
|
|
|
|
|
Yes I've tried the multimedia timers. The problem is that on Windows they aren't quite good enough for musicians, frankly. They don't let you quite achieve the 1 ms precision that musicians require. There is a Microsoft article about that here too:
Guidelines For Providing Multimedia Timer Support[^]
So, anyway, it actually turned out it is only partly solved. I had the HPET enabled as well - the HPET described in that article which I think is a normal feature of modern chips.
To enable it you open up an admin level command prompt and type:
bcdedit /set useplatformclock true
then you need to reboot.
This requires Vista or later.
You know it is enabled if QueryPerformanceFrequency gives you a frequency in the range of 14+ MHz. You might possibly need to enable it in the BIOS as well.
To disable you do the same and type
bcdedit /deletevalue useplatformclock
and reboot.
It's disabled by default. Which seems surprising since it improves multimedia performance - or should - but from the forums it seems some users have issues including reduced performance of some games and mouse pointer "ghosting" and some report freezes with it enabled in the forums. So they might have decided it is more trouble than it is worth to have it enabled by default.
So - with HPET enabled and using the interrupt timer I get this perfect timing.
Actually turns out the interrupt timer changes only once every ms on my computer (roughly) and stays steady in between those calls. So I suppose on some other computers might change less often.
So though very fast look up, you wouldn't probably use it for code performance testing. I'm planning to use it most of the time, but to use the QueryPerformanceCounter(..) for the last couple of ms of the loop just to time fractional ms increments, if required (or for longer if it turns out to have larger increments than 1 ms).
Also bug fix in the previous code, seems you have to do this every time you check it:
for(;;)
{
ts.SysTime.High1Time = USER_SHARED_DATA->InterruptTime.High1Time;
ts.SysTime.LowPart = USER_SHARED_DATA->InterruptTime.LowPart;
if(ts.SysTime.High1Time == USER_SHARED_DATA->InterruptTime.High2Time);
break;
ntests++;
}
On the backwards timers, there is one thing to be careful about - this caught me out - if you have a multi-threaded app with different threads calling the time simultaneously it might seem to run backwards just because you are using the previously recorded time of one thread and comparing it with the current time of the current time. I fixed that by using thread local variables to check the previously recorded time.
It turns out that that was the reason why I thought I had the time going backwards - not multiple cores or anything just a bug in the code for testing if the time was monotonic in a multi-threaded app.
Sorry about that!
Anyway - still have these timing issues for users who run my program on a computer with the OS set to not use the HPET - as it is by default. So - what I'd really like to know is if there is any way to access the HPET in the case where Windows isn't using it for timing itself? Is there some assembly language way for instance to get at its register even though Windows itself isn't using it?
Don't really think there is or surely someone would have posted a way to do it by now, and everyone would be doing it, but you never know .
|
|
|
|
|
Oh - still getting those reversed times
static Spec_Thread double ddwt_was;
if(ddwt_was!=0)
if(ddwt<ddwt_was)
ddwt=ddwt;
ddwt_was=ddwt;
ddwt 22589372.894629
ddwt_was 22589372.895075
And this is fixed using:
{
DWORD threadAffMask=SetThreadAffinityMask(GetCurrentThread(),1);
QueryPerformanceCounter(&HPT_PerformanceCount);
SetThreadAffinityMask(GetCurrentThread(),threadAffMask );
}
So - seems - that code actually does work, you don't need to do it for the entire thread, just with every call as in the example code.
Sorry for the confusion.
So - seems - here anyway - that you can get time reversals if you let the time be measured on any core.
You avoid them if you access the interrupt timer via KUSER_SHARED_DATA though that doesn't have the same resolution on my computer as the QueryPerformanceCounter (only changes every 1ms - though it seems likely that it reports the exact time at the moment that it changes - so you could time an exact ms by just waiting in a busy loop for it to change).
But to get the clocks running at a constant rate you need to force the OS to use HPET. Doesn't seem to be anyway for a program to access HPET if Windows isn't using it as far as I can see anyway.
HPET is guaranteed, on Intel machines anyway, to be accurate to 0.05 % over 1 ms and
http://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf[^]
|
|
|
|
|
I don't know if you're aware that HPET implementation on some motherboards are flaky, in particular AMD Chipsets, may also have problems with boards that have SMI incorrectly generating too many interrupts.
Take a look at the foot of the Wiki page for High Performance Event Timer
Linus Torvald's rant:
HPET grumbles
windows/hardware/gg463347.aspx
Lastly, some source code you might wish to take a look at ($0.00)
zip
I did wonder if you might want to look at the source code for VirtualBox with has options to enable HPET features for VMs.
--* OFF TOPIC & Previously touched upon *--
There have been problems with multi-core timer issues, and apparently there is serialized cpu instruction to avoid out-of-order execution affecting timer readings. RDTSC (not serialized) RDTSCP (new)
"It's true that hard work never killed anyone. But I figure, why take the chance." - Ronald Reagan
That's what machines are for.
Got a problem?
Sleep on it.
|
|
|
|
|
Oh right, maybe that is why some users have issues enabling HPET while others find it works just fine for them.
When it comes to musicians, if this is indeed the best way to achieve sub-millisecond precision on Windows with true exact timing - well they might well when buying new computers choose to buy one that can have the HPET enabled without causing problems. You often get exchange of notes and musicians asking each other which computer makes in their experience work best for music making. Normally ones that score well for silence, and latency and DPC. But this seems another thing to add to the list.
It is hard to over-stress how important it is for musicians to be able to play midi notes and record them with sub millisecond precision, and at least - not with multi-millisecond errors.
I just checked it up, I think from this post that RDTSCP is just like RDTSC except that it also tells you the processor id.
Example assembly code here The Terran Comedy[^]
But so long as you don't mind forcing your thread to go to core 1 whenever it checks the time, then SetThreadAffinityMask seems the way to go - I was wrong earlier when I said it seemed that the thread has to sleep first before it works, that was that bug in my own code.
It seems to work instantly somehow - does this mean the scheduler instantly moves the thread to the other core?
I suspect that probably it looks ahead in the code and when it sees a SetThreadAffinityMask in the near future moves it to another core in anticipation.
|
|
|
|
|
Hi
Please Please somebody post comprehensive series in win32 API programming with visual c++ 2012.
I need it urgently since without the knowledge of it iam having problem in my programming career.
Please make it simple and cover all topics from easy to intermediate to advanced.
regards
|
|
|
|
|
naseer861 wrote: post comprehensive series in win32 API
In a forum posting? Are you serious? Do you even realize how huge the Win32 API is?
|
|
|
|
|
Dude i am not talking about the huge API
atleast start from the basic.
Somethings are understood as obviuos.
|
|
|
|
|
(something is probably lost in translation)
You are asking for a C++ Win32 guide that covers ALL topics from easy to intermediate to advanced ?
What did your own research on the subject returned ? did you go to a library ? what did google/bing returned ?
Nihil obstat
|
|
|
|
|
|
Need a free image library that can handle png xresolution and yresolution.
I need it to be compatible with visual studio 6.0
I greatful for your help.
Sincerely
Andla
Need a free image library that can handle png xresolution and yresolution.
I need it to be compatible with visual studio 6.0
I greatful for your help.
Sincerely
Andla
|
|
|
|
|
|
This[^] one is pretty good ... hope it helps ...
|
|
|
|
|
Hi,
I have narrowed down my CfileDIalog problem as to have something to do with MSCOWRKS.DLL
Does anyone know the pourpose of this DLL can it be removed and is there a way of removing it from my
MFC C++ app
Thanks
|
|
|
|
|
As far as I can ascertain (as suggested previously) this is part of the .NET framework so should not be included in an MFC project. If you are trying to mix MFC with Winforms (C++/CLI) you will have problems.
Use the best guess
|
|
|
|
|
I will try to re-do my project
Thanks
|
|
|
|
|
I already told you before that this DLL was part of .Net and shouldn't even be in an MFC/C++ application (unless you put it there on purpose). You probably made a .Net project inadvertently.
|
|
|
|
|
Hi all,
on dialog box i have a static contol i want to fit its width according to its text when dialog box is open or text change .
i use this but the control width is set less than text width..
CString strText;
m_label.GetWindowText(strText);
CClientDC dc(this);
CFont* pFont = GetFont();
CFont* pOldFont = (CFont*)dc.SelectObject(pFont);
CSize sizeText = dc.GetTextExtent(strText);
dc.SelectObject(pOldFont);
CRect rcText;
m_label.GetWindowRect(rcText);
CRect dlg_stc=rcText;
this->ScreenToClient(dlg_stc);
rcText = dlg_stc;
rcText.right = min(rcText.right, sizeText.cx);
CRect new_rect=rcText;
m_label.MoveWindow(new_rect);
can anybody help me to do this.
thanks.
modified 13-Mar-13 3:14am.
|
|
|
|
|
I have had a similar issue in the past and used the GetTextExtentPoint32() function. I also found it necessary to add the size of a couple of extra characters as the calculation seems very precise.
Use the best guess
|
|
|
|
|
Richard MacCutchan wrote: I have had a similar issue in the past and used the
GetTextExtentPoint32() function. I also found it necessary to add
the size of a couple of extra characters as the calculation seems very precise.
this also gives the same width.
|
|
|
|
|
Le@rner wrote: rcText.right = min(rcText.right, sizeText.cx);
try this for the above statement,
rcText.right = rcText.left + sizeText.cx
and try to avoid using unwanted temporary variables, you can simply have as below,
CRect rcLabel;
m_label.GetWindowRect(rcLabel); rcLabel.right = rcLabel.left + sizeText.cx; ScreenToClient(rcLabel); m_label.MoveWindow(rcLabel);
Do your Duty and Don't Worry about the Result
|
|
|
|
|
|
I have downloaded IVT library ( Integrating Vision Toolkit), I made my app dependent on this library ( as DSP project in VC6.0) , I can partially compile the app because I get "permission denied" when I get to #include preprocessor statement.
I have checked the directory permissions and I have grayed out "read only" checked in IVT directory.
All of the sources I used so far said that such grayed out "read only" checked ( in XP) does not make any difference (?) when directories are involved.
All of my app directories have that grayed out "read only" checked and I have no problem including other (OpenCV) libraries.
I am tempted to recopy / re-download the IVT files , but would like to hear from the forum what is going on here.
Appreciate any advise.
Cheers
Vaclav
Addendum
Here is the real code snippet
I must be doing something really stupid.
#pragma message("include IVT ")
#include <Z:\Program Files\IVT\ivt-1.3.19\IVT\src> // fails
#include <Z:\Program Files\IVT\ivt-1.3.19\IVT\src\Calibration> // fails
#include <Z:\Program Files\IVT\ivt-1.3.19\IVT\src\Calibration\Calibration.h> // OK
|
|
|
|