Re: [hatari-devel] Suppressing repeated log and trace output

[ Thread Index | Date Index | More lists.tuxfamily.org/hatari-devel Archives ]


Hi,

Attached updated patch-set handles cases mentioned at the bottom of the mail (repeat messages are flushed before direct / multi-line output to trace file), and it adds autoscaling to the repeat limit, so CLI option is now just toggle.

I'm considering this good enough to be pushed to Hatari unless somebody has objections within week or two.

It would be nice if somebody using CPU disasm tracing could first verify that my changes are not messing it though.


	- Eero

PS. NetBSD 8.2 startup with CPU symbol and IDE tracing looks like following with it:
------------------------------------------------
hatari --netbsd -c netbsd.cfg --monitor vga --machine falcon --dsp none --mmu on -s 14 --ide-master 8mb-disk.img --disk-a blank-a.st --parse profile.ini --trace ide
DOS MBR:
- Partition 0: type=0x04, start=0x00000001, size=8.0 MB (boot)
- Partition 1: type=0x00, start=0x00004000, size=0.0 MB (invalid)
- Partition 2: type=0x00, start=0x00004000, size=0.0 MB (invalid)
- Partition 3: type=0x00, start=0x00004000, size=0.0 MB (invalid)
- Total size: 8.0 MB in 1 partitions
IDE: little->big endian byte-swapping enabled for drive 0
IDE: using geometry LCHS=16 16 63
NetBSD: kernel_phdrs[0].p_vaddr  = 0x00000000
NetBSD: kernel_phdrs[0].p_offset = 0x00000080
NetBSD: kernel_phdrs[0].p_filesz = 0x002777ac
NetBSD: kernel_phdrs[0].p_memsz  = 0x00292de0
NetBSD: Copying segment 0: 0x00000080,0x002777ac to 0x00002000-0x002797ac
NetBSD: Copying symbol strings: 0x002fc2d6,0x000000d3 to 0x002950e4-0x002951b7
NetBSD: Copying symbol table: 0x00280884,0x0004df50 to 0x002951b8-0x002e3108
NetBSD: Copying symbol strings: 0x002ce7d4,0x0002db02 to 0x002e3108-0x00310c0a
WARNING: removed 6315 complete symbol duplicates
Loaded 12883 symbols (9299 TEXT) from 'kernel'.
Machine info:
ST-RAM size	:    4194304 bytes
TT-RAM size	:          0 bytes
TT-RAM start	: 0x01000000
Cpu-type	: 0x00001008
Kernel loadaddr	: 0x00002000
Kernel size	:    3206156 (0x30ec0c) bytes
Kernel entry	: 0x000027da
Kernel esym	: 0x0030ec0c
Reading debugger commands from 'profile.ini'...
> trace cpu_symbols
Lstart2
8 repeats of: Lstart2
16 repeats of: Lstart2
32 repeats of: Lstart2
64 repeats of: Lstart2
128 repeats of: Lstart2
256 repeats of: Lstart2
512 repeats of: Lstart2
1024 repeats of: Lstart2
2048 repeats of: Lstart2
4096 repeats of: Lstart2
8192 repeats of: Lstart2
16384 repeats of: Lstart2
32768 repeats of: Lstart2
65536 repeats of: Lstart2
131072 repeats of: Lstart2
262144 repeats of: Lstart2
274698 repeats of: Lstart2
Lstart3
Lend_cpuset
start_c
badbaddr
setjmp
longjmp
badbaddr
setjmp
....
------------------------------------------------

On 29.10.2022 0.47, Eero Tamminen wrote:
on suggestion from Uwe, I've extended this code to cover also log messages in addition to trace output.

Patches attached. Any comments?

(see limitations below.)

On 28.8.2022 23.49, Eero Tamminen wrote:
I've had a problem with tracing that some programs hit specific trace point constantly, either as result of bug, or as their normal working, which can scroll the relevant (other) output from console view and scroll buffer near-instantly.

Attached are patches to change tracing so that one can specify whether trace output will compress repeated lines, and how many successive repeats there needs to be for it to output intermediate info about the repeats.


I'm mapping also LOG_TRACE_PRINT() macro to this, but there are few traces where this falls down:
- IDE ATAPI CMD
- NF_SCSIDRV inout

Because they do multiple lines of output.

Then there are few things that access TraceFile directly for multi-line output (instead of using LOG_TRACE_PRINT macro):
- CPU + DSP disasm tracing
- CPU + DSP register tracing
- AES tracing

I.e. one should not enable trace compression when tracing one of above 7 items is enabled.


Comments / thoughts?
From ca5aa968c916814c5f165c45755d8fc42f1f3253 Mon Sep 17 00:00:00 2001
From: Eero Tamminen <oak@xxxxxxxxxxxxxx>
Date: Sat, 29 Oct 2022 00:42:12 +0300
Subject: [PATCH 4/4] Document msg repeat suppression and its "--msg-repeat"
 option

---
 doc/hatari.1          | 5 +++++
 doc/manual.html       | 6 ++++++
 doc/release-notes.txt | 2 ++
 3 files changed, 13 insertions(+)

diff --git a/doc/hatari.1 b/doc/hatari.1
index 7361568e..9ad126dc 100644
--- a/doc/hatari.1
+++ b/doc/hatari.1
@@ -618,6 +618,11 @@ for available (comma separated) tracing flags
 .B \-\-trace\-file <file>
 Save trace output to <file> (default=stderr)
 .TP
+.B \-\-msg\-repeat
+Toggle whether successive repeats of identical log or trace messages
+will be suppressed, so that only their count is shown (default=suppress).
+Disassembly, register and (multi-line) AES traces bypass this feature
+.TP
 .B \-\-parse <file>
 Parse/execute debugger commands from <file>
 .TP
