いまさらベーシックマスターの開発環境を作ってみる(19) プロファイラを作ってみる(2)
いまさらベーシックマスターの開発環境を作ってみる(17) プロファイラを作ってみるで作ったプロファイラ、たいへん便利。時間喰ってるルーチンが簡単にわかるので、最適化しやすい。
調子に載って、メモリアクセス回数をカウントするように改造してみた。
bm2 emulator用のmemory profiler
前回と同じく bm2 を使っています。
起動時から終了時までのメモリアクセス回数を数えます。
あと、bm2では割り込み禁止(SEI)したときのIRQが消えてしまうようなので、dirty hack してみました。
(IRQはレベルトリガなので、CLIしたときにIRQ状態なら割り込みがかかるはず)
j68とは時間が合わないので、これはどうしたもんか。
diff -uNr bm2/Makefile bm2p/Makefile
--- bm2/Makefile 2016-11-13 11:39:45
+++ bm2p/Makefile 2024-07-14 13:25:32
@@ -3,7 +3,7 @@
OBJS = main.o m6800.o m6800asm.o bm2mem.o bm2sub.o sound.o util.o menu.o init.o depend.o sdlxpm.o srecord.o conf.o
# SDL2.0
-CFLAGS = -O3 -finline-limit-20000 -DM68_TRACE -DM68_SUB -Wall $(shell sdl2-config --cflags)
+CFLAGS = -O3 -finline-limit-20000 -DM68_TRACE -DM68_SUB -DM68_PROFILE -Wall $(shell sdl2-config --cflags)
LDFLAGS = -s $(shell sdl2-config --libs)
# SDL1.2
diff -uNr bm2/bm2config bm2p/bm2config
--- bm2/bm2config 2024-07-14 14:59:00
+++ bm2p/bm2config 2024-07-14 14:58:13
@@ -25,3 +25,6 @@
# キーボードの種類 (jp:日本語, en:英語, de:ドイツ語)
keyboard jp
+
+#
+profile y
diff -uNr bm2/bm2mem.c bm2p/bm2mem.c
--- bm2/bm2mem.c 2016-11-13 11:39:17
+++ bm2p/bm2mem.c 2024-07-19 09:18:11
@@ -15,8 +15,10 @@
struct Bm2stat *bm2;
/* メモリ */
- if(p <= 0xe7ff || p >= 0xf000)
+ if(p <= 0xe7ff || p >= 0xf000){
+ m68memprof(p);
return m68->m[p];
+ }
/* I/O */
bm2 = m68->tag;
@@ -67,6 +69,7 @@
int off;
if(p < 0xb000) { /* RAM */
+ m68memprof(p);
if(p <= bm2->ram_end)
m68->m[p] = x;
diff -uNr bm2/init.c bm2p/init.c
--- bm2/init.c 2016-11-13 11:38:40
+++ bm2p/init.c 2024-07-19 09:22:04
@@ -8,6 +8,8 @@
#include
#include
#include
+#include
+#include
#include "bm2.h"
/* キーボード */
@@ -752,6 +754,64 @@
};
/*
+ profiler
+*/
+int m68profile_sub(const char *filename, uint32_t **rmap)
+{
+ int fd;
+ uint32_t buf=0;
+ uint32_t *map;
+
+ fprintf(stderr,"m68profile open %s\n",filename);
+ fd = open(filename,O_RDWR|O_CREAT,0644);
+ if(fd<0){
+ perror("m68prof_sub open:");
+ exit(-1);
+ }
+ size_t len= 65536*sizeof(uint32_t);
+ lseek(fd,0,SEEK_SET);
+ for(int i=0; i<65536; i++){
+ write(fd,(char *)&buf,sizeof(buf));
+ }
+ lseek(fd,0,SEEK_SET);
+ fprintf(stderr,"m68profile mmap %s\n",filename);
+ map = (uint32_t *)mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
+ if(map==MAP_FAILED){
+ perror("mmap failed");
+ exit(-1);
+ }
+ fprintf(stderr,"m68profile map=%lx\n",(unsigned long)map);
+ fprintf(stderr,"m68profile init\n");
+ for(int i=0; i<65536; i++){
+ map[i]=0;
+ }
+ fprintf(stderr,"m68profile init end\n");
+
+ *rmap = map;
+ return fd;
+}
+
+void m68profile(const struct M68stat *m68)
+{
+ static uint32_t *map;
+ static int fd;
+
+ if(map==NULL){
+ fd = m68profile_sub("bm2profile.bin",&map);
+ }
+ map[m68->pc]++;
+}
+void m68memprof(uint16 p)
+{
+ static uint32_t *map;
+ static int fd;
+
+ if(map==NULL){
+ fd = m68profile_sub("bm2memprof.bin",&map);
+ }
+ map[p]++;
+}
+/*
ログを出力する
*/
void m68log(const struct M68stat *m68)
@@ -997,6 +1057,7 @@
/* トレースモードか? */
bm2->cpu.trace = getOptTable(conf, "debug", tableYesNo, FALSE);
+ bm2->cpu.profile = getOptTable(conf, "profile", tableYesNo, FALSE);
/* 画面の拡大率を設定する */
bm2->zoom = getOptInt(conf, "zoom", 2);
diff -uNr bm2/m6800.c bm2p/m6800.c
--- bm2/m6800.c 2016-11-13 01:14:04
+++ bm2p/m6800.c 2024-07-20 00:56:16
@@ -841,6 +841,8 @@
m68.total_states = 0;
m68.emulate_subroutine = 0;
m68.trace = 0;
+ m68.profile = 0;
+ m68.irqed = 0;
m68.tag = tag;
return m68;
}
@@ -935,8 +937,11 @@
{
int s;
- if(m68->cc & MASK_I)
+ if(m68->cc & MASK_I){
+ m68->irqed = 1;
return FALSE;
+ }
+ m68->irqed = 0;
m68write8(m68, m68->sp, m68->pc & 0xff);
m68->sp--;
@@ -997,6 +1002,10 @@
_length = length[_op];
_states = states[_op];
+#if defined(M68_PROFILE)
+ if(m68->profile)
+ m68profile(m68);
+#endif
#if defined(M68_TRACE)
if(m68->trace)
m68log(m68);
diff -uNr bm2/m6800.h bm2p/m6800.h
--- bm2/m6800.h 2014-03-19 23:56:06
+++ bm2p/m6800.h 2024-07-20 00:54:18
@@ -31,6 +31,8 @@
int total_states; /* 累積ステート数 */
int emulate_subroutine; /* サブルーチンをエミュレートするか? */
int trace; /* トレースモードか? */
+ int profile; /* profile mode? */
+ int irqed; /* IRQがあった */
void *tag; /* その他の情報 */
};
@@ -52,6 +54,10 @@
#if defined(M68_SUB)
int m68subroutine(struct M68stat *, uint16);
+#endif
+#if defined(M68_PROFILE)
+void m68profile(const struct M68stat *);
+void m68memprof(uint16 p);
#endif
#if defined(M68_TRACE)
void m68log(const struct M68stat *);
diff -uNr bm2/main.c bm2p/main.c
--- bm2/main.c 2024-07-20 01:29:55
+++ bm2p/main.c 2024-07-20 01:02:38
@@ -20,8 +20,21 @@
for(;;) {
/* コードを実行する */
- m68exec(&bm2->cpu);
-
+ if(bm2->cpu.irqed){
+ int st=bm2->cpu.states;
+ while(st>=100 && bm2->cpu.irqed){
+ bm2->cpu.states = 100;
+ m68exec(&bm2->cpu);
+ st-=100;
+ if(!(bm2->ram_rom & 0x10)){
+ m68irq(&bm2->cpu);
+ }
+ }
+ if(st>0){
+ bm2->cpu.states = st;
+ m68exec(&bm2->cpu);
+ }
+ }
/* 画面を更新する */
updateScreen(bm2);
@@ -38,8 +51,9 @@
/* IRQ(タイマ) */
if(timer >= 1000 / 60) {
- if(!(bm2->ram_rom & 0x10))
+ if(!(bm2->ram_rom & 0x10)){
m68irq(&bm2->cpu);
+ }
timer -= 1000 / 60;
}
diff -uNr bm2/main.c.bak bm2p/main.c.bak
diff -uNr bm2/menu.c bm2p/menu.c
--- bm2/menu.c 2014-03-23 07:47:11
+++ bm2p/menu.c 2024-07-14 13:23:10
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include "bm2.h"
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
diff -uNr bm2/prof2txt.c bm2p/prof2txt.c
--- bm2/prof2txt.c 1970-01-01 09:00:00
+++ bm2p/prof2txt.c 2024-07-14 13:52:52
@@ -0,0 +1,16 @@
+#include
+#include
+
+extern int
+main()
+{
+ uint32_t addr=0;
+ uint32_t count=0;
+
+ while(read(0,&count,sizeof(count))==sizeof(count)){
+ if(count){
+ printf("%04x %d\n",addr,count);
+ }
+ addr++;
+ }
+}
diff -uNr bm2/sound.c bm2p/sound.c
--- bm2/sound.c 2015-07-05 15:07:46
+++ bm2p/sound.c 2024-07-14 13:22:58
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
#include
#include
#include "bm2.h"
測定結果はbm2memprof.binというファイルに入るので、前回作った prof2txt.c で読み出せる。
0ページアクセスだけ読むには grep ^00 で良い。
$ ./prof2txt < bm2memprof.bin |grep ^00 |sort -k2 -nr|head -10
006c 18079995
007b 5430900
007a 5430794
0086 4758300
0071 4583862
0079 4541521
0078 4354822
008f 3599344
0090 3599231
0013 3157296
続く
ディスカッション
コメント一覧
まだ、コメントがありません