--- hatari/doc/manual.html 2019/04/09 08:52:20 1.1.1.16 +++ hatari/doc/manual.html 2019/04/09 08:57:12 1.1.1.20 @@ -1,15 +1,13 @@ - - + + Hatari User's Manual - - - - - - + content="User's manual for the Atari ST emulator Hatari" /> + + + + + @@ -55,103 +64,28 @@

Hatari User's Manual

-

Index

- +

Index

+
+ +
-

Introduction

+

Introduction

-

General description

+

General description

Hatari is an Atari ST, STE, TT and Falcon emulator for Linux, OSX, Windows and other Systems which are supported by the SDL library. @@ -173,11 +107,12 @@ and demos. Of course you can run normal Recent versions of Hatari even feature STE, Falcon and basic TT emulation.

-

Features

+

Features

-

STE hardware emulation

There is support for following additional STE features:

-

Experimental TT hardware emulation

There is support for following additional TT features:

-

Falcon hardware emulation

There is support for following additional Falcon features:

@@ -261,7 +197,7 @@ Software Compatibility List for whic to be affected by them.

-

System requirements

+

System requirements

Hatari currently has the following minimum system requirements:

-

Compiling and running

+

Compiling and running

-

Compiling Hatari

+

Compiling Hatari

Required:

Hint: "info" command "aes", "bios", "gemdos", "vdi" and "xbios" -subcommands for can be used to list the corresponding OS-call opcodes. +subcommands can be used to list the corresponding OS-call opcodes. For example, to see the GEMDOS opcodes, use:

 info gemdos 1
 
- -

Chaining breakpoints and other actions

+

Chaining breakpoints and other actions

As the file pointed by the breakpoint ":file" option (see -Breakpoint options) can contain any +Breakpoint options) can contain any debugger commands, it can also be used to do automatic "chaining" of debugger and breakpoint actions so that after one breakpoint is hit, another one is set. @@ -3419,13 +3003,19 @@ another one is set.

-If tracing isn't possible for the things you'd like to track, you can -use the OS call opcode breakpoints explained above with the ":trace" -breakpoint option. +If there isn't a trace option for something you'd like to track, +you may be able to use tracing breakpoints, explained above. +For example, following tracks Line-A calls:

+
+b  LineAOpcode ! LineAOpcode  &&  LineAOpcode < 0xffff  :trace
+
-

Profiling

+

Profiling

Profiling tells where the emulated code spends most of its (emulated) time. It can be used to find out where a program is (apparently) -stuck or what are the largest performance bottlenecks for a program. +stuck, or what are the largest performance bottlenecks for a program.

+

Collecting the profile data

+

Profiling is used by first enabling the profiler (use "dp" for DSP):

@@ -3546,78 +3176,692 @@ And profiling will start once you contin
 > c
 Returning to emulation...
-Allocated CPU profile buffer (18 MB).
+Allocated CPU profile buffer (27 MB).
 

When you get back to the debugger, the collected profiling information -is processed and a summary of in which parts of the RAM the execution -happened is shown: +is processed and a summary of in which parts of memory the execution +happened, and how long it took, is shown:

-Allocated CPU profile address buffer (4 KB).
-Normal RAM (0-0x400000):
-- no activity
-Cartridge ROM (0xFA0000-0xFC0000):
-- no activity
+Allocated CPU profile address buffer (57 KB).
 ROM TOS (0xE00000-0xE80000):
 - active address range:
-  0xe0014c-0xe23f02
+  0xe00030-0xe611a4
 - active instruction addresses:
-  707 (100.00% of all)
+  14240 (100.00% of all)
 - executed instructions:
-  629144 (100.00% of all)
+  4589668 (100.00% of all)
 - used cycles:
-  9408503 (100.00% of all)
-- address with most cycles:
-  0xe0dcca, 402628 cycles (4.28% of all in area)
-- address with most hits:
-  0xe004a4, 4900 hits (0.78% of all in area)
+  56898472 (100.00% of all)
+  = 7.09347s
+Cartridge ROM (0xFA0000-0xFC0000):
+  - no activity
+
+= 7.09347s
 

(DSP RAM will be shown only as single area in profile information.)

+ +

Investigating the profile data

+

-After this you can request more detailed profiling information: +When you're back in debugger, you can inspect the collected profile data:

-> profile
+> h profile
 'profile' - profile CPU code
