Annotation of researchv10dc/vol2/pi/feel.ms, revision 1.1.1.1

1.1       root        1: .so ../ADM/mac
                      2: .XX pi 335 "The Feel of Pi"
                      3: ...\" Wed May 21 15:35:31 EDT 1986
                      4: .ds p \f2pi\fP
                      5: .ds P \f2Pi\fP
                      6: .ds j \f2jim\fP
                      7: .ds J \f2Jim\fP
                      8: .TL
                      9: The Feel of Pi
                     10: .AU
                     11: T. A. Cargill
                     12: .AI
                     13: .MH
                     14: .AB
                     15: .PP
                     16: \*P is an interactive debugger for C and C++ on Eighth Edition
                     17: .UX
                     18: systems.
                     19: Its user interface uses multiple windows on a DMD 5620 terminal.
                     20: \*P does not feel like a debugger with a sequential command language, nor does it
                     21: feel like a debugger where commands from a bitmap display are translated into a
                     22: sequential command language.
                     23: In contrast, \*p's multiple windows display multiple active views of its multiple
                     24: subject processes, allowing the programmer to browse through a network of
                     25: information.
                     26: The programmer interactively explores a set of executing processes,
                     27: probing for insight with a tool that really helps.
                     28: .PP
                     29: Each window displays a specific view of a subject process in parallel with
                     30: the other windows.
                     31: The contents of pop-up menus are determined by context;
                     32: the current window and the line of text selected within it.
                     33: .PP
                     34: \*P is written in C++ and uses Eighth Edition's
                     35: .CW /proc
                     36: to access arbitrary live subject processes.
                     37: .AE
                     38: .SH
                     39: Introduction
                     40: .PP
                     41: \*P (Process Inspector) is an experiment in debugging with an interactive, bitmap
                     42: graphics user interface.
                     43: The debugging technology is conventional: breakpoints are planted in the subject
                     44: process so that the states the process moves through may be examined.
                     45: But the user interface is unconventional.
                     46: .PP
                     47: In a conventional debugger, the programmer inputs a sequence of commands that are
                     48: interpreted by the debugger.
                     49: The debugger responds with information about the subject process.
                     50: Several problems arise.
                     51: First, the debugger can usually accept only the subset of its commands
                     52: applicable to the debugger's current state.
                     53: For example, breakpoints can only be set in the current source file, or
                     54: expressions can only be evaluated in the current activation record.
                     55: Second, the debugger's output is passive and cannot be used to obtain
                     56: further information about, or other views of, the process.
                     57: For example, if a value is displayed by some command in an
                     58: inappropriate format, the programmer must re-issue the command, specifying another
                     59: format, or take the value and manipulate it elsewhere.
                     60: The effect is that any non-trivial debugging is accomplished by combining
                     61: the debugger with some of our oldest tools \- pencil and paper.
                     62: Third, a debugging command language must necessarily be very large, if it
                     63: is to be useful.
                     64: Generally, keyboard languages are complicated, and often cryptic.
                     65: .PP
                     66: The goal in writing \*p was to create a full-function interactive debugger with a
                     67: good user interface:
                     68: menu-driven, reactive, usable without a scratch pad or reference manual.
                     69: .SH
                     70: Interface Model
                     71: .PP
                     72: \*P's user interface assigns each view of a subject process to a
                     73: separate window.
                     74: Each window has its own menu of operations, appropriate to the view presented.
                     75: Within each window are lines of text providing details of the window's view.
                     76: Each line has its own menu of operations, appropriate to the information presented.
                     77: Interaction is driven by the programmer selecting operations from these menus.
                     78: In response to each operation, the debugger adds or removes windows, or lines,
                     79: or their menus.
                     80: A window or line may also choose to accept a line of input from the keyboard.
                     81: .PP
                     82: On the DMD 5620, a layer is subdivided into a set of scrolling, overlapping
                     83: windows.
                     84: The mechanics of the user interface are derived from \*j, a text editor by
                     85: Pike|reference(blit bstj) |reference(latest volume1).
                     86: There is a current window (with a heavy border), and within it a current
                     87: line (video-inverted).
                     88: Each button on the three-button mouse serves a specific role.
                     89: Button number 1 is for pointing.
                     90: If the cursor is outside the current window, button 1 selects a new current window.
                     91: If the cursor is inside and over a line of text, that line becomes current.
                     92: If inside and in the scroll zone, the window
                     93: scrolls to center the proportional scroll bar over the cursor.
                     94: Buttons 2 and 3 raise the pop-up menus for the current line and window,
                     95: respectively.
                     96: Menus also scroll and may have pop-up sub-menus, making large menus relatively
                     97: easy to use.
                     98: .SH
                     99: An Example
                    100: .PP
                    101: I will demonstrate \*p by examining the copy of \*j that I am
                    102: using to write this paper.
                    103: \*J is two processes, one in the host computer and one in the terminal.
                    104: I will work with its host process.
                    105: I create a new layer on my 5620's screen and simply invoke \*p:
                    106: .P1
                    107: pi
                    108: .P2
                    109: After about 20K bytes of user interface code has downloaded into the 5620, \*p's
                    110: cursor icon requests me to sweep a rectangle for a new window \- the ``Pi''
                    111: window, the master window through which \*p may be bound dynamically to processes
                    112: and core dumps.
                    113: I now have one (almost empty) window in \*p's layer:
                    114: .MB binps
                    115: .LP
                    116: Selecting
                    117: .CW /bin/ps ' `
                    118: from this window's menu runs the
                    119: .I ps
                    120: command and lists the output in the window, one process per line:
                    121: .MB jim
                    122: .LP
                    123: It shows me with a light load \- I am only editing.
                    124: To examine \*j, I point to process 10918 in this list and select
                    125: .CW open\ process ' `
                    126: from its menu.
                    127: I am now requested to sweep a ``Process'' window.
                    128: The Process window has overall control of the process and can create windows
                    129: with more detailed views.
                    130: The process window shows the state of the process, and a callstack if
                    131: the process is stopped.
                    132: The state of process 10918 is:
                    133: .MB RUN1
                    134: .LP
                    135: This is the usual state for \*j's host process
                    136: \- it is blocked reading from the terminal.
                    137: \*P polls the state of the process every second and updates the Process window
                    138: asynchronously with respect to the user and the subject process.
                    139: After some more editing the consumed processor time has increased..
                    140: I raise the Process window's menu:
                    141: .MB srctext
                    142: .LP
                    143: .CW stop ' `
                    144: stops the process asynchronously.
                    145: .CW run ' `
                    146: restarts it.
                    147: .CW src\ text ' `
                    148: creates windows for viewing source text.
                    149: .CW Globals ' `
                    150: creates a window for evaluating expressions in global scope.
                    151: .CW RawMemory ' `
                    152: creates a ``memory editor,'' in which uninterpreted memory cells may be viewed
                    153: and modified.
                    154: .CW Assembler ' `
                    155: creates a window that disassembles memory and provides instruction level
                    156: operations.
                    157: .CW Signals ' `
                    158: creates a window that monitors signals to the process.
                    159: .CW kill? ' `
                    160: kills the process; the question mark calls for a confirming button hit.
                    161: .CW Journal ' `
                    162: creates a window that records significant events in the process \- a trace.
                    163: .PP
                    164: First, I choose to look at some source text.
                    165: If there were a single source file,
                    166: .CW src\ text ' `
                    167: would create a ``Source Text'' window for it.
                    168: \*J has several source files; so \*p asks me to sweep a
                    169: ``Source Files'' window that lists them:
                    170: .MB srcfiles
                    171: .LP
                    172: I point to
                    173: .CW pattern.c
                    174: and choose
                    175: .CW open\ source\ file ' `
                    176: from its menu.
                    177: I sweep a Source Text window.
                    178: It fills with the first few lines of
                    179: .CW pattern.c .
                    180: I raise its menu:
                    181: .MB index
                    182: .LP
                    183: (I have not looked at this code before starting to write this example.
                    184: I believe I will find \*j's regular expression pattern matcher here.
                    185: I know no details of its implementation.
                    186: It is as if I were starting from scratch to find a bug in Pike's code.)
                    187: Moving the cursor over the arrow at the right of
                    188: .CW index\ by\ fcn ' `
                    189: pops up a sub-menu that is a table of contents by function (with line number) of
                    190: .CW pattern.c :
                    191: .MB compile
                    192: It suggests, as I expected, that \*j compiles regular expressions into
                    193: a representation from which they can be interpreted efficiently.
                    194: To see some of this code, I select
                    195: .CW compile().......79 '. `
                    196: This scrolls the window so that the line with the opening brace of
                    197: .CW compile()
                    198: is in the center:
                    199: .MB setbpt
                    200: .LP
                    201: To set a breakpoint, I point to a line of source text, say the opening brace, and
                    202: select
                    203: .CW set\ bpt ' `
                    204: from its menu.
                    205: To indicate the breakpoint,
                    206: .CW >>> ' `
                    207: appears at the beginning of the source line:
                    208: .MB gtgtgt
                    209: .LP
                    210: Note that the breakpoint was set while \*j executed asynchronously.
                    211: .PP
                    212: To force \*j to execute the breakpoint, I type (in \*j's layer) a search command
                    213: whose pattern matches a non-empty sequence of
                    214: .CW a ' `
                    215: followed by a non-empty sequence of
                    216: .CW b ': `
                    217: .CW /a+b+ .
                    218: When \*j hits the breakpoint, \*p asynchronously notices its change of state and
                    219: reports it in the Process window, along with as much of the callstack as fits
                    220: (here, only the deepest activation record):
                    221: .MB bpt
                    222: .LP
                    223: In the Source Text window, the breakpoint source line is
                    224: selected to show the current context.
                    225: To see more of the callstack I reshape the Process window, making it larger:
                    226: .MB callstack
                    227: .LP
                    228: To see the context from which
                    229: .CW compile()
                    230: was called, I select the
                    231: .CW commands(f=0xBCAC)
                    232: line from the callstack and choose
                    233: .CW show\ jim.c:368 ' `
                    234: from its menu.
                    235: I am prompted to sweep another Source Text window,
                    236: .CW jim.c ,
                    237: to see this context.
                    238: To catch the process before it calls
                    239: .CW execute() ,
                    240: I change the selection from the line
                    241: .P1
                    242: compile(p, TRUE);
                    243: .P2
                    244: to the
                    245: .CW if
                    246: statement four lines below
                    247: and set a breakpoint:
                    248: .MB jimc
                    249: .LP
                    250: I then
                    251: .CW run ' `
                    252: from the Source Text window's menu:
                    253: .MB run
                    254: .LP
                    255: .PP
                    256: When \*j reaches this breakpoint, I choose
                    257: .CW step\ into\ fcn ' `
                    258: from the same menu to step the process into
                    259: .CW execute() .
                    260: (The other source stepping commands step
                    261: .I over
                    262: called functions.)
                    263: The source context for
                    264: .CW execute()
                    265: is back in the first source file,
                    266: .CW pattern.c .
                    267: .CW pattern.c 's
                    268: Source Text window moves to the front of the screen and highlights the
                    269: opening brace of
                    270: .CW execute() :
                    271: .MB step1stmt
                    272: .LP
                    273: It appears that the real work will be done by
                    274: .CW fexecute() .
                    275: I could set a breakpoint there, but I use
                    276: .CW step\ 1\ stmt ' `
                    277: from the source window's menu a few times until I get to:
                    278: .P1
                    279: return fexecute(f);
                    280: .P2
                    281: and then use
                    282: .CW step\ into\ fcn ' `
                    283: again.
                    284: The context shown from
                    285: .CW pattern.c
                    286: changes:
                    287: .MB fexec
                    288: .LP
                    289: .PP
                    290: .CW fexecute()
                    291: looks non-trivial.
                    292: Before going further, I would like to understand the data structure driving it.
                    293: I do not know what this data structure is.
                    294: Looking forward through the source text of
                    295: .CW fexecute()
                    296: I understand very little of the code.
                    297: But three lines do make sense:
                    298: .P1
                    299: /* fast check for first char */
                    300: if(startchar && *s!=startchar)
                    301:         goto Continue;
                    302: .P2
                    303: Surely, 
                    304: .CW startchar
                    305: holds a literal character and
                    306: .CW s
                    307: is a pointer into a scanned string.
                    308: To test this I set a breakpoint on the
                    309: .CW if
                    310: and
                    311: .CW run '. `
                    312: At the breakpoint I need the value of
                    313: .CW startchar .
                    314: Choosing
                    315: .CW open\ frame ' `
                    316: from the source line's menu:
                    317: .MB openframe
                    318: .LP
                    319: creates a ``Frame'' window for the activation record of the function
                    320: corresponding to the source line.
                    321: A Frame window evaluates expressions with respect to its activation record.
                    322: The menu contains local variables, each flagged as an argument, an automatic or
                    323: a register:
                    324: .MB startchar
                    325: .LP
                    326: Choosing
                    327: .CW startchar
                    328: evaluates that expression:
                    329: .MB asciion
                    330: .LP
                    331: Is that an
                    332: .CW a '? `
                    333: The value is in decimal because
                    334: .CW startchar
                    335: is declared
                    336: .CW int .
                    337: To override the default format, I select
                    338: .CW format ' `
                    339: from the expression's menu, and
                    340: .CW ascii\ on ' `
                    341: from the sub-menu.
                    342: The expression re-displays itself:
                    343: .MB a97
                    344: .LP
                    345: .PP
                    346: The value of
                    347: .CW startchar
                    348: looks right and probably came from the data structure I am after.
                    349: Scrolling back a few lines in
                    350: .CW pattern.c
                    351: I find an assignment to
                    352: .CW startchar :
                    353: .MB assign
                    354: .LP
                    355: .CW fstart
                    356: may be the pointer I need, but it does not appear in
                    357: .CW fexecute() 's
                    358: menu.
                    359: It must be a global.
                    360: Rather than open the global expression evaluator window and look in its menu,
                    361: I enter the expression
                    362: .P1
                    363: fstart
                    364: .P2
                    365: from the keyboard, with
                    366: .CW fexecute() 's
                    367: Frame window selected as the target.
                    368: The Frame window now contains two expressions:
                    369: .in +.2i
                    370: .MB typeof
                    371: .LP
                    372: .in -.2i
                    373: What type is
                    374: .CW fstart ?
                    375: I can almost tell from its menu.
                    376: Most of the entries in an expression's menu are new expressions that may
                    377: be derived from it.
                    378: The
                    379: .CW $-> 's
                    380: tell me that I have a pointer to a structure.
                    381: (In the menu, and from the keyboard,
                    382: .CW $
                    383: denotes the current expression.)
                    384: Choosing
                    385: .CW typeof\ $ ' `
                    386: confirms it:
                    387: .in +.2i
                    388: .MB left
                    389: .in -.2i
                    390: .LP
                    391: Choosing
                    392: .CW $->left ', `
                    393: followed by
                    394: .CW $->op ', `
                    395: and
                    396: .CW $->right ' `
                    397: yields:
                    398: .MB op
                    399: .LP
                    400: Reformatting
                    401: .CW fstart->op
                    402: in ASCII leaves:
                    403: .in +.2i
                    404: .MB star
                    405: .LP
                    406: .in -.2i
                    407: .LP
                    408: So here is some kind of tree, where an operator code
                    409: less than octal 200 is to match its own value in the scanned text.
                    410: The left sub-tree is empty; the right looks promising.
                    411: Dereferencing with
                    412: .CW *\ $ ' `
                    413: yields:
                    414: .sp 0.5
                    415: .in +.2i
                    416: .MB right
                    417: .in -.2i
                    418: The
                    419: .CW left
                    420: field of
                    421: .CW fstart->right
                    422: is equal to
                    423: .CW fstart
                    424: itself; maybe this is a doubly-linked list.
                    425: Applying
                    426: .CW $->right ' `
                    427: to
                    428: .CW fstart->right ,
                    429: I get:
                    430: .MB rr
                    431: .LP
                    432: I already know this, but applying
                    433: .CW *\ $ ' `
                    434: produces (showing \*p's entire layer for the first time):
                    435: .MB thelast
                    436: .LP
                    437: Note that the value of the
                    438: .CW op
                    439: field for the current expression is displayed in ASCII as
                    440: .CW b '. `
                    441: The ASCII format explicitly requested for that field earlier was saved in the
                    442: symbol table and is now the default.
                    443: The
                    444: .CW left
                    445: pointer is zero here.
                    446: It now looks as though
                    447: .CW left
                    448: points back to the beginning of the sub-pattern controlled by the
                    449: closure operator.
                    450: .PP
                    451: Let me stop here.
                    452: I have started to unravel the data structure and understand the program.
                    453: I hope this paper description conveys something of the feel of \*p.
                    454: .SH
                    455: Programmer Reaction
                    456: .PP
                    457: Most programmers take somewhere from a few hours to a few days to make the
                    458: transition from drowning in a sea of windows to considering \*p an indispensable
                    459: tool.
                    460: At the outset, they do not expect dynamic binding to subject processes and
                    461: cannot see why there are so many windows.
                    462: Invoking a debugger without specifying a dump or program is a foreign notion.
                    463: Expectations of a debugger are very low: ``I only want the value of
                    464: .I x
                    465: when
                    466: .I f()
                    467: is called \- why all the windows?''
                    468: With increased confidence and ambition they use \*p with more sophistication.
                    469: Styles vary considerably.
                    470: Each programmer uses idiosyncratic sizes, shapes and placements of windows,
                    471: especially when debugging multiple processes.
                    472: Some prefer to enter most of their expressions from the keyboard, others
                    473: never touch it.
                    474: .PP
                    475: There are two main problems.
                    476: First, binding \*p to subject processes is too complicated for novices.
                    477: Experts demand many special facilities, which have been allowed to complicate
                    478: what the novice encounters.
                    479: Second, demand for programmable debugging is growing among the expert users.
                    480: Programmability was excluded from \*p in order to concentrate on
                    481: interactive behavior.
                    482: \*P does have ``spy'' expressions, which re-display themselves if their values
                    483: change, and conditional breakpoints, but it is not programmable, say, to
                    484: step 10 instructions after encountering a breakpoint.
                    485: It is now time to think about how programmability and interaction can be combined.
                    486: .SH
                    487: Asynchronous Multiple Processes
                    488: .PP
                    489: An arbitrary set of processes may be examined simultaneously.
                    490: For each subject process there is an independent network of windows.
                    491: Since all the windows are in a flat space on the screen, each successive action
                    492: from the programmer may be in an any window, associated with an any
                    493: process.
                    494: Events in the set of subject processes are reported as they occur.
                    495: For example, the programmer might step source statements alternately
                    496: between a pair of processes while watching the changing values of
                    497: spy expressions in a third process.
                    498: This simplifies debugging situations that were difficult or impossible
                    499: in the past.
                    500: For example, it becomes straightforward to
                    501: (i) compare the behavior of two similar programs;
                    502: (ii) compare the effects of different inputs on a single program;
                    503: (iii) observe the interaction between related processes, say child and parent.
                    504: .SH
                    505: Implementation
                    506: .PP
                    507: \*P depends on the Research
                    508: .UX 's
                    509: .CW /proc |reference(killian processes)|reference(latest volume1),
                    510: and object-oriented programming in C++|reference(cplusplus).
                    511: .PP
                    512: .CW /proc
                    513: permits \*p to bind itself dynamically to any processes, and execute
                    514: asynchronously with them.
                    515: For each process, \*p can tell the kernel how to handle an
                    516: .I exec()
                    517: by the process and signals received from other processes.
                    518: A breakpoint in code executed by a child of a subject process suspends the child
                    519: so that it may be opened and examined.
                    520: Code sharing is managed transparently by
                    521: .CW /proc .
                    522: .PP
                    523: The browsing and asynchrony are driven by object-oriented programming in C++.
                    524: A large host C++ program communicates with a small 5620 C program.
                    525: Everything the programmer can identify on the screen is a C++ object, an
                    526: instance of a class.
                    527: The host program binds an object identifier (which can be thought
                    528: of as a host address) and a menu of operations
                    529: to each window and each line of text as it describes them to the terminal.
                    530: When the programmer selects an operation from a menu associated with an object's
                    531: image, the terminal sends back a remote invocation of one of the object's member
                    532: functions.
                    533: Generally, executing this function creates, changes or removes host objects and
                    534: their images in the terminal.
                    535: Host-terminal communication is asynchronous; the programmer need not wait
                    536: for results to appear on the screen before issuing another operation.
                    537: There is no ambiguity in this ``mouse-ahead''; the identity of the object
                    538: on which a menu operates is frozen when the menu is raised.
                    539: A crude object registration scheme in the host detects (with high probability)
                    540: and ignores operations for objects that have been destroyed.
                    541: .SH
                    542: Conclusion
                    543: .PP
                    544: \*P's easy access to information about arbitrary processes
                    545: has made programmers more sophisticated in their debugging practices.
                    546: Programmers working with large programs written by others are happier.
                    547: Programmers who would not normally read assembly code can sometimes spot
                    548: code generation bugs in the compiler.
                    549: Programmers with families of interacting processes have a handle on them.
                    550: In general, programmers understand their programs better.
                    551: .SH
                    552: References
                    553: .LP
                    554: |reference_placement
                    555: .BP
                    556: photo page
                    557: .BP
                    558: divider with title
                    559: .sp
                    560: .ce
                    561: Supporting Tools and Languages

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.