我需要对 1 us 级别的精确计时来计时 pwm 波占空比的变化。
背景
我正在使用 Gumstix Over Water COM ( https://www.gumstix.com/store/app.php/products/265/ ),它有一个以 499.92 BogoMIPS 运行的单核 ARM Cortex-A8 处理器(Gumstix 页面声称根据 /proc/cpuinfo 到 1Ghz,建议使用 800Mhz)。该操作系统是基于内核版本 2.6.34 的 Angstrom Image 版本的 Linux,它在 Gumstix Water COM 上有库存。
问题
我已经阅读了大量关于 Linux 中精确计时的文章(并且已经尝试了大部分),并且共识似乎是使用 clock_gettime() 并引用 CLOCK_MONOTONIC 是最好的方法。(我本来希望使用 RDTSC 寄存器进行计时,因为我有一个具有最低节能能力的内核,但这不是英特尔处理器。)所以这是奇怪的部分,而 clock_getres() 返回 1,表明分辨率为 1 ns , 实际时序测试表明最小分辨率为 30517ns 或(不可能是巧合)恰好是 32.768KHz 时钟滴答之间的时间。这就是我的意思:
// Stackoverflow example
#include <stdio.h>
#include <time.h>
#define SEC2NANOSEC 1000000000
int main( int argc, const char* argv[] )
{
// //////////////// Min resolution test //////////////////////
struct timespec resStart, resEnd, ts;
ts.tv_sec = 0; // s
ts.tv_nsec = 1; // ns
int iters = 100;
double resTime,sum = 0;
int i;
for (i = 0; i<iters; i++)
{
clock_gettime(CLOCK_MONOTONIC, &resStart); // start timer
// clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts);
clock_gettime(CLOCK_MONOTONIC, &resEnd); // end timer
resTime = ((double)resEnd.tv_sec*SEC2NANOSEC + (double)resEnd.tv_nsec
- ((double)resStart.tv_sec*SEC2NANOSEC + (double)resStart.tv_nsec);
sum = sum + resTime;
printf("resTime = %f\n",resTime);
}
printf("Average = %f\n",sum/(double)iters);
}
(不要为双重转换而烦恼, tv_sec 在 time_t 和 tv_nsec 是很长的。)
编译:
gcc soExample.c -o runSOExample -lrt
运行:
./runSOExample
如图所示,将 nanosleep 注释掉后,结果为 0ns 或 30517ns,大多数为 0ns。这使我相信 CLOCK_MONOTONIC 在 32.768kHz 处更新,并且大部分时间在第二次 clock_gettime() 调用之前时钟尚未更新,并且在结果为 30517ns 的情况下,时钟已在两次调用之间更新。
当我在我的开发计算机(运行在 1.4 GHz 的 AMD FX(tm)-6100 六核处理器)上做同样的事情时,最小延迟是更恒定的 149-151ns,没有零。
因此,让我们将这些结果与 CPU 速度进行比较。对于 Gumstix,30517ns (32.768kHz) 相当于 499.93MHz cpu 的 15298 个周期。对于我的开发计算机,150ns 相当于 1.4Ghz CPU 的 210 个周期。
使用未注释的 clock_nanosleep() 调用,平均结果如下: Gumstix:平均值 = 213623,结果上下变化,以 30517ns 的最小分辨率的倍数 开发计算机:57710-68065 ns,没有明显的趋势。在开发计算机的情况下,我希望分辨率实际上处于 1 ns 水平,而测量到的 ~150ns 确实是两个 clock_gettime() 调用之间经过的时间。
所以,我的问题是:是什么决定了最小分辨率?当处理器的运行速度仅快 2.6 倍时,为什么开发计算机的分辨率比 Gumstix 高 30000 倍?有没有办法改变 CLOCK_MONOTONIC 的更新频率和位置?在内核中?
谢谢!如果您需要更多信息或说明,请询问。