-Usage:  profile <on|off|counts|cycles|symbols|stats> [show count]
-	on & off enable and disable profiling.  Data is collected
-	until debugger is entered again after which you can view
-	statistics about the data or view PC addresses that took
-	most cycles or functions/symbols called most often.
-	You can specify how many items are shown at most.
+Usage:  profile <subcommand> [parameter]
+
+        Subcommands:
+	        - on
+		- off
+		- counts [count]
+		- cycles [count]
+		- misses [count]
+		- symbols [count]
+		- addresses [address]
+		- callers
+		- stack
+		- stats
+		- save <file>
+		- loops <file> [CPU limit] [DSP limit]
+
+        'on' & 'off' enable and disable profiling.  Data is collected
+	until debugger is entered again at which point you get profiling
+	statistics ('stats') summary.
+
+	Then you can ask for list of the PC addresses, sorted either by
+	execution 'counts', used 'cycles' or cache 'misses'. First can
+	be limited just to named addresses with 'symbols'.  Optional
+	count will limit how many items will be shown.
+
+	'addresses' lists the profiled addresses in order, with the
+	instructions (currently) residing at them.  By default this
+	starts from the first executed instruction, or you can
+	specify the starting address.
+
+	'callers' shows (raw) caller information for addresses which
+	had symbol(s) associated with them.  'stack' shows the current
+	profile stack (this is useful only with :noinit breakpoints).
+
+	Profile address and callers information can be saved with
+	'save' command.
+
+	Detailed (spin) looping information can be collected by
+	specifying to which file it should be saved, with optional
+	limit(s) on how many bytes first and last instruction
+	address of the loop can differ (0 = no limit).
 
-

For example:

+

For example, to see which memory addresses were executed most +and what instructions those have at the end of profiling, use:

 > profile counts 8
 addr:           count:
-0xe004a4        0.78%   4900
-0xe004b6        0.78%   4896
-0xe0dcbc        0.55%   3448
-0xe0dcc6        0.55%   3448
-0xe0f59e        0.55%   3446
-0xe0dcce        0.55%   3445
-0xe0dcd6        0.55%   3445
+0xe06f10        12.11%  555724  move.l    $4ba,d1
+0xe06f16        12.11%  555724  cmp.l     d1,d0
+0xe06f18        12.11%  555724  bgt.s     $e06f06
+0xe06f06        12.11%  555708  move.b    $fffffa01.w,d1
+0xe06f0a        12.11%  555708  btst      #5,d1
+0xe06f0e        12.11%  555708  beq.s     $e06f1e
+0xe00ed8         1.66%  76001   subq.l    #1,d0
+0xe00eda         1.66%  76001   bpl.s     $e00ed8
 8 CPU addresses listed.
 
+

-If you have loaded symbol information for code addresses, with the -"profile symbols" command you get a list of how many times the code -execution passed through the defined symbol addresses. +Then, to see what the executed code and its costs look like +around top addresses: +

+> profile addresses 0xe06f04
+# disassembly with profile data:
+# <instructions percentage>% (<sum of instructions>, <sum of cycles>, <sum of i-cache misses>)
+$e06f04 :             bra.s     $e06f10                    0.00% (48, 576, 0)
+$e06f06 :             move.b    $fffffa01.w,d1            12.11% (555708, 8902068, 0)
+$e06f0a :             btst      #5,d1                     12.11% (555708, 6685268, 0)
+$e06f0e :             beq.s     $e06f1e                   12.11% (555708, 4457312, 0)
+$e06f10 :             move.l    $4ba,d1                   12.11% (555724, 11125668, 0)
+$e06f16 :             cmp.l     d1,d0                     12.11% (555724, 4461708, 0)
+$e06f18 :             bgt.s     $e06f06                   12.11% (555724, 4455040, 0)
+$e06f1a :             moveq     #1,d0                      0.00% (16, 64, 0)
+Disassembled 8 (of active 14240) CPU addresses.
+
+

+Unlike normal disassembly, "profile addresses" command shows only +memory addresses which instructions were executed during profiling. +You get instruction cache misses only when using cycle-accurate 030 +emulation with a Hatari version configured to use WinUAE CPU core. +

+If you have loaded symbol information, symbol names are shown above +the corresponding addresses. With the "profile symbols" command you +get a list of how many times the code execution passed through the +defined symbol addresses.

+ +

Profile data accuracy

+ +

Profile data accuracy depends on Hatari emulation accuracy. +Profile data accuracy from most to least accurate when Hatari's +default emulation options are used is following:

+ + + +

Caller information

+

