📄 mal_debugger.mx
字号:
@' The contents of this file are subject to the MonetDB Public License@' Version 1.1 (the "License"); you may not use this file except in@' compliance with the License. You may obtain a copy of the License at@' http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html@'@' Software distributed under the License is distributed on an "AS IS"@' basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the@' License for the specific language governing rights and limitations@' under the License.@'@' The Original Code is the MonetDB Database System.@'@' The Initial Developer of the Original Code is CWI.@' Portions created by CWI are Copyright (C) 1997-2007 CWI.@' All Rights Reserved.@a M.L. Kersten@* The MAL DebuggerIn practice it is hard to write a correct MAL program thefirst time around. Instead, it is more often constructed bytrial-and-error. As long as there are syntax and semantic errorsthe MAL compiler provides a sufficient handle to proceed. Onceit passes the compiler we have to resort to a debugger toassess its behavior.@menu* Program Debugging ::* Handling Breakpoints::* Profile Switches::* Program Inspection::* Runtime Inspection::@end menu@node Program Debugging, Handling Breakpoints, The MAL Debugger, The MAL Debugger@+ Program DebuggingTo ease debugging and performance monitoring, the MAL interpretercomes with a gdb-like debugger.An illustrative session elicits the functionality offered.@example>function test(i:int):str;> io.print(i);> i:= i*2;> b:= bat.new(:int,:int);> bat.insert(b,1,i);> io.print(b);> return test:= "ok";>end test;>user.test(1);[ 1 ]#-----------------## h t # name# int int # type#-----------------#[ 1, 2 ]@end exampleThe debugger can be entered at any time using the call mdb.start().An overview of the available commands is readily available.@example>mdb.start();#mdb !end main;mdb>help next -- Advance to next statement continue -- Continue program being debugged catch -- Catch the next exception break [<var>] -- set breakpoint on current instruction or <var> delete [<var>] -- remove break/trace point <var> debug <int> -- set kernel debugging mask dot [<int>] [<file>] -- generate the dependency graph step -- advance to next MAL instruction module -- display a module signatures atom -- show atom list finish -- finish current call exit -- terminate executionr quit -- turn off debugging list <obj> -- list current program block List <obj> -- list with type information var <obj> -- print symbol table for module optimizer <obj> -- display program after optimizer step print <var> -- display value of a variable print <var> <cnt>[<first>] -- display BAT chunk info <var> -- display bat variable properties run -- restart current procedure where -- print stack trace down -- go down the stack up -- go up the stack trace <var> -- trace assignment to variables set @verb{ { }timer,flow,io,memory@verb{ } } -- set trace switches unset -- turn off switches help -- this messagemdb>@end exampleThe term @sc{<obj>} is an abbreviation for a MAL operation @sc{<mod>.<fcn>}, optionally extended witha version number, i.e. @sc{[<nr>]}.The @sc{var} denotes a variable in the current stack frame.Debugger commands may be abbreviated.We walk our way through a debugging session, highlighting theeffects of the debugger commands.The call to mdb.start() has been encapsulated in a completeMAL function, as shown by issuing the list command.A more detailed listing shows the binding to the C-routineand the result of type resolution.@example>mdb.start();#end main;mdb>lfunction user.main():int; mdb.start();end main;mdb>Lfunction user.main():int; # 0 (main:int) mdb.start(); # 1 MDBstart (_1:void)end main; # 2@end exampleThe user module is the default place for function defined atthe console. The modules loaded can be shown typeing thecommand 'module' (or 'm' for short). The function signatures become visible using the module and optionallythe function name.@examplemdb>m alarm#command alarm.alarm(secs:int,action:str):void address ALARMsetalarm;#command alarm.ctime():str address ALARMctime;#command alarm.epilogue():void address ALARMepilogue;#command alarm.epoch():int address ALARMepoch;#command alarm.prelude():void address ALARMprelude;#command alarm.sleep(secs:int):void address ALARMsleep;#command alarm.time():int address ALARMtime;#command alarm.timers():bat[:str,:str] address ALARMtimers;#command alarm.usec():lng address ALARMusec;mdb>m alarm.sleep#command alarm.sleep(secs:int):void address ALARMsleep;mdb>@end exampleThe debugger mode is left with a <return>.Any subsequent MAL instruction re-activates the debugger toawait for commands. The default operation is to step throughthe execution using the 'next' ('n') or 'step' ('s) commands,as shown below.@example>user.test(1);# user.test(1);mdb>n# io.print(i);mdb>[ 1 ]# i := calc.*(i,2);mdb># b := bat.new(:int,:int);mdb>@end exampleThe last instruction shown is next to be executed. The result can beshown using a print statement, which contains the location ofthe variable on the stack frame, its name, its value and type.The complete stack frame becomes visible with 'values' ('v')command:@example# bat.insert(b,1,i);mdb># io.print(b);mdb>v#Stack for 'test' size=32 top=11#[0] test = nil:str#[1] i = 4:int#[2] _2 = 0:int unused#[3] _3 = 2:int constant#[4] b = <tmp_1226>:bat[:int,:int] count=1 lrefs=1 refs=0#[5] _5 = 0:int type variable#[6] _6 = nil:bat[:int,:int] unused#[7] _7 = 1:int constant#[8] _8 = 0:int unused#[9] _9 = "ok":str constant@end exampleThe variables marked 'unused' have been introduced as temporary variables,but which are not referenced in the remainder of the program.It also illustrates basic BAT properties, a complete description of whichcan be obtained using the 'info' ('i') command.A sample of the BAT content can be printed passing tuple indices, e.g.'print b 10 10' prints the second batch of ten tuples.@node Handling Breakpoints, Profile Switches, Program Debugging, The MAL Debugger@+ Handling BreakpointsA powerful mechanism for debugging a program is to set breakpointsduring the debugging session.The breakpoints are designated by a target variable name,a [module.]function name, or a MAL line number (#<number>).The snippet below illustrates the reaction to set a break pointon assignment to variable 'i'. @example>mdb.start();#end main;mdb>>user.test(1);# user.test(1);mdb>break ibreakpoint on 'i' not setmdb>n# io.print(i);mdb>break imdb>c[ 1 ]# i := calc.*(i,2);mdb>@end exampleThe breakpoints remain in effect over multiple function calls.They can be removed with the @sc{delete} statement.A list of all remaining breakpoints is obtained with @sc{breakpoints}.The interpreter can be instructed to call the debugger as soon as an exceptionis raised. Simply add the instruction @sc{mdb.setCatch(true)}.@node Profile Switches, Program Inspection, Handling Breakpoints, The MAL Debugger@+ Profile SwitchesSwitches control the level of detail output shown while debuggingor tracing program execution.They are toggled with the @sc{set} and @sc{unset} command.The following switches are currently supported:@table @sc@item timeractivates a listing of all instructions being executed.It is measured in wall-clock time.@item flowshows the total byte size of all BAT target results and input arguments.It is a good indicator on the amount of data being processed.@item memorykeeps track on growing memory needs.@item iokeeps track on the amount of physical IOand is used to detect operators consuming excessive amounts of space.@end tableThe snippet below shows setting the @sc{memory} and @sc{timer}switch. The switches take effect at the next instruction.@examplemdb>set timermdb>set flowmdb>c[ 3 ]# 26 usec# 0 0# io.print(i=3)# 6 usec# 0 0# i := calc.*(i=6, _3=2)# 10 usec# 0 0# b := bat.new(_5=0, _6=0)# 7 usec# 0 8# bat.insert(b=<tmp_167>bat[:int,:int]@verb{ { }1@verb{ } }, _8=1, i=6)#-----------------## h t # name# int int # type#-----------------#[ 1, 6 ]# 41 usec# 0 8# io.print(b=<tmp_167>bat[:int,:int]@verb{ { }1@verb{ } })# 7 usec# 0 0# return test := "ok";# 211 usec# 0 0# user.test(_2=3)@end example@node Program Inspection, Runtime Inspection, Profile Switches, The MAL Debugger@+ Program Inspection The debugger commands available for inspection of the program andsymbol tables are:@table @sc@item list (List) [<mod>.<fcn>['['<nr>']']]A listing of the current MAL block, or one designatedby the <mod>.<fcn> is produced.The @sc{[<nr>]} extension provides access to an elementin the MAL block history.The alternative name 'List' also produces the type information.@item optimizer [<mod>.<fcn>['['<nr>']']]Gives an overview of the optimizer actions in the history of the MAL block.Intermediate results can be accessed using the list command.@item atomsLists the atoms currently known@item modules [<mod>]Lists the modules currently known. An optional <mod> argumentproduces a list of all signatures within the module identified.@item dot [<mod>.<fcn>['['<nr>']']] [<file>]A dataflow diagram can be produced using the @sc{dot} command.It expects a function identifier with an optional history indexand produces a file for the Linux program @sc{dot},which can produce a nice, multi-page graph to illustrate plancomplexity.@end table@examplemdb>dot user.test@end exampleThis example produces the @sc{user-tst.dot} in the currentworking directory. The program call@exampledot -Tps user-tst-0.dot -o user-tst-0.ps@end examplecreates a postscript file with the graphs. With the Adobe reader professionalyou can break it up into multiple pages. An alternativeis the program available from @sc{http://www.tug.org/tex-archive/support/poster/poster.c}The result is shown in the figure below:Since the flow graphs become rather complex, an optional variablelist limits its size.[TODO]@node Runtime Inspection, The MAL Profiler, Program Inspection, The MAL Debugger@+ Runtime Inspection and ReflectionPart of the debugger functionality can also be used directly withMAL instructions. The execution trace of a snippet of code can be visualized encapsulation with @sc{mdb.setTrace(true)} and @sc{mdb.setTrace(false)}.Likewise, the performance can be monitored with the command @sc{mdb.setTimer(on/off)}.Using a boolean argument makes it easy to control the (performance) traceat run time. The following snippet shows the effect of patchingthe test case.@example>function test(i:int):str;> mdb.setTrace(true);> io.print(i);> i:= i*2;> b:= bat.new(:int,:int);> bat.insert(b,1,i);> io.print(b);> mdb.setTrace(false);> return test:= "ok";>end test;>user.test(1);# mdb.setTrace(_3=true)[ 1 ]# io.print(i=1)# i := calc.*(i=2, _5=2)# b := bat.new(_7=0, _8=0)# bat.insert(b=<tmp_1226>, _10=1, i=2)#-----------------## h t # name# int int # type#-----------------#[ 1, 2 ]# io.print(b=<tmp_1226>)# 261 usec! user.test(_2=1)>@end exampleThe command @sc{mdb.setTimer()} toggles the performance traceing flag. The argument is a boolen to designate its state. The primary output of the timer switch is statistics in micro-seconds,the memory tracer shows the arena increment, and the IO tracershows in- and out-blocks.The time spent on preparing the trace information is excludedfrom the report.For more detailed timing information the Linuxtool @emph{valgrind} may be of help.The routines @sc{mdb.setFlow()}, @sc{mdb.setMemory()}, and @sc{mdb.setIO()} (de-)activate the other switches.@example>function test(i:int):str;> mdb.setTimer(true);> io.print(i);> i:= i*2;> b:= bat.new(:int,:int);> bat.insert(b,1,i);> io.print(b);> mdb.setTimer(false);> return test:= "ok";>end test;>user.test(1);# 6 usec# mdb.setTimer(_3=true)[ 1 ]# 43 usec# io.print(i=1)# 5 usec# i := calc.*(i=2, _5=2)# 24 usec# b := bat.new(_7=0, _8=0)# 10 usec# bat.insert(b=<tmp_1226>, _10=1, i=2)#-----------------## h t # name# int int # type#-----------------#[ 1, 2 ]# 172 usec# io.print(b=<tmp_1226>)# 261 usec# user.test(_2=1)@end exampleIt is also possible to activate the debugger from within a program using @sc{mdb.start()}. It remains in this mode until you either issue a quit command, or the command mdb.stop() instruction isencountered. The debugger is only activated when the user can direct its executionfrom the client interface. Otherwise, there is no proper input channeland the debugger will run in trace mode.The program listing functionality of the debugger is also captured in the MAL debugger module. The current codeblock can be listed using @sc{mdb.list()} and @sc{mdb.List()}.An arbitrary code block can be shown with @sc{mdb.list}(@emph{module},@emph{function})and @sc{mdb.List}(@emph{module},@emph{function}).A BAT representation of the current function is return by @sc{mdb.getDefinition()}@.The symbol table and stack content, if available, can be shown withthe operations @sc{mdb.var()} and @sc{mdb.list}(@emph{module},@emph{function})Access to the stack frames may be helpful in the context of exception handling.The operation @sc{mdb.getStackDepth()} gives the depth and individualelements can be accessed as BATs using @sc{mdb.getStackFrame(@emph{n})}.The top stack frame is accessed using @sc{mdb.getStackFrame()}.@{@- Compilation controlBeing able to debug comes at a price.It should be possible to turn off the feature at compile time.@h#ifndef _MAL_DEBUGGER_H#define _MAL_DEBUGGER_H#include "mal_scenario.h"#include "mal_client.h"#define MAL_DEBUGGER /* debugger is active */#define MAXBREAKS 32mal_export int MDBdelay; /* do not immediately react */typedef struct { MalBlkPtr brkBlock[MAXBREAKS]; int brkPc[MAXBREAKS]; int brkVar[MAXBREAKS]; str brkMod[MAXBREAKS]; str brkFcn[MAXBREAKS]; char brkCmd[MAXBREAKS]; str brkRequest[MAXBREAKS]; int brkTop;} mdbStateRecord, *mdbState;mal_export void mdbSetBreakpoint(Client cntxt, MalBlkPtr mb, int pc, char cmd);mal_export void mdbClrBreakRequest(Client cntxt, str name);mal_export void mdbShowBreakpoints(Client cntxt);mal_export void mdbCommand(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int pc);mal_export int mdbSession(void);mal_export void mdbStep(Client cntxt, MalBlkPtr mb, MalStkPtr stk, int pc);mal_export void mdbHelp(stream *f);mal_export void printStackElm(stream *f, MalBlkPtr mb, VarPtr n, ValPtr v, int index, size_t cnt, int first, int lifespan);mal_export void printBATelm(stream *f, int i, size_t cnt, size_t first);mal_export void printStack(stream *f, MalBlkPtr mb, MalStkPtr s, int lifespan);mal_export void printBatInfo(stream *f, VarPtr n, ValPtr v);mal_export void printBatProperties(stream *f, VarPtr n, ValPtr v, str props);mal_export void printTraceCall(Client cntxt, MalBlkPtr mb, MalStkPtr stk, int pc);mal_export str call2str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, int pc);mal_export str runMALDebugger(Symbol s);mal_export void printBBPinfo(stream *out);mal_export void resetOptimizerDebugger(void);mal_export void optimizerDebug(MalBlkPtr mb, str name, int actions, lng usec);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -