1. microsecond delay must not be based on the message (SetTimer function), because the presence of a message jam will affect the fine
The SetTimer unit is the millisecond. The actual response time may be about 55 milliseconds.
2. microsecond delay can not be based on interrupts, VxD fastest clock service program Set_global_time_out function
To ensure accuracy of 1 milliseconds. Other hook int 8H interrupt processing function, etc., can only guarantee the accuracy of 55ms. (And sometimes not
Can
3. It is possible to think of the kind of delay that is based on the cyclic execution of statements in the Assembly. But the assembler code is not universal,
The frequency of the CPU.
So you can use a few functions under Windows to write a generic generation
Code. Gettickcout,timegettime,queryperformancecounter.
1) gettickcout response can only guarantee the accuracy of 55MS
2) timeGetTime can only guarantee the accuracy of 1ms
3) Instead of counting the number of interrupts, the QueryPerformanceCounter function relies on reading other hardware clocks to
Can have a precision of 0.8 microseconds. This system does not support systems under Windows 95, but these systems should be
No one has to use it.
Here is the sample code:
The Large_integer type is similar to a 64-bit integer, which is a union with longlong type and two
A long composition of the Union of the struct.
The QueryPerformanceFrequency function gets the high-precision timer in your computer how many times per second,
The parameter large_integer, which returns FALSE, indicates that your current computer hardware does not support high-precision timers.
The QueryPerformanceCounter function gets the number of times the current timer has been recorded. similar to Gettickcout.
#include <windows.h>
#include <iostream>
using namespace Std;
void Main () {
int delaytime = 20; Microsecond-level delay.
Large_integer m_liperffreq={0};
if (! QueryPerformanceFrequency (&m_liperffreq))
{
cout << "Your current computer hardware does not support high-precision timers" <<endl;
Return
}
Large_integer m_liperfstart={0};
QueryPerformanceCounter (&m_liperfstart);
Large_integer liperfnow={0};
for (;;)
{
QueryPerformanceCounter (&liperfnow);
Double Time= ((Liperfnow.quadpart-
M_liperfstart.quadpart) *1000000)/(double) m_liperffreq.quadpart);
if (Time >= delaytime)
Break
}
Cout.precision (40);
cout << start << (double) M_liperfstart.quadpart <<endl;
cout << End << (double) Liperfnow.quadpart <<endl;
cout<< "Time Precision" << (1/(double) m_liperffreq.quadpart) *1000000<< "Microsecond" <<endl;
cout << "Delay" << ((Liperfnow.quadpart-m_liperfstart.quadpart)
*1000000)/(double) m_liperffreq.quadpart) << "Microsecond" <<endl;
}
Because Windows is a multitasking system, as long as you ensure that Windows executes this code without being interrupted by other processes, you can
Guaranteed latency microsecond success. There is a small chance of interruption. Generally not considered. If code execution time is less than one
A time slice, then 100% will not be interrupted.
In the SDK, you can use the DWORD timeGetTime (VOID) function to get the system time, whose return value is in millisecond units. Functions that can be used to implement the delay function.
void Delay (DWORD delaytime)
{
DWORD Delaytimebegin;
DWORD Delaytimeend;
Delaytimebegin=timegettime ();
Do
{
Delaytimeend=timegettime ();
}while (Delaytimeend-delaytimebegin<delaytime)
}
Note: Before using timeGetTime, you should include the header file #i nclude <Mmsystem.h> or #i nclude <Windows.h> and project->settings->link- Add Winmm.lib in >object/library modules
You can also add #pragma comment (lib, "Winmm.lib") to the file header
Command line: Precompiled processing Instructions #pragma comment (lib, "Xxx.lib"), allowing the VC to add Winmm.lib to the project for compilation.
In the Windows platform, there are two commonly used timers, one is the timeGetTime multimedia timer, which can provide millisecond-level timing. But this precision is too coarse for many applications. The other is the Queryperformancecount counter, which can provide a microsecond count depending on the system. For real-time graphics processing, multimedia data stream processing, or real-time system construction programmers, the use of queryperformancecount/queryperformancefrequency is a basic skill.
In this paper, we will introduce another high-precision timing method that directly utilizes the Pentium CPU internal timestamp. The following discussion is mainly due to the book "Windows graphics Programming", page 15th-page 17, interested readers can directly refer to the book. For a detailed discussion of the RDTSC directive, refer to the Intel Product manual. This article is only used for throwing bricks.
In the Intel Pentium CPU, there is a part called timestamp (Time Stamp), which records the number of clock cycles that have elapsed since the CPU was power-up, in the format of 64-bit unsigned integers. Because the current CPU frequency is very high, so this component can achieve the nanosecond level of timing accuracy. This accuracy is unmatched by the above two methods.
In CPUs above Pentium, a machine instruction RDTSC (read time Stamp Counter) is provided to read the number of the timestamp and save it in the EDX:EAX register pair. Since the EDX:EAX register is the register that exactly is the C + + language saving function return value in the Win32 platform, we can think of this instruction as a normal function call. Like this:
inline unsigned __int64 getcyclecount ()
{
__asm RDTSC
}
But no, because RDTSC is not directly supported by C + + inline assembler, so we want to embed the instruction directly in the machine code form 0x0f, 0X31 with _emit pseudo-directive, as follows:
inline unsigned __int64 getcyclecount ()
{
__asm _emit 0x0F
__asm _emit 0x31
}
In the future where counters are needed, you can call the two-getcyclecount function as you would with a normal Win32 API, comparing the difference of two return values, like this:
unsigned long T;
t = (unsigned long) getcyclecount ();
Do Something time-intensive ...
T-= (unsigned long) getcyclecount ();
The 15th page of Windows graphics programming has written a class that encapsulates this counter. Interested readers can refer to the code of that class. For more accurate timing, the author made a small improvement, the execution of the RDTSC instruction time, through the two consecutive calls to Getcyclecount function calculated and saved up, after each time after the end of the actual count to reduce the time to get more accurate timing numbers. But I personally think this little improvement is not very significant. Measured on my machine, this instruction takes about dozens of to 100 cycles, which is just one-tenth microseconds on a Celeron 800MHz machine. For most applications, this time is completely negligible, and the compensation is too coarse for applications that really need to be accurate to nanosecond orders of magnitude.
The advantages of this method are:
1. High precision. The nanosecond-level timing accuracy can be achieved directly (each clock cycle on a 1GHz CPU is a nanosecond), which is difficult to achieve with other timing methods.
2. Low cost. The timeGetTime function requires a link to the multimedia library winmm.lib,queryperformance* function according to MSDN instructions that require hardware support (although I have not seen unsupported machines) and kernel library support, So both can only be used under the Windows platform (for high-precision timing issues under the DOS platform, refer to the graphical program Developer's Guide for a detailed description of control timer 8253). But the RDTSC instruction is a CPU instruction, generally the i386 platform Pentium above the machine all supports, even does not have the platform limit (I believe I386 version Unix and Linux This method also applies, but does not have the condition experiment), and the function calls the overhead is the smallest.
3. With the CPU frequency directly corresponding to the rate relationship. A count is equivalent to 1/(CPU frequency Hz) seconds, so as long as you know the CPU frequency, you can directly calculate the time. This differs from Queryperformancecount, which requires QueryPerformanceFrequency to obtain the current counter count number of times per second in order to be converted into time.
The disadvantages of this approach are:
1. Most of the existing C + + compilers do not directly support the use of RDTSC instructions, and need to be programmed directly into the machine code, more cumbersome.
2. Data jitter is rather severe. In fact, for any measurement means, precision and stability is always a pair of contradictions. If you use low-precision timegettime to time, basically the results of each timing is the same, and the RDTSC command each time the results are different, there are often hundreds of or even thousands of gaps. This is the inherent contradiction of the high precision of this method.
For the maximum length of the timing of this method, we can simply calculate it with the following formula:
Number of seconds since CPU power = number of cycles read RDTSC/CPU main frequency rate (HZ)
The largest number that can be expressed by a 64-bit unsigned integer is 1.8x10^19, which can be timed for about 700 years on my Celeron 800 (the book says it can be timed for 117 years on a 200MHz Pentium, and this number does not know how it came out, which is not the same as my calculations). In any case, we don't have to be concerned about the overflow problem.
Here are a few small examples, a brief comparison of the usage and accuracy of three timing methods
Timer1.cpp the definition of the Timer class//ktimer class using the RDTSC directive can be found in Windows graphics programming P15
Compile line: CL timer1.cpp/link USER32.lib
#include <stdio.h>
#include "KTimer.h"
Main ()
{
unsigned t;
Ktimer timer;
Timer. Start ();
Sleep (1000);
t = Timer. Stop ();
printf ("Lasting time:%d/n", t);
}
Timer2.cpp uses the timeGetTime function
Need to contain <mmsys.h>, but due to the intricate relationship of Windows header files
Easy to include <windows.h> less lazy:)
Compile line: CL timer2.cpp/link winmm.lib
#include <windows.h>
#include <stdio.h>
Main ()
{
DWORD T1, T2;
T1 = timeGetTime ();
Sleep (1000);
T2 = timeGetTime ();
printf ("Begin Time:%u/n", T1);
printf ("End Time:%u/n", T2);
printf ("Lasting time:%u/n", (T2-T1));
}
Timer3.cpp uses the QueryPerformanceCounter function
Compile line: CL timer3.cpp/link KERNEl32.lib
#include <windows.h>
#include <stdio.h>
Main ()
{
Large_integer T1, t2, TC;
QueryPerformanceFrequency (&TC);
printf ("Frequency:%u/n", TC. QuadPart);
QueryPerformanceCounter (&T1);
Sleep (1000);
QueryPerformanceCounter (&T2);
printf ("Begin Time:%u/n", T1. QuadPart);
printf ("End Time:%u/n", T2. QuadPart);
printf ("Lasting time:%u/n", (T2. Quadpart-t1. QuadPart));
}
////////////////////////////////////////////////
The above three sample programs are the time spent testing 1 seconds of hibernation
file://Test/test environment: Celeron 800mhz/256m SDRAM
Windows Professional SP2
Microsoft Visual C + + 6.0 SP5
////////////////////////////////////////////////
The following is the result of the operation of the Timer1, using a high-precision RDTSC instruction
Lasting time:804586872
The following is the result of the operation of the Timer2, using the most coarse timegettime API
Begin time:20254254
End time:20255255
Lasting time:1001
The following is the result of the Timer3 operation, using the Queryperformancecount API
frequency:3579545
Begin time:3804729124
End time:3808298836
Lasting time:3569712
Microsecond latency under Windows