-After the profiling information has been post-processed, it will -also be shown in the disassembly output. +If you have loaded symbols (see Debug symbols) +before continuing emulation/profiling, additional caller information +will be collected for all the code symbol addresses which are called +as subroutines. This information includes callstack, call counts, +calling instruction type (subroutine call, branch, return etc), and +costs for those calls, both including costs for further subroutine +calls and without them.

+

When debugger is re-entered, current callstack is output before +profiling information:

+
+> a _P_LineAttack
+CPU condition breakpoint 1 with 1 condition(s) added:
+        pc = $30f44
+$030f44 : 48e7 3820                            movem.l   d2-d4/a2,-(sp)
+> c
+...
+CPU breakpoint condition(s) matched 1 times.
+        pc = $30f44
+Finalizing costs for 12 non-returned functions:
+- 0x32a3c: _P_GunShot (return = 0x32b7e)
+- 0x32b18: _A_FireShotgun (return = 0x3229a)
+- 0x3223a: _P_SetPsprite (return = 0x32e86)
+- 0x32e4e: _P_MovePsprites (return = 0x38070)
+- 0x37f44: _P_PlayerThink (return = 0x36ea0)
+- 0x36e44: _P_Ticker (return = 0x260e0)
+- 0x25dcc: _G_Ticker (return = 0x1e4c6)
+- 0x1e29e: _TryRunTics (return = 0x239fa)
+- 0x238e8: _D_DoomLoop (return = 0x2556a)
+- 0x24d7a: _D_DoomMain (return = 0x44346)
+...
+
+ +

("profile stack" command can be used in breakpoints with :noinit +option to show backtraces during caller profiling.)

+ +

Other information collected during profiling is shown with +following command:

+
+> profile callers
+# <callee>: <caller1> = <calls> <types>[ <inclusive/totals>[ <exclusive/totals>]], <caller2> ..., <callee name>
+# types: s = subroutine call, r = return from subroutine, e = exception, x = return from exception,
+#        b = branch/jump, n = PC moved to next instruction, u = unknown PC change
+# totals: calls/instructions/cycles/misses
+0xe00030: 0xffffff = 1 e, _main
+0xe000fe: 0xe00a0c = 1 b, memdone
+0xe0010a: 0xe04e34 = 1 s 1/5/72 1/5/72, _run_cartridge_applications
+0xe00144: 0xe04dbe = 1 s 4/118/1512 1/27/444, _init_acia_vecs
+0xe001ea: 0xe00ec6 = 1 b, _int_acia
+0xe0038c: 0xe04c28 = 1 s 1/191/2052 1/191/2052, _init_exc_vec
+0xe003a6: 0xe04c2e = 1 s 1/388/4656 1/388/4656, _init_user_vec
+...
+
+ +

+For example, if you don't know all the places from which a certain +function is called, or in what context a certain interrupt handler can +be called during the period you're profiling, profile caller +information will tell you: +

+
+callee: caller: calls: calltype:
+  |       |       |   /
+0x379:  0x155 = 144 r, 0x283 = 112 b, 0x2ef = 112 b, 0x378 = 72 s
+583236/359708265/1631189180 72/4419020/19123430, dsp_interrupt
+           |                       |                 |
+    inclusive costs         exclusive costs     callee name
+  (of calls from 0x378)
 
-

Usage examples

+Calltypes: +- b: jump/branch +- n: PC just moved to next address +- r: subroutine return +- s: subroutine call +
+

+(Most "calls" to "dsp_interrupt" were subroutine call returns (=r) +to it from address 0x155.) +

+ +

+With the execution counts in normal profiling data, caller information +can actually be used to have complete picture of what exactly the code +did during profiling. Main/overview work for this analysis is best done +automatically, by the profiler data post-processor (documented below). +

+ + +

Caller data accuracy

+ +

Everything about profile data accuracy applies also to caller costs, +but there are additional things to take into account, mainly because +profiler cannot determine when exceptions are being handled:

+ + + +

Saving profile data to a file

+ +

It's useful to save the profile data to a file: +

+> profile save program-profile.txt
+
+ +

With the saved profile disassembly (and optional caller information) +you can more easily investigate what your program did during +profiling, search symbols & addresses in it, and compare the +results to profiles you've saved from earlier versions of your code.

+ +

You may even create your own post-processing tools for +investigating the profiling data more closely, e.g. to +find +CPU/DSP communication bottlenecks.

+ + +

Profile data post-processing

+ +

Saved profile data can be post-processed with (Python) script +installed by Hatari, to:

+ + + +

Providing symbols for the post-processor

