High-precision timing, extended Second Edition

Source: Internet
Author: User

I have written a text about the latency and timing accuracy in windows, A latency and timing method is provided by embedding assembly code to read the CPU instruction period register in milliseconds. (See Region. However, the Code was implemented as a VC ++ dynamic link library, and I always wanted to rewrite it into a C ++ class. Today, I finally got started. The reason was that a person on the wxWidgets Forum was asking this question, which finally aroused my interest. So I overcame the inertia and moved my hand. Design goal: compile both in VC ++ and GCC. To achieve this goal, we must first solve two problems: 1. The methods for declaring 64-bit integer in VC ++ and GCC are different. VC ++ is _ int64, and GCC is long. 2. The methods of VC ++ and GCC Embedded Assembly are different. GCC uses at&t assembly, while VC ++ uses Intel assembly. To solve these two problems, determine the Conditional compilation, use the _ msc_ver macro to determine whether the compiling environment is VC ++ or GCC. If the _ msc_ver macro exists, it indicates that it is a VC ++ environment.

The Code is as follows:
asmdelay.h 
---------------------------------------------------- 
// Exact timing class. // Function 1: Obtain CPU clock speed (MHz) // function 2: precise latency (milliseconds) // Function 3: precise timing (milliseconds) // compile: VC ++/GCC // Note: for compiling under VC ++, enter the settings of the current project and select asmdelay. CPP, select the C/C ++ tab, select precompiled headers from the category combo box, and select not using precompiled headers.
#ifndef __ASMDELAY_h__24687444848486484894589754#define __ASMDELAY_h__24687444848486484894589754
#ifdef _MSC_VER typedef unsigned __int64 __UINT64;#else typedef unsigned long long __UINT64;#endif
Class casmdelay {PRIVATE: Unsigned long m_freq; // CPU clock speed _ uint64 m_timestamp; // The CPU timestamp int getfrequency (void) when the timer is enabled ); // function for calculating CPU clock speed _ uint64 getcyclecount (); // read the CPU command cycle register public: Unsigned long getcpufreq (); // view CPU clock speed casmdelay ();~ Casmdelay (); void msdelay (long MS); // millisecond-level latency void startcalculagraph (); // start the timer long stopcalculagraph (); // end the timer, and return the number of milliseconds from startup to shutdown .};
#endif
---------------------------------------------------- 
asmdelay.cpp 
---------------------------------------------------- 
#include "asmdelay.h"#include "windows.h"
CAsmDelay::CAsmDelay(){    m_Freq = GetFrequency();}
CAsmDelay::~CAsmDelay(){}
unsigned long CAsmDelay::GetCPUFreq(){    return m_Freq;}
_ Uint64 casmdelay: getcyclecount () // read the CPU instruction period register {volatile _ uint64 cyclecount;
#ifdef _MSC_VER __asm RDTSC __asm mov DWORD PTR CycleCount, EAX __asm mov DWORD PTR (CycleCount+4), EDX return CycleCount;#else    volatile unsigned long lo=0,hi=0,    *phi=((unsigned long *)(&CycleCount)) + 1,    *plo=(unsigned long *)&CycleCount;
 __asm__ ("RDTSC");    __asm__  __volatile__ ("movl %%eax,%0; movl %%edx,%1;"                        :"=r"(lo),"=r"(hi)::"%eax","%edx");
    *phi=hi;    *plo=lo;    return CycleCount;#endif
}
// Obtain the internal function of CPU frequency // mhzint casmdelay: getfrequency (void ){
 _LARGE_INTEGER CurrTicks, TicksCount; __UINT64 iStartCounter, iStopCounter;
 unsigned long dwOldProcessP = GetPriorityClass(GetCurrentProcess()); unsigned long dwOldThreadP = GetThreadPriority(GetCurrentThread());
 SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
 QueryPerformanceFrequency(&TicksCount); QueryPerformanceCounter(&CurrTicks);
 TicksCount.QuadPart /= 16; TicksCount.QuadPart += CurrTicks.QuadPart;
 iStartCounter=GetCycleCount();
 while(CurrTicks.QuadPart<TicksCount.QuadPart) QueryPerformanceCounter(&CurrTicks);
 iStopCounter = GetCycleCount();
 SetThreadPriority(GetCurrentThread(), dwOldThreadP); SetPriorityClass(GetCurrentProcess(), dwOldProcessP);
 return (int)((iStopCounter-iStartCounter)/62500);
}
Void casmdelay: msdelay (long MS) {// convert the number of milliseconds to the number of clock cycles _ uint64 msectocycle = (m_freq * 1000) * MS; // record the current clock cycle _ uint64 TMR = getcyclecount (); // delay until the number of clock cycles meets the predefined Number of milliseconds; while (getcyclecount ()-TMR <msectocycle) {}}
Void casmdelay: startcalculagraph () // start timer {m_timestamp = getcyclecount () ;}long casmdelay: stopcalculagraph () // end timer, and return the number of milliseconds from startup to shutdown. {_ Uint64 timestampdiff = getcyclecount ()-m_timestamp; return timestampdiff/(m_freq * 1000 );}
---------------------------------------------------- 
Test Project:
http://wxforum.shadonet.com/download.php?id=731
Description: code for millisecond-level latency and timing.
Compiler compatibility: VC ++/GCC
Project included:. Dev can be compiled using wxdev-C ++
. DSW can be compiled with VC ++ 6
Two projects share asmdelay. cpp. h
Wxdev-C ++ and VC ++ interfaces:
 
-------------------------------------------------------------
Appendix: minor debugging experience in GCC Embedded Assembly:
1. at&t assembly is very different from Intel assembly. The mov command data type of at&t assembly is implemented with a suffix, such as movb movw movl.
In addition, the operands are copied from left to right, which is opposite to Intel assembly.
2. GCC generates assembly code through formatted strings, as shown in this article:
 
    __asm__ __volatile__ ("movl %%eax,%0; movl %%edx,%1;" 
 
                        :"=r"(lo),"=r"(hi)::"%eax","%edx"); 
The first part is a string: "movl % eax, % 0; movl % edX, % 1;", which is an assembly instruction and can contain multiple assembly instructions, separated;
Followed by the separator, followed by the second part, which is the output part (destination operand). Here, the C language variables can be connected, and each element of the output part is separated by commas, the first element corresponds to % 0, the second element corresponds to % 1, and so on.
In "= r", "=" indicates the output, "R" indicates the link register variable, or "G" indicates the register or memory variable, or "M" indicates the memory variable, when _ volatile _ exists, they have the same effect. For details, see 5.
Brackets are the connected high-level language variables.
The third part is the input part (source operand). Because the input part is not connected to the advanced language variable, it is omitted. Two consecutive parts:
The last part and the fourth part are the limitation registers that modify the registers in the first part.
3. If GCC enables Speed Optimization, it is best to use volatile to modify the advanced language variables in functions embedded with assembly code to ensure the running results are correct. Otherwise, the optimization will lead
The program allocates variables in the registers, while the Assembly often uses registers, which will inevitably lead to errors due to conflicts.
4. The _ volatile _ modifier tells the compiler that optimization is prohibited. Prevents the compiler from deleting or reorganizing Assembly commands.
5. constraint letters:
:"=r" (__dummy)
"= R" indicates that the target operand can use any common register, and the variable _ dummy is stored in this register, but if it is:
:“=m”(__dummy)
"= M" indicates that the target operand is stored in the memory unit _ dummy. Here R and m are called restricted letters.
There are many restricted letters. The following table lists the main restricted letters and their meanings:

Letter Description
M, V, O Memory Unit
R Indicates any general registers
Q One of the registers eax, EBX, ECx, and EDX.
I, h Represents the direct operand
E, F Floating Point Number
G Indicates "arbitrary"
A, B. c d Indicates that registers eax/ax/Al, EBX/BX/BL, ECx/CX/Cl or edX/dx/dl are required.
S, d Indicates that the Register ESI or EDI is required.
I Represents a constant (0 ~ 31)
 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.