ナノ秒単位の高性能な時刻がほしい時

beagleboneやraspberry piで、ナノ秒単位の正確な時間がほしい時について。
通常のtime関数とかでは遅すぎて困るときは、以下のようにすると、ナノ秒単位で時刻が取れます。
値は、CPUとかの動作クロックの影響をうけるので注意してください。

ボード メモリ位置 バイト長
beaglebone 0x4804003C 4バイト
raspberry pi 2-3 0x3F003004 4バイト

このメモリ位置は常にカウントアップされていきます。
値はunsigned int値で、オーバーフローすると0に戻ります。
ここを読みだすことでとても正確な時間を取得することができます。
今何時?という用途にはまったく使えませんが、処理時間の間隔を正確に測るとかの用途に向いています。


カーネルランドで読みだす場合は、 ioremapが便利だと思う。

//ナノ秒単位の高性能な時刻がほしい時。
//kernel land
void *g_timer = ioremap(0x4804003C,4); //beaglebone
void *g_timer = ioremap(0x3F003004,4); //raspberry pi 2-3

//一番オーバーヘッドを生まないであろうマクロ展開で読みだす.
#define dmtimer_get()  ((unsigned int)ioread32(g_timer))

printk(KERN_ALERT "timer: %u\n", dmtimer_get() );

iounmap(g_timer);


ユーザランドで読みだす場合は、 mmapするよろし。

//ナノ秒単位の高性能な時刻がほしい時。
//userland
int g_fd = open("/dev/mem", O_RDWR | O_SYNC);
if (g_fd < 0)
{
	printf("Could not open /dev/mem fd\n");
	return -1;
}

//mmap確保
//0x3F003004 とかを直接mmapすると落ちるので、ちょい手前から 0x100ぐらい適当に確保する.
//void* g_mmap = ( unsigned int*) mmap(NULL, 0x100, PROT_READ,MAP_SHARED,g_fd, 0x48040000); //beaglebone
unsigned int* g_mmap = ( unsigned int*) mmap(NULL, 0x100, PROT_READ,MAP_SHARED,g_fd, 0x3F003000); //raspberry pi 2-3
if (g_mmap == MAP_FAILED) {
	printf("Could not mmap %d\n",g_mmap);
	close(g_fd);
	g_fd=0;
	return -2;
}
//unsigned int* g_timer = &g_mmap[0x3C/sizeof(int)]; //0x4804003C
unsigned int* g_timer = &g_mmap[0x4/sizeof(int)]; //0x3F003004

//一番オーバーヘッドを生まないであろうマクロ展開で読みだす.
#define dmtimer_get()  (*g_timer)

for(int i = 0 ; i < 10 ;i++)
{
	printf("timer: %u\n", dmtimer_get() );
	sleep(1);
}

//unmap(g_mmap)を呼び出さなくてもプロセス終了時には自動解放される 
close(g_fd);

この高性能タイマー機能の名前がよくわからないのだが、dmtimer とか、high level timer とか、いろいろ名前があるらしい。
検索しにくいから統一させてほしいものである。