+ +

When the data is post-processed, you should always provide +the post-processor symbols for the profile code! Relying just on the +symbol in the profile data can cause costs to be assigned to wrong +symbol, if symbol's code wasn't called through symbol's own address, +but by jumping inside its code.

+ +

If your code is in fixed location, you should tell +post-processor to handle symbol addresses as absolute (-a):

+
+$ hatari_profile.py -a etos512k.sym emutos-profile.txt
+
+ +

Normal programs are relocated and you should instead give +the symbols as TEXT (code) section relative ones (-r):

+
+$ hatari_profile.py -r program.sym program-profile.txt
+
+ +

If symbols are included to your binary in DRI/GST format, first they +need to be extracted to the ASCII format +understood by the post-processor:

+
+$ gst2ascii -l -o program.prg > program.sym
+
+ +

If there are some extra symbols that you don't want to see +separately in profiles, because they aren't real functions, +but e.g. loop labels, you can either remove them manually +from the ASCII *.sym file, or filter them out with grep: +

+
+$ gst2ascii -l -o program.prg | grep -v -e useless1 -e useless2 > program.sym
+
+ + +

Post-processor provided statistics

+ +

Above post-processor examples just parse + verify the given data +and produce output like this:

+
+Hatari profile data processor
+
+Parsing TEXT relative symbol address information from program.sym...
+[...]
+3237 lines with 1550 code symbols/addresses parsed, 0 unknown.
+
+Parsing profile information from program-profile.txt...
+[...]
+9575 lines processed with 368 functions.
+
+CPU profile information from 'program-profile.txt':
+- Hatari v1.6.2+ (May  4 2013), WinUAE CPU core
+
+ +

To get statistics (-s) and list of top (-t) CPU users in profile, +add "-st" option:

+
+$ hatari_profile.py -st -r program.sym program-profile.txt
+[...]
+CPU profile information from 'program-profile.txt':
+- Hatari v1.6.2+ (May  4 2013), WinUAE CPU core
+
+Time spent in profile = 34.49539s.
+
+Calls:
+- max = 187738, in __toupper at 0x52b88, on line 8286
+- 1585901 in total
+Executed instructions:
+- max = 1900544, in flat_remap_mips+14 at 0x47654, on line 7020
+- 64499351 in total
+Used cycles:
+- max = 15224620, in flat_remap_mips+18 at 0x47658, on line 7022
+- 553392132 in total
+Instruction cache misses:
+- max = 184308, in _BM_T_GetTicks at 0x43b90, on line 4772
+- 4941307 in total
+
+Calls:
+  11.84%      187698  __toupper
+  11.48%      182105  _BM_T_GetTicks
+  11.48%      182019  _I_GetTime
+[...]
+Executed instructions:
+  34.83%    22462729  flat_generate_mips
+  14.08%     9080215  flat_remap_mips
+   8.55%     5515945  render_patch_direct
+   5.09%     3283328  _TryRunTics
+[...]
+Used cycles:
+  23.62%   130702768  flat_generate_mips
+  12.42%    68735832  flat_remap_mips
+   9.77%    54041148  _TryRunTics
+   5.80%    32111536  correct_element
+[...]
+Instruction cache misses:
+  37.03%     1829764  _TryRunTics
+  11.20%      553314  _BM_T_GetTicks
+   9.44%      466319  _NetUpdate
+   9.27%      457899  _HGetPacket
+[...]
+
+ +

If you want to see also symbol addresses and what is per call +cost, add -i option:

+

+$ hatari_profile.py -st -i -r program.sym program-profile.txt
+[...]
+Executed instructions:
+  34.83%    22462729  flat_generate_mips   (0x04778a, 774576 / call)
+  14.08%     9080215  flat_remap_mips      (0x047646, 313110 / call)
+   8.55%     5515945  render_patch_direct  (0x047382, 29977 / call)
+   5.09%     3283328  _TryRunTics          (0x042356, 19660 / call)
+[...]
+Used cycles:
+  23.62%   8.14728s  130702768  flat_generate_mips  (0x04778a, 0.28094s / call)
+  12.42%   4.28461s   68735832  flat_remap_mips     (0x047646, 0.14775s / call)
+   9.77%   3.36863s   54041148  _TryRunTics         (0x042356, 0.02017s / call)
+   5.80%   2.00165s   32111536  correct_element     (0x04a658, 0.00001s / call)
+[...]
+Instruction cache misses:
+  37.03%     1829764  _TryRunTics          (0x042356, 10956 / call)
+  11.20%      553314  _BM_T_GetTicks       (0x043b90, 3 / call)
+   9.44%      466319  _NetUpdate           (0x041bcc, 5 / call)
+   9.27%      457899  _HGetPacket          (0x041754, 5 / call)
+[...]
+
+ +

