2025年4月30日水曜日

C言語のforとマクロで簡単な時間計測

前回、処理時間計測の必要に駆られた。いちいち時間計測のコードを入れて回るのが面倒なので、forとマクロで簡単に計測した。

enum{
        SW_SH2,
        SW_HBIN,
        SW_HBOUT,
        SW_VBIN,
        SW_VBOUT,
        SW_SCSP,
        SW_SCU,
        SW_68K,
        SW_SMPC,
        SW_CDB,
        SW_SYNC,
        SW_MAX
};
static const char* swname[]={
        "SW_SH2",
        "SW_HBIN",
        "SW_HBOUT",
        "SW_VBIN",
        "SW_VBOUT",
        "SW_SCSP",
        "SW_SCU",
        "SW_68K",
        "SW_SMPC",
        "SW_CDB",
        "SW_SYNC",
        "SW_MAX"
};
static u64 swbuff_[SW_MAX];
static u64 start_time_ = 0;
static int sw_flag = 0;
#define SW(n) for(tick_start();sw_flag;tick_end(n))
static void tick_start()
{
        sw_flag=1;
        start_time_ = YabauseGetTicks();
}
static void tick_end(int n)
{
        u64 diff = YabauseGetTicks() - start_time_;
        swbuff_[n] += diff;
        sw_flag=0;
}
static void tick_clear()
{
        for(int i=0;i<SW_MAX;i++){
                swbuff_[i] = 0;
        }
}
static void tick_show()
{
        for(int i=0;i<SW_MAX;i++){
                printf("%d:%s: %llu\n", i, swname[i], swbuff_[i]);
        }
}
for文は最初と最後で文を実行できるので、これを利用して、tick_start()とtick_end()を呼び、sw_buff_に時間を足していく。tick_startでループ条件ON、tick_endでループ条件OFFとすれば、ループにならない。

こうしておけば以下のようにSW(番号){}で囲むと時間を計って加算してくれる。

SW(SW_SH2){
  計測したい処理(SH2)
}
SW(SW_SCU){
  計測したい処理(SCU)
}

新しいCならforの中で変数宣言できるので、工夫すれば入れ子で計測できたりしそうだが、そこまではやってない。

YabauseGetTicks()は現在時刻を取得するようなyabauseの関数で以下のようになっている。

u64 YabauseGetTicks(void) {
#ifdef WIN32
   u64 ticks;
   QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
   return ticks;
#elif defined(_arch_dreamcast)
   return (u64) timer_ms_gettime64();
#elif defined(GEKKO)
   return gettime();
#elif defined(PSP)
   return sceKernelGetSystemTimeWide();
#elif defined(ANDROID)
        struct timespec clock_time;
        clock_gettime(CLOCK_REALTIME , &clock_time);
        return (u64)clock_time.tv_sec * 1000000 + clock_time.tv_nsec/1000;
#elif defined(HAVE_GETTIMEOFDAY)
   struct timeval tv;
   gettimeofday(&tv, NULL);
   return (u64)tv.tv_sec * 1000000 + tv.tv_usec;
#elif defined(HAVE_LIBSDL)
   return (u64)SDL_GetTicks();
#endif
}

という事でやってみた結果、遅い処理はどうやらSH2とSCUのエミュレーション部分のようだった。

SH2部分はダイナミックリコンパイル(JITコンパイル?)されていて、もうこれ以上は早くならなそう。

SCUも同じような感じでコンパイルしなおせば早くなるのかもしれないが、かなり特殊な命令形態っぽいので、簡単にアセンブラに変換はできないような気がする。これ以上はもう無理か。。あと2倍くらい早いか倍のコア数がある端末ならば、何とかなりそうな気がするが。。

0 件のコメント:

コメントを投稿