diff --git a/doc/manual.html b/doc/manual.html
index 692cd07e..a506223e 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -1106,6 +1106,12 @@ E.g. EmuTOS uses it for debug output.</p>
 &lt;file&gt;</p>
 <p class="paramdesc">Save trace output to &lt;file&gt;
 (default=stderr)</p>
+<p class="parameter">--msg-repeat</p>
+<p class="paramdesc">Toggle whether successive repeats of identical log
+or trace messages will be suppressed, so that only their count is shown
+(default=suppress). Disassembly, register and (multi-line) AES traces
+bypass this feature
+</p>
 <p class="parameter">--parse
 &lt;file&gt;</p>
 <p class="paramdesc">Parse/execute debugger commands from
diff --git a/doc/release-notes.txt b/doc/release-notes.txt
index 6e9b214f..60d72548 100644
--- a/doc/release-notes.txt
+++ b/doc/release-notes.txt
@@ -34,6 +34,8 @@ Emulator improvements:
 - Debugger:
   - Fix: free all debugger allocations before exit
   - Fix: invalid free on freeing loaded GNU debug symbols
+  - Suppress repeats of identical log & trace messages by default
+    (show only their count) and add "--msg-repeat" option to toggle that
   - Preliminary support for disassembly output options working also for
     CPU core disassembler in addition to external disassember output
   - When entering debugger with 'history' enabled, disassembly address
-- 
2.30.2

From 43aac9de0377d7fbddb9bb2fe8eb38a962f0623d Mon Sep 17 00:00:00 2001
From: Eero Tamminen <oak@xxxxxxxxxxxxxx>
Date: Sun, 30 Oct 2022 20:04:28 +0200
Subject: [PATCH 3/4] Integrate direct trace file output with message
 suppression

LOG_TRACE_PRINT was earlier changed to message repeat handling,
however that does not work properly for all code in Hatari.

* Add LOG_TRACE_DIRECT define for multi-line output where
  going through the message repeat handling does not make sense,
  or some part of output does not use tracing infra for output
  (e.g. CPU & DSP disasm & reg tracing)

* Add LOG_TRACE_DIRECT_LEVEL define for multi-line output in hdc.c
  which does not its output within LOG_TRACE_LEVEL block

* Add LOG_TRACE_DIRECT_INIT define to flush any pending message
  repeats before doing direct output to trace file

* To round off the defines, add LOG_TRACE_DIRECT_FLUSH to
  flush trace file after direct output is done
---
 src/cpu/newcpu.c              | 39 +++++++++++++++++++++++------------
 src/debug/debugcpu.c          |  1 +
 src/debug/log.c               | 11 ++++++----
 src/debug/log.h               |  9 ++++++++
 src/falcon/dsp_cpu.c          |  2 ++
 src/hdc.c                     | 21 ++++++++++++-------
 src/ide.c                     |  8 ++++---
 src/nf_scsidrv.c              |  8 +++----
 src/vdi.c                     |  3 ++-
 tests/debugger/test-dummies.c |  1 +
 10 files changed, 71 insertions(+), 32 deletions(-)

diff --git a/src/cpu/newcpu.c b/src/cpu/newcpu.c
index 5798ffce..4d0267db 100644
--- a/src/cpu/newcpu.c
+++ b/src/cpu/newcpu.c
@@ -5284,7 +5284,8 @@ static void m68k_run_1 (void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 				}
 #endif
@@ -5428,7 +5429,8 @@ static void m68k_run_1_ce (void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 				}
 #endif
@@ -6024,7 +6026,8 @@ static void m68k_run_jit(void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 				}
 #endif
@@ -6175,7 +6178,8 @@ static void m68k_run_mmu060 (void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 				}
 #endif
@@ -6269,7 +6273,8 @@ static void m68k_run_mmu040 (void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 				}
 #endif
@@ -6416,7 +6421,8 @@ insretry:
 					{
 						int FrameCycles, HblCounterVideo, LineCycles;
 						Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-						LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+						LOG_TRACE_DIRECT_INIT ();
+						LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 						m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 					}
 #endif
@@ -6593,7 +6599,8 @@ static void m68k_run_3ce (void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 				}
 				currcycle = CYCLE_UNIT / 2;	/* Assume at least 1 cycle per instruction */
@@ -6691,7 +6698,8 @@ static void m68k_run_3p(void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 				}
 #endif
@@ -6828,7 +6836,8 @@ static void m68k_run_2ce (void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 #if 0
 // logs to debug data cache issues
@@ -7028,7 +7037,8 @@ static void m68k_run_2p (void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 				}
 #endif
@@ -7226,7 +7236,8 @@ static void m68k_run_2_000(void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
 				}
 #endif
@@ -7319,7 +7330,8 @@ static void m68k_run_2_020(void)
 				{
 					int FrameCycles, HblCounterVideo, LineCycles;
 					Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-					LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+					LOG_TRACE_DIRECT_INIT ();
+					LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 					m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 				}
 #endif
@@ -7396,7 +7408,8 @@ static void m68k_run_mmu (void)
 		{
 			int FrameCycles, HblCounterVideo, LineCycles;
 			Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
-			LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
+			LOG_TRACE_DIRECT_INIT ();
+			LOG_TRACE_DIRECT ( "cpu video_cyc=%6d %3d@%3d %"PRIu64" : " , FrameCycles, LineCycles, HblCounterVideo , CyclesGlobalClockCounter );
 			m68k_disasm_file(TraceFile, m68k_getpc (), NULL, m68k_getpc (), 1);
 		}
 #endif
diff --git a/src/debug/debugcpu.c b/src/debug/debugcpu.c
index 831f7344..9f5ff6a5 100644
--- a/src/debug/debugcpu.c
+++ b/src/debug/debugcpu.c
@@ -896,6 +896,7 @@ void DebugCpu_Check(void)
 	if (LOG_TRACE_LEVEL(TRACE_CPU_REGS))
 	{
 		uaecptr nextpc;
+		LOG_TRACE_DIRECT_INIT ();
 		m68k_dumpstate_file(TraceFile, &nextpc, 0xffffffff);
 	}
 	if (nCpuActiveCBs)
diff --git a/src/debug/log.c b/src/debug/log.c
index e81ec36b..0b719dcb 100644
--- a/src/debug/log.c
+++ b/src/debug/log.c
@@ -262,16 +262,18 @@ static void printMsgRepeat(FILE *fp)
 }
 
 /**
- * If there is a pending that has not been output yet, output it.
+ * If there is a pending that has not been output yet, output it
+ * and return true, otherwise false.
  */