(For cycles the "per call" information is in seconds, not as +a cost count.)

+ +

If your profile file contains caller information, you should +add -p option to see it, as that will also help in detecting symbol +issues (see Interpreting +the numbers):

+

+$ hatari_profile.py -st -p -r program.sym program-profile.txt
+[...]
+9575 lines processed with 368 functions.
+[...]
+Of all 1570498 switches, ignored 581 for type(s) ['r', 'u', 'x'].
+
+CPU profile information from 'badmood-level-load-CPU.txt':
+- Hatari v1.6.2+ (May  4 2013), WinUAE CPU core
+[...]
+Calls:
+  11.84%  11.84%      187698    187698  __toupper
+  11.48%  11.48%      182105    182105  _BM_T_GetTicks
+  11.48%  22.95%      182019    364038  _I_GetTime
+[...]
+Executed instructions:
+  34.83%  34.86%  34.86%    22462729  22484024  22484024  flat_generate_mips
+  14.08%  14.10%  14.10%     9080215   9091270   9091676  flat_remap_mips
+   8.55%                     5515945                      render_patch_direct
+   5.09%   5.11%  94.96%     3283328   3294022  61247717  _TryRunTics
+[...]
+Used cycles:
+  23.62%  23.69%  23.69%   130702768 131100604 131100604  flat_generate_mips
+  12.42%  12.46%  12.46%    68735832  68928816  68930904  flat_remap_mips
+   9.77%   9.80%  95.66%    54041148  54238744 529368824  _TryRunTics
+   5.80%   5.82%   5.82%    32111536  32193664  32193664  correct_element
+[...]
+Instruction cache misses:
+  37.03%  37.14%  98.57%     1829764   1835261   4870573  _TryRunTics
+  11.20%  11.24%  11.24%      553314    555191    555191  _BM_T_GetTicks
+   9.44%   9.49%  29.13%      466319    468782   1439340  _NetUpdate
+   9.27%   9.29%   9.37%      457899    459197    463217  _HGetPacket
+[...]
+
+ +

Now there's a message telling that some of the calls were ignored +because according to their "call type", they were actually returns from +exceptions, not real calls (this is mainly important for callgraph +generation, discussed below).

+ + +

Interpreting the results

+ +

In addition to accuracy issues mentioned in previous Profiling +sections, function/symbol level costs have gotchas of their own.

+ +

The first cost percentage and count columns are sums for all +the instructions that were in profile data file between +the indicated symbol's address and the address of the next symbol +(= "between-symbols" cost).

+ +

NOTE: If your symbol file doesn't contain addresses +for all the relevant symbols, results from this can be misleading because +instructions costs get assigned to whatever symbol's address +happened to precede those instructions. And you don't see which +caller is causing it from caller info or callgraph either, as entry +point for that time sink lacking a symbol means profiler hadn't +tracked calls to it...

+ +

The next two cost percentage and count columns are for subroutine +calls costs, first one for exclusive and latter for inclusive cost +i.e. including costs for further subroutine calls. Values are based on +caller information documented above.

+ +

Reasons why between-symbol costs, and subroutine call costs can +differ, are following:

+ + +

In the first case, you should check the profile data to find out +whether there are missing symbols for executed function entry points. +You can notice function entry points as address gap and/or code +retrieving arguments from stack. Exit points can be seen from RTS +instructions.

+ +

