いまさらベーシックマスターの開発環境を作ってみる(19) プロファイラを作ってみる(2)

2024/07/20BASICMASTER, 昔のパソコン

いまさらベーシックマスターの開発環境を作ってみる(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

続く