カーネル内での特定処理にかかる時間を測定
NetBSD 1.6でカーネル内での特定処理にかかる時間を測定しようと思ったのだが、そういう仕組みは入ってなさそうだったので、Quick & Dirtyに書いてみた。
コード
#define MEASURE_TIMES 10000 typedef struct { int id; int time; unsigned start[MEASURE_TIMES]; unsigned end[MEASURE_TIMES]; } measure_record_t; static void measure_get_diff(measure_record_t *r, unsigned *diff); static void measure_dump(measure_record_t *r); static unsigned measure_diff_min(unsigned *array); static unsigned measure_diff_max(unsigned *array); static unsigned measure_diff_median(unsigned *array); static unsigned measure_diff_average(unsigned *array); static void qsort(void *a, size_t n, size_t es, int (*cmp) __P((const void *, const void *))); static inline int measure_start(measure_record_t *r) { if(r->time < MEASURE_TIMES) { r->start[r->time] = cpu_counter32(); return r->time++; } return -1; } static inline void measure_end(measure_record_t *r, int time) { KASSERT(r->time != -1); r->end[time] = cpu_counter32(); if(time == MEASURE_TIMES - 1) { measure_dump(r); r->time = 0; } } static void measure_dump(measure_record_t *r) { unsigned diff[MEASURE_TIMES] = {0}; measure_get_diff(r, diff); printf("id:%d min:%u max:%u median:%u average:%u\n", r->id, measure_diff_min(diff), measure_diff_max(diff), measure_diff_median(diff), measure_diff_average(diff)); } static void measure_get_diff(measure_record_t *r, unsigned *diff) { int i; for(i = 0; i < MEASURE_TIMES; i++) diff[i] = r->end[i] - r->start[i]; } static unsigned measure_diff_min(unsigned *array) { unsigned res = UINT_MAX; int i; for(i = 0; i < MEASURE_TIMES; i++) if(array[i] < res) res = array[i]; return res; } static unsigned measure_diff_max(unsigned *array) { unsigned res = 0; int i; for(i = 0; i < MEASURE_TIMES; i++) if(array[i] > res) res = array[i]; return res; } static int unsigned_cmp(const void *_a, const void *_b) { unsigned a = *(unsigned *)_a; unsigned b = *(unsigned *)_b; if(a < b) return -1; else if(a > b) return 1; return 0; } static unsigned measure_diff_median(unsigned *array) { qsort(array, MEASURE_TIMES, sizeof(unsigned), unsigned_cmp); return array[MEASURE_TIMES / 2]; } static unsigned measure_diff_average(unsigned *array) { unsigned long long sum = 0; int i; for(i = 0; i < MEASURE_TIMES; i++) sum += array[i]; return (unsigned)(sum / (unsigned long long)MEASURE_TIMES); }
使い方
measure_record_t mr0 = {0,}; /* 変数準備 0としているのは識別用ID */ int mt0 = measure_start(&mr0); /* 測定開始 */ hoge(); /* 測定対象 */ measure_end(&mr0, mt0); /* 測定終了 */
ものすごく汚いが、mbufにm->m_pkthdr.measure_timeとかでっち上げ
m->m_pkthdr.measure_time = measure_start(&mr0);
として、別のコンテキストから
measure_end(&mr0, m->m_pkthdr.measure_time);
とかやるとどこからどこへ流れてる間にどの程度時間がかかったのかパケット毎に追跡出来る。
はず。
netisr(softint)を跨ぐ追跡がやりたかったのでこんな風にしてみましたが何か。
ちなみにqsortはカーネルにリンクされてる筈がないので、libcからぶんどってきた。