-static void printPendingMsgRepeat(FILE *fp)
+static bool printPendingMsgRepeat(FILE *fp)
 {
 	if (likely(MsgState.count == 0))
-		return;
+		return false;
 	if (MsgState.count > 1)
 		printMsgRepeat(fp);
 	else
 		fputs(MsgState.prev, fp);
+	return true;
 }
 
 /**
@@ -312,7 +314,8 @@ static void addMsgRepeat(FILE *fp, const char *line)
  */
 void Log_ResetMsgRepeat(void)
 {
-	printPendingMsgRepeat(MsgState.fp);
+	if (!printPendingMsgRepeat(MsgState.fp))
+		return;
 	MsgState.prev[0] = '\0';
 	if (MsgState.limit)
 		MsgState.limit = REPEAT_LIMIT_INIT;
diff --git a/src/debug/log.h b/src/debug/log.h
index b4b327aa..bab3ec03 100644
--- a/src/debug/log.h
+++ b/src/debug/log.h
@@ -321,5 +321,14 @@ extern uint64_t LogTraceFlags;
  */
 #define LOG_TRACE_PRINT(...)	Log_Trace(__VA_ARGS__)
 
+/* Skip message repeat suppression on multi-line output.
+ * LOG_TRACE_DIRECT_INIT() should called before doing them and
+ * LOG_TRACE_DIRECT_FLUSH() can be called after them
+ */
+#define LOG_TRACE_DIRECT(...)	    fprintf(TraceFile, __VA_ARGS__)
+#define	LOG_TRACE_DIRECT_LEVEL(level, ...) \
+	if (LOG_TRACE_LEVEL(level)) { fprintf(TraceFile, __VA_ARGS__); }
+#define LOG_TRACE_DIRECT_INIT()	    Log_ResetMsgRepeat()
+#define LOG_TRACE_DIRECT_FLUSH()    fflush(TraceFile)
 
 #endif		/* HATARI_LOG_H */
diff --git a/src/falcon/dsp_cpu.c b/src/falcon/dsp_cpu.c
index e519e3e2..a2f1103f 100644
--- a/src/falcon/dsp_cpu.c
+++ b/src/falcon/dsp_cpu.c
@@ -796,6 +796,7 @@ void dsp56k_execute_instruction(void)
 	if (LOG_TRACE_LEVEL(TRACE_DSP_DISASM)) {
 		/* Call dsp56k_disasm only when DSP is called in trace mode */
 		if (isDsp_in_disasm_mode == false) {
+			LOG_TRACE_DIRECT_INIT();
 			disasm_return = dsp56k_disasm(DSP_TRACE_MODE, TraceFile);
 
 			if (disasm_return != 0 && LOG_TRACE_LEVEL(TRACE_DSP_DISASM_REG)) {
@@ -830,6 +831,7 @@ void dsp56k_execute_instruction(void)
 		/* Display only when DSP is called in trace mode */
 		if (isDsp_in_disasm_mode == false) {
 			if (disasm_return != 0) {
+				LOG_TRACE_DIRECT_INIT();
 				fprintf(TraceFile, "%s", dsp56k_getInstructionText());
 
 				/* DSP regs trace enabled only if DSP DISASM is enabled */
diff --git a/src/hdc.c b/src/hdc.c
index d83fa49c..05c63f92 100644
--- a/src/hdc.c
+++ b/src/hdc.c
@@ -771,7 +771,8 @@ int HDC_PartitionCount(FILE *fp, const uint64_t tracelevel, int *pIsByteSwapped)
 	{
 		int ptype, boot;
 
-		LOG_TRACE(tracelevel, "DOS MBR:\n");
+		LOG_TRACE_DIRECT_INIT();
+		LOG_TRACE_DIRECT_LEVEL(tracelevel, "DOS MBR:\n");
 		/* first partition table entry */
 		pinfo = bootsector + 0x1BE;
 		for (i = 0; i < 4; i++, pinfo += 16)
@@ -781,12 +782,15 @@ int HDC_PartitionCount(FILE *fp, const uint64_t tracelevel, int *pIsByteSwapped)
 			start = SDL_SwapLE32(*(uint32_t*)(pinfo+8));
 			sectors = SDL_SwapLE32(*(uint32_t*)(pinfo+12));
 			total += sectors;
-			LOG_TRACE(tracelevel, "- Partition %d: type=0x%02x, start=0x%08x, size=%.1f MB %s%s\n",
-				  i, ptype, start, sectors/2048.0, boot ? "(boot)" : "", sectors ? "" : "(invalid)");
+			LOG_TRACE_DIRECT_LEVEL(tracelevel,
+				"- Partition %d: type=0x%02x, start=0x%08x, size=%.1f MB %s%s\n",
+				i, ptype, start, sectors/2048.0, boot ? "(boot)" : "", sectors ? "" : "(invalid)");
 			if (ptype)
 				parts++;
 		}
-		LOG_TRACE(tracelevel, "- Total size: %.1f MB in %d partitions\n", total/2048.0, parts);
+		LOG_TRACE_DIRECT_LEVEL(tracelevel,
+			"- Total size: %.1f MB in %d partitions\n", total/2048.0, parts);
+		LOG_TRACE_DIRECT_FLUSH();
 	}
 	else
 	{
@@ -800,7 +804,8 @@ int HDC_PartitionCount(FILE *fp, const uint64_t tracelevel, int *pIsByteSwapped)
 		int j, flags;
 		bool extended;
 
-		LOG_TRACE(tracelevel, "ATARI MBR:\n");
+		LOG_TRACE_DIRECT_INIT();
+		LOG_TRACE_DIRECT_LEVEL(tracelevel, "ATARI MBR:\n");
 		pinfo = bootsector + 0x1C6;
 		for (i = 0; i < 4; i++, pinfo += 12)
 		{
@@ -816,7 +821,7 @@ int HDC_PartitionCount(FILE *fp, const uint64_t tracelevel, int *pIsByteSwapped)
 			extended = strcmp("XGM", pid) == 0;
 			start = HDC_ReadInt32(pinfo, 4);
 			sectors = HDC_ReadInt32(pinfo, 8);
-			LOG_TRACE(tracelevel,
+			LOG_TRACE_DIRECT_LEVEL(tracelevel,
 				  "- Partition %d: ID=%s, start=0x%08x, size=%.1f MB, flags=0x%x %s%s\n",
 				  i, pid, start, sectors/2048.0, flags,
 				  (flags & 0x80) ? "(boot)": "",
@@ -825,7 +830,9 @@ int HDC_PartitionCount(FILE *fp, const uint64_t tracelevel, int *pIsByteSwapped)
 				parts++;
 		}
 		total = HDC_ReadInt32(bootsector, 0x1C2);
-		LOG_TRACE(tracelevel, "- Total size: %.1f MB in %d partitions\n", total/2048.0, parts);
+		LOG_TRACE_DIRECT_LEVEL(tracelevel,
+			"- Total size: %.1f MB in %d partitions\n", total/2048.0, parts);
+		LOG_TRACE_DIRECT_FLUSH();
 	}
 
 	if (fseeko(fp, offset, SEEK_SET) != 0)
diff --git a/src/ide.c b/src/ide.c
index e1117e25..5dd3e893 100644
--- a/src/ide.c
+++ b/src/ide.c
@@ -1529,12 +1529,14 @@ static void ide_atapi_cmd(IDEState *s)
 	if (LOG_TRACE_LEVEL(TRACE_IDE))
 	{
 		int i;
-		LOG_TRACE_PRINT("IDE: ATAPI limit=0x%x packet", s->lcyl | (s->hcyl << 8));
+		LOG_TRACE_DIRECT_INIT();
+		LOG_TRACE_DIRECT("IDE: ATAPI limit=0x%x packet", s->lcyl | (s->hcyl << 8));
 		for (i = 0; i < ATAPI_PACKET_SIZE; i++)
 		{
-			LOG_TRACE_PRINT(" %02x", packet[i]);
+			LOG_TRACE_DIRECT(" %02x", packet[i]);
 		}
-		LOG_TRACE_PRINT("\n");
+		LOG_TRACE_DIRECT("\n");
+		LOG_TRACE_DIRECT_FLUSH();
 	}
 
 	switch (s->io_buffer[0])
diff --git a/src/nf_scsidrv.c b/src/nf_scsidrv.c
index 27178070..110264a7 100644
--- a/src/nf_scsidrv.c
+++ b/src/nf_scsidrv.c
@@ -308,7 +308,8 @@ static int scsidrv_inout(uint32_t stack)
 
 	if (LOG_TRACE_LEVEL(TRACE_SCSIDRV))
 	{
-		LOG_TRACE_PRINT(
+		LOG_TRACE_DIRECT_INIT();
+		LOG_TRACE_DIRECT(
 		    "scsidrv_inout: handle=%d, dir=%d, cmd_len=%d, buffer=%p,\n"
 		    "               transfer_len=%d, sense_buffer=%p, timeout=%d,\n"
 		    "               cmd=",
@@ -318,10 +319,9 @@ static int scsidrv_inout(uint32_t stack)
 		uint32_t i;
 		for (i = 0; i < cmd_len; i++)
 		{
-			char str[8];
-			sprintf(str, i ? ":$%02X" : "$%02X", cmd[i]);
-			LOG_TRACE_PRINT("%s", str);
+			LOG_TRACE_DIRECT("%s$%02X", i?":":"", cmd[i]);
 		}
+		LOG_TRACE_DIRECT_FLUSH();
 	}
 
 	// Writing is allowed with a RAM or ROM address,
diff --git a/src/vdi.c b/src/vdi.c
index 97534599..d5ab6005 100644
--- a/src/vdi.c
+++ b/src/vdi.c
@@ -931,7 +931,8 @@ bool VDI_AES_Entry(void)
 			return false;
 		if (LOG_TRACE_LEVEL(TRACE_OS_AES))
 		{
-			fprintf(TraceFile, "AES 0x%02hX ", AES.OpCode);
+			LOG_TRACE_DIRECT_INIT();
+			LOG_TRACE_DIRECT("AES 0x%02hX ", AES.OpCode);
 			AES_OpcodeInfo(TraceFile, AES.OpCode);
 			fflush(TraceFile);
 		}
diff --git a/tests/debugger/test-dummies.c b/tests/debugger/test-dummies.c
index 17684ab2..32f3c7b5 100644
--- a/tests/debugger/test-dummies.c
+++ b/tests/debugger/test-dummies.c
@@ -9,6 +9,7 @@
 uint64_t LogTraceFlags = 0;
 FILE *TraceFile;
 void Log_Trace(const char *format, ...) { }
+void Log_ResetMsgRepeat(void) {}
 
 /* fake Hatari configuration variables for number parsing */
 #include "configuration.h"
-- 
2.30.2

From 9d4f48c176d278f94bbb4d6f0b693c28f6f908f0 Mon Sep 17 00:00:00 2001
From: Eero Tamminen <oak@xxxxxxxxxxxxxx>
Date: Sun, 28 Aug 2022 22:11:48 +0300
Subject: [PATCH 2/4] Change CPU+DSP symbol tracing to use Log_Trace() function

So that repeated entries will be compressed on output.
---
 src/debug/debugcpu.c | 29 ++++++++++-------------------
 src/debug/debugdsp.c | 31 +++++++++++--------------------
 2 files changed, 21 insertions(+), 39 deletions(-)

diff --git a/src/debug/debugcpu.c b/src/debug/debugcpu.c
index 0ab0daeb..831f7344 100644
--- a/src/debug/debugcpu.c
+++ b/src/debug/debugcpu.c
@@ -143,23 +143,6 @@ static int DebugCpu_SaveBin(int nArgc, char *psArgs[])
 }
 
 
-/**
- * Check whether given address matches any CPU symbol and whether
- * there's profiling information available for it.  If yes, show it.
- * 
- * @return true if symbol was shown, false otherwise
- */
-static bool DebugCpu_ShowAddressInfo(uint32_t addr, FILE *fp)
-{
-	const char *symbol = Symbols_GetByCpuAddress(addr, SYMTYPE_ALL);
-	if (symbol)
-	{
-		fprintf(fp, "%s:\n", symbol);
-		return true;
-	}
-	return false;
-}
-
 /**
  * Disassemble - arg = starting address, or PC.
  */
@@ -202,6 +185,7 @@ int DebugCpu_DisAsm(int nArgc, char *psArgs[])
 	prev_addr = disasm_addr;
 	for (shown = 0; shown < lines && disasm_addr < disasm_upper; shown++)
 	{
+		const char *symbol;
 		if (prev_addr < pc && disasm_addr > pc)
 		{
 			fputs("ERROR, disassembly misaligned with PC address, correcting\n", debugOutput);
@@ -214,8 +198,12 @@ int DebugCpu_DisAsm(int nArgc, char *psArgs[])
 			shown++;
 		}
 		prev_addr = disasm_addr;
-		if (DebugCpu_ShowAddressInfo(disasm_addr, debugOutput))
+		symbol = Symbols_GetByCpuAddress(disasm_addr, SYMTYPE_ALL);
+		if (symbol)
+		{
+			fprintf(debugOutput, "%s:\n", symbol);
 			shown++;
+		}
 		Disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, 1);
 		disasm_addr = nextpc;
 	}
@@ -900,7 +888,10 @@ void DebugCpu_Check(void)
 	}
 	if (LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS)))
 	{
-		DebugCpu_ShowAddressInfo(M68000_GetPC(), TraceFile);
+		const char *symbol;
+		symbol = Symbols_GetByCpuAddress(M68000_GetPC(), SYMTYPE_ALL);
+		if (symbol)
+			LOG_TRACE_PRINT("%s\n", symbol);
 	}
 	if (LOG_TRACE_LEVEL(TRACE_CPU_REGS))
 	{
diff --git a/src/debug/debugdsp.c b/src/debug/debugdsp.c
index 5a978f17..80e7613d 100644
--- a/src/debug/debugdsp.c
+++ b/src/debug/debugdsp.c
@@ -101,24 +101,6 @@ error_msg:
 }
 
 
-/**
- * Check whether given address matches any DSP symbol and whether
- * there's profiling information available for it.  If yes, show it.
- * 
- * @return true if symbol was shown, false otherwise
- */
-static bool DebugDsp_ShowAddressInfo(uint16_t addr, FILE *fp)
-{
-	const char *symbol = Symbols_GetByDspAddress(addr, SYMTYPE_ALL);
-	if (symbol)
-	{
-		fprintf(fp, "%s:\n", symbol);
-		return true;
-	}
-	return false;
-}
-
-
 /**
  * DSP disassemble - arg = starting address/range, or PC.
  */
@@ -176,6 +158,8 @@ int DebugDsp_DisAsm(int nArgc, char *psArgs[])
 	prev_addr = dsp_disasm_addr;
 	fprintf(debugOutput, "DSP disasm 0x%hx-0x%hx:\n", dsp_disasm_addr, dsp_disasm_upper);
 	for (shown = 1; shown < lines && dsp_disasm_addr < dsp_disasm_upper; shown++) {
+		const char *symbol;
+
 		if (prev_addr < pc && dsp_disasm_addr > pc)
 		{
 			fputs("ERROR, disassembly misaligned with PC address, correcting\n", debugOutput);
@@ -188,8 +172,12 @@ int DebugDsp_DisAsm(int nArgc, char *psArgs[])
 			shown++;
 		}
 		prev_addr = dsp_disasm_addr;
-		if (DebugDsp_ShowAddressInfo(dsp_disasm_addr, debugOutput))
+		symbol = Symbols_GetByDspAddress(dsp_disasm_addr, SYMTYPE_ALL);
+		if (symbol)
+		{
+			fprintf(debugOutput, "%s:\n", symbol);
 			shown++;
+		}
 		dsp_disasm_addr = DSP_DisasmAddress(debugOutput, dsp_disasm_addr, dsp_disasm_addr);
 	}
 	fflush(debugOutput);
@@ -529,7 +517,10 @@ void DebugDsp_Check(void)
 	}
 	if (LOG_TRACE_LEVEL((TRACE_DSP_DISASM|TRACE_DSP_SYMBOLS)))
 	{
-		DebugDsp_ShowAddressInfo(DSP_GetPC(), TraceFile);
+		const char *symbol;
+		symbol = Symbols_GetByDspAddress(DSP_GetPC(), SYMTYPE_ALL);
+		if (symbol)
+			LOG_TRACE_PRINT("%s\n", symbol);
 	}
 	if (nDspActiveCBs)
 	{
-- 
2.30.2

From 28a563cb3dba865a87815507b1e73794855d04e5 Mon Sep 17 00:00:00 2001
From: Eero Tamminen <oak@xxxxxxxxxxxxxx>
Date: Sun, 28 Aug 2022 20:54:01 +0300
Subject: [PATCH 1/4] Support for suppressing successive identical log & trace
 messages

There are situations (bugs) where specific log or trace messages start
repeating constantly.  After repeating for a while, rest is useless,
fills logs quickly and often scrolls the useful info (about how that
sitation was entered) out of view faster than one can react.

Limit on how often Hatari prints count of repeated messages is doubled
whenever earlier limit is reached, and drops back to default if
message changes.

This commit includes only general log & trace message integration.
Later commits add special handling for few places needing extra care.

Repeat suppression is enabled by default and can be toggled with the
new "--msg-repeat" option.
---
 src/debug/debugui.c           |   3 +
 src/debug/log.c               | 225 +++++++++++++++++++++++++++++-----
 src/debug/log.h               |  12 +-
 src/main.c                    |   2 +-
 src/options.c                 |   7 ++
 tests/debugger/test-dummies.c |   1 +
 6 files changed, 214 insertions(+), 36 deletions(-)

diff --git a/src/debug/debugui.c b/src/debug/debugui.c
index 52bf1629..f6aaf4be 100644
--- a/src/debug/debugui.c
+++ b/src/debug/debugui.c
@@ -1074,6 +1074,8 @@ void DebugUI_Init(void)
 	const dbgcommand_t *cpucmd, *dspcmd;
 	int cpucmds, dspcmds;
 
+	Log_ResetMsgRepeat();
+
 	/* already initialized? */
 	if (debugCommands)
 		return;
@@ -1120,6 +1122,7 @@ void DebugUI_UnInit(void)
 {
 	Profile_CpuFree();
 	Profile_DspFree();
+	Log_ResetMsgRepeat();
 	free(debugCommand);
 	debugCommands = 0;
 }
diff --git a/src/debug/log.c b/src/debug/log.c
index 62307b46..e81ec36b 100644
--- a/src/debug/log.c
+++ b/src/debug/log.c
@@ -31,6 +31,7 @@ const char Log_fileid[] = "Hatari log.c";
 #include "file.h"
 #include "vdi.h"
 #include "options.h"
+#include "str.h"
 
 int ExceptionDebugMask;
 
@@ -166,6 +167,24 @@ static flagname_t TraceFlags[] = {
 uint64_t LogTraceFlags = TRACE_NONE;
 FILE *TraceFile = NULL;
 
+
+/* SDL GUI Alerts can show 4*50 chars at max, and much longer
+ * console messages are not very readable either, just slow
+ */
+#define MAX_MSG_LEN 256
+#define REPEAT_LIMIT_INIT 8
+
+/* FILE* for output stream, message line repeat suppression limit,
+ * current repeat count, and previous line content for checking
+ * repetition
+ */
+static struct {
+	FILE *fp;
+	int limit;
+	int count;
+	char prev[MAX_MSG_LEN];
+} MsgState;
+
 static FILE *hLogFile = NULL;
 
 /* local settings, to be able change them temporarily */
@@ -181,6 +200,7 @@ void Log_Default(void)
 	hLogFile = stderr;
 	TraceFile = stderr;
 	TextLogLevel = LOG_INFO;
+	MsgState.limit = REPEAT_LIMIT_INIT;
 }
 
 /**
@@ -204,7 +224,7 @@ int Log_Init(void)
 
 	hLogFile = File_Open(ConfigureParams.Log.sLogFileName, "w");
 	TraceFile = File_Open(ConfigureParams.Log.sTraceFileName, "w");
-   
+
 	return (hLogFile && TraceFile);
 }
 
@@ -231,18 +251,117 @@ void Log_UnInit(void)
 	TraceFile = File_Close(TraceFile);
 }
 
+/*-----------------------------------------------------------------------
+ * log/trace message repeat suppression handling
+ */
+
+static void printMsgRepeat(FILE *fp)
+{
+	/* strings already include trailing newline */
+	fprintf(fp, "%d repeats of: %s", MsgState.count, MsgState.prev);
+}
+
+/**
+ * If there is a pending that has not been output yet, output it.
+ */
+static void printPendingMsgRepeat(FILE *fp)
+{
+	if (likely(MsgState.count == 0))
+		return;
+	if (MsgState.count > 1)
+		printMsgRepeat(fp);
+	else
+		fputs(MsgState.prev, fp);
+}
+
+/**
+ * Output pending and given messages when appropriate and
+ * store given message if it's not a repeat.
+ */
+static void addMsgRepeat(FILE *fp, const char *line)
+{
+	/* repeated message? */
+	if (fp == MsgState.fp &&
+	    unlikely(strcmp(line, MsgState.prev) == 0))
+	{
+		MsgState.count++;
+		/* limit crossed? -> print + increase repeat limit */
+		if (unlikely(MsgState.count >= MsgState.limit))
+		{
+			printMsgRepeat(fp);
+			MsgState.limit *= 2;
+			MsgState.count = 0;
+			fflush(fp);
+		}
+		return;
+	}
+	/* no repeat -> print previous message/repeat */
+	printPendingMsgRepeat(MsgState.fp);
+
+	/* store + print new message */
+	Str_Copy(MsgState.prev, line, sizeof(MsgState.prev));
+	MsgState.limit = REPEAT_LIMIT_INIT;
+	MsgState.count = 0;
+	MsgState.fp = fp;
+	fputs(line, fp);
+	fflush(fp);
+}
+
+/**
+ * Output pending message repeat info and reset repeat info.
+ */
+void Log_ResetMsgRepeat(void)
+{
+	printPendingMsgRepeat(MsgState.fp);
+	MsgState.prev[0] = '\0';
+	if (MsgState.limit)
+		MsgState.limit = REPEAT_LIMIT_INIT;
+	MsgState.count = 0;
+	MsgState.fp = NULL;
+}
+
+/**
+ * Toggle whether message repeats are shown
+ */
+void Log_ToggleMsgRepeat(void)
+{
+	if (MsgState.limit)
+	{
+		fprintf(stderr, "Message repeats will be shown as-is\n");
+		MsgState.limit = 0;
+	}
+	else
+	{
+		fprintf(stderr, "Message repeats will be suppressed\n");
+		MsgState.limit = REPEAT_LIMIT_INIT;
+	}
+	Log_ResetMsgRepeat();
+}
 
 /*-----------------------------------------------------------------------*/
 /**
- * Print log prefix when needed
+ * Add log prefix to given string and return its lenght
  */
-static void Log_PrintPrefix(FILE *fp, LOGTYPE idx)
+static int Log_AddPrefix(char *msg, int len, LOGTYPE idx)
 {
 	static const char* prefix[] = LOG_NAMES;
 
 	assert(idx >= 0 && idx < ARRAY_SIZE(prefix));
-	if (prefix[idx])
-		fprintf(fp, "%s: ", prefix[idx]);
+	return snprintf(msg, len, "%s: ", prefix[idx]);
+}
+
+/**
+ * Add a new-line if it's missing. 'msg' points to place
+ * where it should be, and size is buffer size.
+ */
+static void addMissingNewline(char *msg, int size)
+{
+	assert(size > 2);
+	if (size > 2 && msg[0] != '\n')
+	{
+		msg[1] = '\n';
+		msg[2] = '\0';
+	}
 }
 
 
@@ -252,18 +371,29 @@ static void Log_PrintPrefix(FILE *fp, LOGTYPE idx)
  */
 void Log_Printf(LOGTYPE nType, const char *psFormat, ...)
 {
-	va_list argptr;
+	if (!(hLogFile && nType <= TextLogLevel))
+		return;
 
-	if (hLogFile && nType <= TextLogLevel)
-	{
-		Log_PrintPrefix(hLogFile, nType);
-		va_start(argptr, psFormat);
-		vfprintf(hLogFile, psFormat, argptr);
-		va_end(argptr);
-		/* Add a new-line if necessary: */
-		if (psFormat[strlen(psFormat)-1] != '\n')
-			fputs("\n", hLogFile);
-	}
+	char line[sizeof(MsgState.prev)];
+	int count, len = sizeof(line);
+	char *msg = line;
+
+	count = Log_AddPrefix(line, len, nType);
+	msg += count;
+	len -= count;
+
+	va_list argptr;
+	va_start(argptr, psFormat);
+	count = vsnprintf(msg, len, psFormat, argptr);
+	va_end(argptr);
+	msg += count;
+	len -= count;
+
+	addMissingNewline(msg-1, len+1);
+	if (MsgState.limit)
+		addMsgRepeat(hLogFile, line);
+	else
+		fputs(line, hLogFile);
 }
 
 
@@ -278,30 +408,35 @@ void Log_AlertDlg(LOGTYPE nType, const char *psFormat, ...)
 	/* Output to log file: */
 	if (hLogFile && nType <= TextLogLevel)
 	{
-		Log_PrintPrefix(hLogFile, nType);
+		char line[sizeof(MsgState.prev)];
+		int count, len = sizeof(line);
+		char *msg = line;
+
+		count = Log_AddPrefix(line, len, nType);
+		msg += count;
+		len -= count;
+
 		va_start(argptr, psFormat);
-		vfprintf(hLogFile, psFormat, argptr);
+		count = vsnprintf(msg, len, psFormat, argptr);
 		va_end(argptr);
-		/* Add a new-line if necessary: */
-		if (psFormat[strlen(psFormat)-1] != '\n')
-			fputs("\n", hLogFile);
+		msg += count;
+		len -= count;
+
+		addMissingNewline(msg-1, len+1);
+		if (MsgState.limit)
+			addMsgRepeat(hLogFile, line);
+		else
+			fputs(line, hLogFile);
 	}
 
 	/* Show alert dialog box: */
 	if (sdlscrn && nType <= AlertDlgLogLevel)
 	{
-		char *psTmpBuf;
-		psTmpBuf = malloc(2048);
-		if (!psTmpBuf)
-		{
-			perror("Log_AlertDlg");
-			return;
-		}
+		char buf[MAX_MSG_LEN];
 		va_start(argptr, psFormat);
-		vsnprintf(psTmpBuf, 2048, psFormat, argptr);
+		vsnprintf(buf, sizeof(buf), psFormat, argptr);
 		va_end(argptr);
-		DlgAlert_Notice(psTmpBuf);
-		free(psTmpBuf);
+		DlgAlert_Notice(buf);
 	}
 }
 
@@ -504,6 +639,31 @@ char *Log_MatchTrace(const char *text, int state)
 	return NULL;
 }
 
+/**
+ * Do trace output with optional repeat suppression
+ */
+void Log_Trace(const char *format, ...)
+{
+	va_list argptr;
+	char line[sizeof(MsgState.prev)];
+
+	if (!TraceFile)
+		return;
+
+	va_start(argptr, format);
+	if (MsgState.limit)
+	{
+		vsnprintf(line, sizeof(line), format, argptr);
+		addMsgRepeat(TraceFile, line);
+	}
+	else
+	{
+		vfprintf(TraceFile, format, argptr);
+		fflush(TraceFile);
+	}
+	va_end(argptr);
+}
+
 #else	/* !ENABLE_TRACING */
 
 /** dummy */
@@ -518,4 +678,7 @@ char *Log_MatchTrace(const char *text, int state)
 	return NULL;
 }
 
+/** dummy */
+void Log_Trace(const char *format, ...) {}
+
 #endif	/* !ENABLE_TRACING */
diff --git a/src/debug/log.h b/src/debug/log.h
index ce6b415e..b4b327aa 100644
--- a/src/debug/log.h
+++ b/src/debug/log.h
@@ -82,6 +82,10 @@ extern void Log_AlertDlg(LOGTYPE nType, const char *psFormat, ...)
 extern LOGTYPE Log_ParseOptions(const char *OptionStr);
 extern const char* Log_SetTraceOptions(const char *OptionsStr);
 extern char *Log_MatchTrace(const char *text, int state);
+extern void Log_ToggleMsgRepeat(void);
+extern void Log_ResetMsgRepeat(void);
+extern void Log_Trace(const char *format, ...)
+	__attribute__ ((format (printf, 1, 2)));
 
 #ifndef __GNUC__
 #undef __attribute__
@@ -298,11 +302,11 @@ extern uint64_t LogTraceFlags;
 
 #if ENABLE_TRACING
 
-#define	LOG_TRACE(level, ...) \
-	if (unlikely(LogTraceFlags & (level))) { fprintf(TraceFile, __VA_ARGS__); fflush(TraceFile); }
-
 #define LOG_TRACE_LEVEL( level )	(unlikely(LogTraceFlags & (level)))
 
+#define	LOG_TRACE(level, ...) \
+	if (LOG_TRACE_LEVEL(level))	{ Log_Trace(__VA_ARGS__); }
+
 #else		/* ENABLE_TRACING */
 
 #define LOG_TRACE(level, ...)	{}
@@ -315,7 +319,7 @@ extern uint64_t LogTraceFlags;
  * In code it's used in such a way that it will be optimized away when tracing
  * is disabled.
  */
-#define LOG_TRACE_PRINT(...)	fprintf(TraceFile , __VA_ARGS__)
+#define LOG_TRACE_PRINT(...)	Log_Trace(__VA_ARGS__)
 
 
 #endif		/* HATARI_LOG_H */
diff --git a/src/main.c b/src/main.c
index 4371f64f..8df85467 100644
--- a/src/main.c
+++ b/src/main.c
@@ -823,10 +823,10 @@ static void Main_UnInit(void)
 	SDL_Quit();
 
 	/* Close debug log file */
+	DebugUI_UnInit();
 	Log_UnInit();
 
 	Paths_UnInit();
-	DebugUI_UnInit();
 }
 
 
