/* * blitperf — микробенчмарк спрайтового пути: операций в секунду (RTC) * для каждого слоя цепочки putsprite/gfx_heal. Диагностика разрыва * с asm-референсом (examples/balls ~1.5 мс/шар при теории ~0.3 мс): * отделяет стоимость leaf'ов от C-обвязки (клип/банк/заголовок) и * даёт опорные точки (bar — давно оптимизированный accel-путь). * * Методика: измеряется число вызовов за одну RTC-секунду (старт по * смене секунды; время проверяется раз в 8 операций). Строка «empty» * — цена самого цикла (вызов пустышки + getdatetime/8) — вычитать из * остальных: t_op = 1/n_op - 1/n_empty. * * ВНИМАНИЕ: использует ВНУТРЕННИЕ символы libbgi (прототипы * продублированы ниже — сверять с libbgi/_bgi.h при изменениях ABI). * * Запуск: * python3 toolchain/mame_interactive.py tests/blitperf/blitperf.exe \ * --snap 22 --timeout 24 */ #include #include #include /* --- внутренности libbgi (копия из _bgi.h, НЕ публичный API) ------- */ extern uint16_t _gfx_addr_base; void _bgi_begin(void); void _bgi_end(void); void _bgi_heal_rows_raw(uint8_t *scr, int y0, uint8_t w, uint8_t h); void _bgi_copy_rows_raw(const uint8_t *src, uint8_t *dst, uint8_t w, uint8_t h, int dstride, int sstride, uint8_t y0); /* ------------------------------------------------------------------- */ #define BW 16 static uint8_t spr[4 + BW * BW]; static void build_sprite(void) { uint8_t *p = spr; int i; *p++ = BW; *p++ = 0; *p++ = BW; *p++ = 0; for (i = 0; i < BW * BW; i++) *p++ = (uint8_t)(LIGHTRED + ((i & 7) == 0)); /* без 0xFF */ } /* --- операции ------------------------------------------------------ */ static void op_empty(void) { } static void op_leaf_heal(void) /* leaf + W3-скобка, без C-обвязки */ { _bgi_begin(); _bgi_heal_rows_raw((uint8_t *)(_gfx_addr_base + 100), 100, BW, BW); _bgi_end(); } static void op_leaf_blit(void) /* copy-leaf + скобка, без обвязки */ { _bgi_begin(); _bgi_copy_rows_raw(spr + 4, (uint8_t *)(_gfx_addr_base + 100), BW, BW, 0, BW, 100); _bgi_end(); } static void op_gfx_heal(void) { gfx_heal(100, 100, BW, BW); } static void op_blit_part(void) { gfx_blit_part(100, 100, spr, 0, 0, BW, BW); } static void op_putsprite(void) { putsprite(100, 100, spr); } static void op_bar(void) /* опорная точка: accel-fill 16×16 */ { bar(100, 100, 100 + BW - 1, 100 + BW - 1); } /* --- измеритель ---------------------------------------------------- */ static uint16_t bench(void (*op)(void)) { datetime_t dt; uint8_t s0, k; uint16_t n = 0; getdatetime(&dt); s0 = dt.second; do { getdatetime(&dt); } while (dt.second == s0); /* синхр. к границе */ s0 = dt.second; for (;;) { for (k = 0; k < 8; k++) op(); n += 8; getdatetime(&dt); if (dt.second != s0) return n; } } static void say_num(int y, const char *tag, uint16_t v) { char buf[16]; uint8_t i; uint16_t d = 10000; for (i = 0; tag[i] && i < 9; i++) buf[i] = tag[i]; while (i < 10) buf[i++] = ' '; for (; d; d /= 10) buf[i++] = (char)('0' + (v / d) % 10); buf[i] = 0; setcolor(WHITE); outtextxy(4, y, buf); } int main(void) { build_sprite(); initgraph(); cleardevice(); setcolor(WHITE); outtextxy(4, 4, "BLITPERF ops/sec (16x16)"); say_num(20, "empty", bench(op_empty)); say_num(30, "leafheal", bench(op_leaf_heal)); say_num(40, "leafblit", bench(op_leaf_blit)); say_num(50, "gfx_heal", bench(op_gfx_heal)); say_num(60, "blitpart", bench(op_blit_part)); say_num(70, "putsprite", bench(op_putsprite)); say_num(80, "bar", bench(op_bar)); outtextxy(4, 96, "done"); for (;;) { } }