Second case can also be seen from the profile data. Call count +is same as count for how many times first instruction is executed +(worst case: large loop on subroutine's first instruction).

+ +

While subroutine costs should be more accurate and relevant, due to +code optimizations many of the functions are not called as subroutines +(on m68k, using JSR/BSR), but just jumped or branched to. Because of +this, it's useful to compare both subroutine and between-symbols +costs. One should be able to see from the profile disassembly which +of the above cases is cause for the discrepancy in the values.

+ +

NOTE: Before starting to do any serious source +level optimizations, you should always verify from profile +data (disassembly) where exactly the costs are in a function, to make +sure your optimization efforts can actually help the performance.

+ + +

Generating and viewing callgraphs

+ +

Callgraphs require that saved profile data contains caller +function address information, i.e. symbols for the code should +be loaded before starting profiling it (see +loading symbol data).

+ +

Separate callgraphs will be created for each of the costs +(0=calls, 1=instructions, 2=cycles) with the -g option:

+
+$ hatari_profile.py -p -g -r program.sym program-profile.txt
+[...]
+Generating 'program-profile-0.dot' DOT callgraph file...
+
+Generating 'program-profile-1.dot' DOT callgraph file...
+
+Generating 'program-profile-2.dot' DOT callgraph file...
+[...]
+
+ +

Callgraphs are saved in GraphViz +"dot" format. Dot files can be viewed:

+ + +

Produced callgraph will look like this:

+
+ + Part of callgraph + +
+ +

Interpreting the callgraph:

+ + + +

Making large callgraphs readable

+ +

If profile is for larger and more varied amount of code +(e.g. program startup), the resulting callgraph can be so +huge it's unreadable.

+ +

If your code has interrupt handlers, they can get called +at any point, which can show in callgraph as "explicit" calls +from the interrupted functions. To get rid of such incorrect +calls, give interrupt handler names to --ignore-to option:

+
+$ hatari_profile.py -p -g --ignore-to handler1,handler2 -r program.sym program-profile.txt
+
+ +

In large callgraph most of the functions aren't really interesting, +because their contribution to the cost is insignificant. You can +remove large number of them with --no-leafs and --no-intermediate +options, those options act only on nodes which costs are below +given threshold. Leaf nodes are ones which don't have any parents +and/or children. Intermediate ones have only single parent and +children (node calling itself is not taken into account). + +

Threshold for this is given with the --limit (-l) option. With +that it typically makes also sense to change the node emphasis +threshold with --emph-limit (-e) option:

+
+$ hatari_profile.py -p -g -l 0.5 -e 2.0 -r program.sym program-profile.txt
+
+ +

If you're not interested in from how many different addresses +a given function calls another function, use --compact option. If you +still see multiple calls between two nodes with it, the reason is that +they happened through different call paths which were removed from +the callgraph after --compact option was applied:

+
+$ hatari_profile.py -p -g -l 1.0 -e 2.0 --no-leafs --no-intermediate --compact -r program.sym program-profile.txt
+
+ +

If even this doesn't help, you can remove all nodes below +the given cost threshold limit with --no-limited option, but this +often doesn't leave much of a call hierarchy. Instead you may +consider removing all nodes except for subroutine call ones, with the +--only-subroutines option.

+ +

If you have trouble locating nodes you're specially interested +about, you can either color them differently with the --mark option, +or exclude everything else from the callgraph except those nodes and +their immediate callers & callees, with the --only option:

+
+$ hatari_profile.py -p -g --only func1,func2 -r program.sym program-profile.txt
+
+ +

Last option for reading the callgraph is using -k option to +export the data for use in (Linux) Kcachegrind UI. Kcachegrind generates +callgraphs on the fly, and just for the area around the function +you selected, so navigating in callgraph may be easier. It also +shows the related profile disassembly, which can make verifying +matters easier:

+
+$ hatari_profile.py -p -k -r program.sym program-profile.txt
+[...]
+Generating callgrind file 'program-profile.cg'...
+[...]
+$ kcachegrind program-profile.cg
+
+
+ Kcachegrind screenshot +
+ + +

Usage examples

Here's a list of some common debugging tasks and how to do them @@ -3626,13 +3870,13 @@ with the Hatari debugger:

Stopping on program startup and examining its data
-
Please see Breakpoint variables -and Inspecting emulation state +
Please see Breakpoint variables +and Inspecting emulation state sections.
Tracing specific things in the system
-
To trace e.g. all GEMDOS calls and IO operations, use: +
To trace e.g. all GEMDOS calls and I/O operations, use:
 trace  gemdos,io_all
 
@@ -3648,6 +3892,24 @@ a $12345 :6
+
Stopping when specific exception happens
+
Hatari's -D option doesn't invoke debugger on all exceptions and +doesn't allow invoking debugger just for specific exceptions. To +stop at specific exception, one can check when it's called. +At the start of memory is the CPU exception table for exception +handler addresses, so to stop e.g. at bus error with some extra +information, one can use following: +
+history  on
+b  pc=($8)
+
+After bus error invokes debugger, 'history' command can then be used +to see (executed memory addresses with their current) instructions +leading to the error. The most interesting vector addresses are: +$8 (Bus error), $C (Address error), $10 (Illegal instruction), +$14 (Division by zero). See also --debug-except option. +
+
Stopping when register has a specific value
To stop when e.g. D1 register contains value 5, set a breakpoint on:
@@ -3672,7 +3934,7 @@ b  d1 > 9  &&  d1 < 31
 
 
Stopping when memory location has a specific value
To stop when e.g. bit 1 of the Video Shifter Sync Mode byte at -IO address $ff820a is set i.e. video frequency is 60Hz, set +I/O address $ff820a is set i.e. video frequency is 60Hz, set a breakpoint on:
 b  ($ff820a).b & 2 = 2
@@ -3688,7 +3950,7 @@ b  ($ff820a).b & 2 ! ($ff820a).b & 2
 
Tracing all changes in specific memory location
-
To see the new values and continue without stopping, use +
To see the new values and continue without stopping, add the ":trace" breakpoint option:
 b  ($ff820a).b & 2 ! ($ff820a).b & 2  :trace
@@ -3710,37 +3972,56 @@ b  d0 = "d0 + 10"
 
+
Examining specific system call return value
+
To check e.g. what's the Fopen() GEMDOS call return value, +check with "info gemdos 1" its opcode, set a breakpoint for that +and step to next (n) instruction from the trap call when breakpoint +is hit. GEMDOS call return value is then in register D0: +
+> trace  gemdos
+> b  GemdosOpcode = $3D
+> c
+[...continue until breakpoint...]
+1. CPU breakpoint condition(s) matched 1 times.
+        GemdosOpcode = $3D
+> n
+GEMDOS 0x3D Fopen("TEST.TXT", read-only)
+> e  d0
+= %1000000 (bin), #64 (dec), $40 (hex)
+
+
+
Seeing code leading to a breakpoint
-
To see the instructions executed before debugger was entered, -you need to enabled history tracking beforehand and then whenever the -debugger is entered, you can request given number (here 16) of past -instructions to be shown: +
To see CPU instructions executed before debugger was entered, +you need to enable history tracking before it. Whenever +debugger is entered, you can then request given number (here 16) of +past instructions to be shown:
-history on
+history  cpu
 c
 [breakpoint is hit and debugger entered]
-history 16
+history  16
 
Getting instruction execution history for every breakpoint
-To see last 16 instructions whenever (a normal or tracing) breakpoint -is hit: +To see last 16 instructions for both CPU and DSP whenever +(a normal or tracing) breakpoint is hit:
-history on
-lock history 16
+history  on
+lock  history 16
 c
 
-
Single step so that new register values are shown after each step
+
Single stepping so that new register values are shown after each step
-lock registers
-c 1
+lock  registers
+s
 [new register values]
-c 1
+s
 [new register values]
 ...
 
@@ -3760,7 +4041,7 @@ you enter debugger manually etc, write t
 lock  file stack.ini
 
-Please see also Chaining breakpoints +Please see also Chaining breakpoints section for more examples on what you can do with the debugger input files.
@@ -3772,18 +4053,46 @@ c [after a while, use AltGr+Pause to get back to debugger] profile counts
+Please see Profiling section for more info. +
+ +
Seeing program callstack when breakpoint is hit
+
Profiler caller data includes +callstack information (with some limitations). +
+ +
Seeing call backtraces whenever given function is called
+
Enable profiling, load symbols for the program and set breakpoint +for the function you're interested about, in the following way: +
+profile on
+symbols prg
+b  pc = _my_function  :quiet :noinit :file showstack.ini
+
+I.e. whenever 'my_function' address is called, quietly trigger a +breakpoint without resetting profiling (callstack) information and run +debugger command(s) from the 'showstack.ini' debugger script file, +which contains following command: +
+profile stack
+
+
+ +
Seeing how program functions/symbols call each other
+
Profile data +post-processing can provide execution callgraphs.

Hint: for most of the above commands, one just needs to prefix them with -"d" (or "dsp" if using full command names) to do similar operation on +"d" (or "dsp" when using full command names) to do similar operation on the DSP.

-

Build notes

+

Build notes

Lastly, the debugger is much nicer to use with the command line @@ -3802,7 +4111,7 @@ By default it should be enabled.

-

Performance

+

Performance

Hatari performance varies between Atari programs, depending on what features Hatari needs to emulate for them. Less accurate Atari @@ -3813,7 +4122,7 @@ overhead.

have a noticeable effect on performance.

-

Improving Hatari performance

+

Improving Hatari performance

Hatari currently runs best in 16 or 32 bits per pixel color depth @@ -3851,16 +4160,16 @@ can be slower despite optimizations.

-

Emulation options

+

Emulation options

Emulation options have the largest impact on performance. These options can be changed from the Hatari GUI System dialog and the emulation needs to be rebooted for any of these changes to take -an effect! +an effect! They're enabled by default.

-
DSP
+

DSP

Emulating the Falcon DSP is performance-wise several times more demanding than emulating the m68k; DSP runs at higher frequency, executes many @@ -3871,7 +4180,7 @@ that do use DSP, many use it only for ba fine without the real DSP emulation.

-
Timer-D
+

Timer-D

The single largest factor contributing to general Hatari emulation performance is the handling of interrupts. Enabling Timer-D patching @@ -3880,7 +4189,15 @@ significantly reduces the number of inte Atari machine. Using this has adverse effect only for very rare programs.

-
Compatible CPU
+

FDC

+

+While accurate FDC emulation doesn't take that much CPU, it slows down +floppy image accesses (and Hatari startup) a lot. Only very +few demos and games require accurate FDC emulation for their copy protection, +so enabling fast floppy access is fairly safe. +

+ +

Compatible CPU

After the DSP and interrupts, m68k emulation takes most time. Disabling the "Slower but more compatible CPU" option will speed up @@ -3899,15 +4216,15 @@ machine.

-NOTE: Above options may cause some programs not to work correctly. +NOTE: Above options may cause some programs to work in correctly. The Hatari Software Compatibility List -lists programs known to need real real Falcon DSP emulation or Timer-D -frequency. Disabling "Compatible CPU" option is recommended only as -a last resort. +lists programs known to need real Falcon DSP emulation, Timer-D +frequency or accurate FDC timings. Disabling "Compatible CPU" option +is recommended only as a last resort.

-

Emulator options

+

Emulator options

Emulator options don't usually have as large effect on performance as @@ -3916,7 +4233,7 @@ just the quality of the emulation "outpu be toggled at run-time without rebooting the emulation.

-
Sound
+

Sound

Internal Hatari sound handling and the SDL_mixer sound thread libALSA sound processing can account up to 1/3 of the Hatari CPU usage @@ -3927,7 +4244,7 @@ in Hatari as this can significantly redu interrupts.

-
Frame skipping
+

Frame skipping

Screen rendering can take noticeable amount of CPU time. The default Hatari "auto" frame skipping should be used unless there's a good @@ -3944,7 +4261,7 @@ emulation to run slower than a real Atar Hatari does redundant work to convert frames you can't see.

-
Zooming
+

Zooming

If you are not using frame skip, disabling zooming can have noticeable improvement on performance. You can do this by specifying @@ -3955,7 +4272,7 @@ mode-lines (e.g. "320x200") to your xorg to use zooming, disabling borders may help a bit.

-
Spec512 color handling
+

Spec512 color handling

Handling Spec512 color modes which change the ST/e palette constantly takes some extra CPU. If you have problems with CPU usage in such @@ -3965,7 +4282,7 @@ completely by zeroing the threshold for --spec512 0 option.

-
Statusbar and drive LED
+

Statusbar and drive LED

If your version of the SDL library uses VSync to synchronize the screen output, drawing of the statusbar or the drive LED may have some minor @@ -3973,7 +4290,7 @@ impact on performance too. Normally the

-

Measuring the performance

+

Measuring the performance

There are a couple of ways to monitor and measure Hatari performance. @@ -4021,9 +4338,9 @@ at the same time you're making the measu

-

Appendix

+

Appendix

-

Copying

+

Copying

This program is free software; you can redistribute it and/or modify @@ -4045,15 +4362,13 @@ Inc., 51 Franklin Street, Fifth Floor, B Foundation | The GNU General Public License

-

Introduction to Emulation

+

Introduction to Emulation

Emulation via software is an art and Hatari is an example of this.

Emulation is to make a computer behave like a (probably) completely -different machine on the lowest possible niveau. +different machine on the lowest possible level. This includes CPU and custom chip emulation allowing software written -for the emulated machine to be run without notice. -A good emulator will run most of the software intended for the emulated -platform without trouble. +for the emulated machine to be run without it noticing a difference.

The key to emulation is to simply do those things with a software @@ -4077,24 +4392,11 @@ error-free using such a simple loop syst

But in most cases the CPU emulation is the simplest part. Correct -emulation of the various custom chips and hardware -parts of the emulated system is much trickier. +emulation of the various custom chips and hardware parts of the +emulated system, and their proper synchronization, is much trickier.

-
+
-
- - - - - - - -
Valid HTML 4.01! - June 2012 -