diff --git a/src/options.c b/src/options.c
index ba462072..d579c9f6 100644
--- a/src/options.c
+++ b/src/options.c
@@ -195,6 +195,7 @@ enum {
 	OPT_NATFEATS,
 	OPT_TRACE,
 	OPT_TRACEFILE,
+	OPT_MSG_REPEAT,
 	OPT_PARSE,
 	OPT_SAVECONFIG,
 	OPT_CONTROLSOCKET,
@@ -488,6 +489,8 @@ static const opt_t HatariOptions[] = {
 	  "<flags>", "Activate emulation tracing, see '--trace help'" },
 	{ OPT_TRACEFILE, NULL, "--trace-file",
 	  "<file>", "Save trace output to <file> (default=stderr)" },
+	{ OPT_MSG_REPEAT, NULL, "--msg-repeat",
+	  NULL, "Toggle log/trace message repeats (default=suppress)" },
 	{ OPT_PARSE, NULL, "--parse",
 	  "<file>", "Parse/execute debugger commands from <file>" },
 	{ OPT_SAVECONFIG, NULL, "--saveconfig",
@@ -2182,6 +2185,10 @@ bool Opt_ParseParameters(int argc, const char * const argv[])
 					NULL);
 			break;
 
+		case OPT_MSG_REPEAT:
+			Log_ToggleMsgRepeat();
+			break;
+
 		case OPT_CONTROLSOCKET:
 			i += 1;
 			errstr = Control_SetSocket(argv[i]);
diff --git a/tests/debugger/test-dummies.c b/tests/debugger/test-dummies.c
index 59926732..17684ab2 100644
--- a/tests/debugger/test-dummies.c
+++ b/tests/debugger/test-dummies.c
@@ -8,6 +8,7 @@
 
 uint64_t LogTraceFlags = 0;
 FILE *TraceFile;
+void Log_Trace(const char *format, ...) { }
 
 /* fake Hatari configuration variables for number parsing */
 #include "configuration.h"
-- 
2.30.2



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/