系统时钟分辨率 [英] System clock resolution

查看:543
本文介绍了系统时钟分辨率的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个可以在短时间内(少于1毫秒)激活的计时器.

我从www.sysinternals.com找到了一个名为"ClockRes v2.0"的应用程序.
该应用程序报告了

最大计时器间隔15.6毫秒
最小计时器间隔0.5毫秒
当前计时器间隔15.6 ms.

这意味着可以更改系统时钟分辨率.但是我失败了.

接下来,我尝试使用此代码创建计时器.(从注册表读取频率,禁用CPU Boost Speed和多线程技术)

I''m trying to create a timer that activate in a small time(less than 1ms).

I found a application from www.sysinternals.com called "ClockRes v2.0"
That application reported

Maximum timer Interval 15.6 ms
Minimum timer Interval 0.5 ms
Current timer Interval 15.6 ms.

That means, It''s possible to change system clock resolution.but I''m fail.

Next, I try this code to create my timer.(read freq from registry,disabled CPU Boost Speed and multithread technology)

void MicroTmr(double ms)
{
	unsigned __int64 start_in = 0;
	unsigned __int64 stop_in= 0;
	if (!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS))
		 cout << "Set Prioity Class Fail. " << endl;
		start_in = __rdtsc();
		while(true)
		{
			stop_in = __rdtsc();
			if (stop_in-start_in > freq/1000*ms)
				break;
		}
		start_in = 0;
		stop_in = 0;
}



但是,如果我将此功能设置为与程序位于同一内核中,则此功能将极大地干扰程序.(我也将程序的优先级设置为REALTIME_PRIORITY_CLASS)

我的问题是:
1.如何更改系统时钟分辨率?
2.如何保护我的程序不受干扰?
3.有什么方法可以在短间隔(小于1毫秒)内使用计时器

非常感谢您的回答.



but, If I set this function and my program in a same core this function will extremely disturb my program.(I set my program''s priority at REALTIME_PRIORITY_CLASS too)

My question is :
1. How can I change system clock resolution?
2. How can I protect my program from the disturbance?
3. Are there any ways to use timer in a small interval(Less than 1ms)

Very thank you for your answer.

推荐答案

1.该实用程序使用函数::GetSystemTimeAdjustment来获取间隔.而且,按预期,::SetSystemTimeAdjustment可以更改间隔.

2.使用非常高的优先级是一个非常糟糕的主意.您可以锁定完整的系统.您可以使用::QueryPerformanceCounter以更高的分辨率测量时间跨度. CodeProject上有一些有关性能计数器的文章.

3.如果您只想测量时间,使用::QueryPerformanceCounter可能会解决您的问题.如果您需要在特定的非常短的时间后采取某种措施,则事情会变得更加复杂.


我必须纠正对第一项的回答. ::GetSystemTimeAdjustment只能用于获取当前计时器间隔,而::SetSystemTimeAdjustment不能用于设置它.为了得到最小.和最大值和更改间隔,可以使用未记录的功能NtQueryTimerResolution()NtSetTimerResolution().这些功能没有关联的导入库.使用GetModuleHandle()GetProcAddress()动态链接到 Ntdll.dll .可以使用GetModuleHandle()而不是LoadLibrary(),因为 Ntdll.dll 已由应用程序加载:

1. The utility uses the function ::GetSystemTimeAdjustment to get the intervals. And, as expected, ::SetSystemTimeAdjustment can change the interval.

2. Using very high priorities is a very bad idea. You can lock your complete system. You may use ::QueryPerformanceCounter to measure time spans with higher resolutions. There are some articles here at CodeProject about the Performance Counter.

3. If you only want to measure times, using ::QueryPerformanceCounter may solve your problem. If you need some kind of action after a specific very short time, things are more complicated.


I must correct my answer to the first item. ::GetSystemTimeAdjustment can be only used to get the current timer interval and ::SetSystemTimeAdjustment can''t be used to set it. To get also the min. and max. values and change the interval, the undocumented functions NtQueryTimerResolution() and NtSetTimerResolution() can be used. These functions have no associated import library. Use GetModuleHandle() and GetProcAddress() to dynamically link to Ntdll.dll. GetModuleHandle() can be used rather than LoadLibrary() because Ntdll.dll has been loaded by the app:

typedef NTSTATUS (CALLBACK* LPFN_NtQueryTimerResolution)(PULONG,PULONG,PULONG);
typedef NTSTATUS (CALLBACK* LPFN_NtSetTimerResolution)(ULONG,BOOLEAN,PULONG);

HMODULE hNtDll = ::GetModuleHandle(_T("Ntdll"));
if (hNtDll)
{
    ULONG nMinRes, nMaxRes, nCurRes;
    LPFN_NtQueryTimerResolution pQueryResolution = 
        (LPFN_NtQueryTimerResolution)::GetProcAddress(hNtDll, "NtQueryTimerResolution");
    if (pQueryResolution &&
        pQueryResolution(&nMinRes, &nMaxRes, &nCurRes) == STATUS_SUCCESS)
    {
        TRACE(_T("NT timer resolutions (min/max/cur): %u.%u / %u.%u / %u.%u ms"), 
            nMinRes / 10000, (nMinRes % 10000) / 10,
            nMaxRes / 10000, (nMaxRes % 10000) / 10,
            nCurRes / 10000, (nCurRes % 10000) / 10);
    }
    LPFN_NtSetTimerResolution pSetResolution = 
        (LPFN_NtSetTimerResolution)::GetProcAddress(hNtDll, "NtSetTimerResolution");
    if (pSetResolution && nSetRes)
    {
        NTSTATUS nStatus = pSetResolution(nSetRes, TRUE, &nCurRes);
    }
}


Windows没有提供一种内置的方式来触发事件,精确到至少5毫秒(最多5毫秒). (但请参见 timeGetTime timeBeginPeriod QueryPerformanceCounter
Windows gives no built-in way of setting off events with a precision greter than (at best) 5 ms. (But see timeGetTime, timeBeginPeriod and timeEndPeriod for a possible way of measuring with ms precision.)

If you want to measure time with high precision, use the high-resolution performance counter. See QueryPerformanceCounter and QueryPerformanceFrequency. I guess you could make a polling function and put it in a worker thread where it could signal a semaphore or call a function pointer or something.

However, there''s no guarantee that any given system has a high-resolution performance counter, and if yours don''t, you''re out of luck.


这篇关于系统时钟分辨率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