21.09..1996 Mika Heiskanen mheiskan@delta.hut.fi PROFILER V4.0 for HP48GX ^^^^^^^^^^^^^^^^^^^^^^^^ The commands in Profiler library provide an easy way to do some simple analysis on the execution times of the commands and subprograms in a library. Profiler also can provide the full path to a command which has caused a crash, and a command to modify individual commands in a library for quick tests. The library can be stored in covered ports. For example when you want to know what happens when you execute RSIM command in ALG48 libray (lid 909) you do this: 909 TMK Creates dummy lib for speed measuring 'X+Y' RSIM Execute RSIM command from the dummy library TRES Analyze the data in 'Times' variable View the returned text string TINI Initialize counter data for another test '(X+Y)/2' RSIM Do the second test TRES Analyze the data from the second test run View the returned analysis TPG Purge the dummy library, leaving the original ALG48 library active. Commands: Name: TMK Stack: ( %lid --> ) Desc: Creates dummy library for the library for the given library. Stores and activates the dummy in port 0. Errors if library is missing or it doesn't have any commands. For convenience TINI is automatically executed for the created dummy or the already existing dummy. Name: TINI Stack: ( --> ) Desc: Find the latest dummy lib from port 0 and create variable 'Times' in HOME for holding the timing counters. Name: TPG Stack: ( --> ) Desc: Detach and purge the latest dummy library from port 0. Name: TMOD Stack: ( ob romptr --> ) Desc: Returns a library in which the romptr contents have been changed into ob. The original is not overwritten in any way so all machine language jumps work as they should. The purpose of the command is to speed up testing small changes in libraries. Trying to change a profiled library or a non-existent romptr will generate an error. Name: TNAM Stack: ( $names %romid --> ) Desc: Given a string containing romptr names for a library, returns the corresponding 'Names' and 'Romps' variable. Names is returned in a form suitable for both the Profiler and INCLUDE command in Jazz. Romps is a variable used by Jazz disassembler to give names to romptrs. For example my input for ALG48 would look like: "xRSIM xFCTR xAADD ... PFactSpl PFactor " Note especially that the last line should terminate in the newline character too. Name: TRES Stack: ( --> $ ) Desc: Analyze the counters in 'Times' variable and return a readable string of the form: +---------------------------- |Cmd Calls Time Percent Name | 0 n0 x.yyy % xx.yy | 1 n1 x.yyy % xx.yy |... Cmd: The command number of the romp Calls: How many times was the romp called. Time: Execution time for all the calls. Percent: Percentage of the total execution time. TRES will automatically assign names for each romp if there exists a variable 'Names' in HOME containing a string. Each line in the string is considered one name which should be appended to the corresponding line in output. Blank lines are allowed. For example if analyzing ALG48 you could store "xRSIM xFCTR .. " in 'Names'. For convenience any leading "DEFINE " on the line is skipped. TRES will not output any line which has a zero call count unless this is specificly enabled by setting user flag 1. Note that the times for programs include the times for their subprograms. Thus if you execute a single command in the library for testing that romp will always get %100.00 percentage. If the profiling run is somehow aborted the information in Times will be incomplete for any romptr that was running, in particular time information is lost. However the Profiler will be able to provide the full path to the command where the abort occurred! So for example your program crashes or you use ON-C to abort a jammed program, simply execute TRES and follow the indexed path to the command where the problem occurred. The indexes are shown in the place of timing information and are surrounded with brackets for easy identification. Warnings: Obviously the dummy lib uses the RPL stream to get a timer stopped after an indivudual romp has been executed. Thus any romp which modifies the previous streams is a no-no for the profiler. Most common example is :: 'R ; eg a command which operates on 'next' object in stream. In this case the next object would be the timer stopping code. Depending on anything can happen in this case, most notably a crash. Apparently there are some conditions under which you cannot stop the timer freely. Thus this new version of the Profiler winds back the clock by the estimated overhead whenever a single romp is executed. Thus your clock will miss some ticks, the total number depending on the number of romp calls done in the test run. However due to the 'accurate' measurements I did the overhead in the results is now clearly smaller. Note that if you get a suspiciously large time for some romptr, garbage collection may have occurred during that program. Try another test run to see if this was the case. The timing code generates an error if 'Times' variable is not found. If the program being tested has an error trap this may cause weird behaviour. Should be quite rare though since both TMK and TINI create the 'Times' variable. If the program being tested operates on home directory the 'Times' variable may be moved around during execution. This means that there will be extra overhead due to repeated searches for the variable (instead of using a RAM variable shortcut) and thus the results will show larger execution times than they should. The program is a hack. Hacked input could cause crashes, although I I took care of typical problems. For a very simple crash example just consider the typical French 'protection' of making the size field in link tables much too large. I have no interest in trying to detect such tricks. Notes: The program can be quite easily converted so that it will work in SX, but I personally don't have the interest for doing so. However the package includes the full GNU source code for the library, so anyone wishing to convert the library for SX is free to do so.