-- TexDebug.mesa -- last written by Doug Wyatt, December 19, 1979 3:04 AM DIRECTORY TexDebugDefs: FROM "TexDebugDefs", TexDefs: FROM "TexDefs", TexGlueDefs: FROM "TexGlueDefs", TexIODefs: FROM "TexIODefs", TexMemDefs: FROM "TexMemDefs", TexMem: FROM "TexMem", TexNodeDefs: FROM "TexNodeDefs", TexNode: FROM "TexNode", TexSynDefs: FROM "TexSynDefs"; TexDebug: PROGRAM IMPORTS TexIODefs,mem:TexMem,TexNodeDefs,node:TexNode,TexSynDefs EXPORTS TexDebugDefs SHARES TexMem,TexMemDefs,TexNode = BEGIN OPEN TexDefs,TexGlueDefs,TexNodeDefs,TexMemDefs,TexIODefs; showMem: BOOLEAN=FALSE; showNodes: BOOLEAN=FALSE; -- * * * * * Memory statistics: entering MainControl -- seglist (x,x,xx,xx) = xxx pages, xxxxx words -- freesize xxxxx biglist (xx,xx) -- size NodesAlloc NodesUsed WordsAlloc WordsUsed WordsFree -- n xxxxx xxxxx xxxxx xxxxx xxxxx -- n xxxxx xxxxx xxxxx xxxxx xxxxx -- n xxxxx xxxxx xxxxx xxxxx xxxxx -- nn xxxxx xxxxx xxxxx xxxxx xxxxx -- nn xxxxx xxxxx xxxxx xxxxx xxxxx -- nn xxxxx xxxxx xxxxx xxxxx xxxxx -- nn xxxxx xxxxx xxxxx xxxxx xxxxx -- small xxxxx xxxxx xxxxx xxxxx xxxxx -- big xxxxx xxxxx xxxxx xxxxx xxxxx -- total xxxxx xxxxx xxxxx xxxxx xxxxx -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * foo: STRING←"Debugging"; -- for calling ShowMem from debugger ShowMem: PUBLIC PROCEDURE[string: STRING] = BEGIN IF showMem THEN MemStats[string] END; CheckDEBUG: PROCEDURE[s: STRING] RETURNS[BOOLEAN] = BEGIN OPEN TexDebugDefs; IF NOT DEBUG THEN BEGIN Ws["* * * "L]; Ws[s]; Ws[" unavailable: DEBUG not enabled!"L]; Cr; END; RETURN[DEBUG]; END; MemStats: PROCEDURE[string: STRING] = BEGIN OPEN mem,debug; seg: SegPtr; bptr: BigPtr; size: SmallSize; slot: Slot; pgs,na,wa,nu,wu,wf: CARDINAL←0; sna,snu,swa,swu,swf: CARDINAL←0; bna,bwa,bnu,bwu,bnf,bwf: CARDINAL←0; IF NOT CheckDEBUG["MemStats"L] THEN RETURN; Cr; Ws["* * * * * Memory statistics: "L]; Ws[string]; Cr; Ws["seglist ("L]; IF (seg←seglist)#NIL THEN DO Wnf[seg.pages,0]; pgs←pgs+seg.pages; IF (seg←seg.link)#NIL THEN Wc[',] ELSE EXIT; ENDLOOP; Ws[") = "L]; Wnf[pgs,0]; Ws[" pages,"L]; Wnf[WordsForPages[pgs],0]; Ws[" words"L]; Cr; Ws["freesize"L]; Wnf[freesize,6]; Ws[" biglist ("L]; IF (bptr←biglist)#NIL THEN DO Wnf[bptr.size,0]; bnf←bnf+1; bwf←bwf+bptr.size; IF (bptr←bptr.link)#NIL THEN Wc[',] ELSE EXIT; ENDLOOP; Ws[")"L]; Cr; Ws[" size NodesAlloc NodesUsed WordsAlloc WordsUsed WordsFree"L]; Cr; FOR slot IN Slot DO IF (na←slotcount[slot])=0 THEN LOOP; nu←slotNodesUsed[slot]; size←slotsize[slot]; wa←na*size; wu←slotWordsUsed[slot]; wf←wa-wu; sna←sna+na; snu←snu+nu; swa←swa+wa; swu←swu+wu; swf←swf+wf; Wnf[size,5]; Wnf[na,11]; Wnf[nu,11]; Wnf[wa,11]; Wnf[wu,11]; Wnf[wf,11]; Cr; ENDLOOP; Ws["small"L]; Wnf[sna,11]; Wnf[snu,11]; Wnf[swa,11]; Wnf[swu,11]; Wnf[swf,11]; Cr; bna←bnf+(bnu←bigNodesUsed); bwa←bwf+(bwu←bigWordsUsed); Ws[" big"L]; Wnf[bna,11]; Wnf[bnu,11]; Wnf[bwa,11]; Wnf[bwu,11]; Wnf[bwf,11]; Cr; Ws["total"L]; Wnf[sna+bna,11]; Wnf[snu+bnu,11]; Wnf[swa+bwa,11]; Wnf[swu+bwu,11]; Wnf[swf+bwf,11]; Cr; Ws[" strings"L]; Wnf[strings,6]; Ws[" Chars"L]; Wnf[stringChars,6]; Ws[" Words"L]; Wnf[stringWords,6]; Cr; Ws["* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *"L]; Cr; END; -- *** Math mode Zone: pgs xxx alloc xxxxx used xxxxx -- *** seglist (x,x,x) unused xxxxx ShowZone: PUBLIC PROCEDURE[zone: ZonePtr, string: STRING] = BEGIN IF showMem THEN ZoneStats[zone,string]; END; ZoneStats: PROCEDURE[zone: ZonePtr, string: STRING] = BEGIN OPEN mem,LOOPHOLE[zone,ZPtr],debug; seg: ZSegPtr; pgs,wa,wu: CARDINAL←0; IF NOT CheckDEBUG["ZoneStats"L] THEN RETURN; pgs←totalpages; wa←WordsForPages[pgs]; wu←wa-(freesize+unused); Cr; Ws["*** "L]; Ws[string]; Ws[" Zone: pgs"L]; Wnf[pgs,4]; Ws[" alloc"L]; Wnf[wa,6]; Ws[" used"L]; Wnf[wu,6]; Cr; IF (seg←seglist)#NIL THEN BEGIN Ws["*** seglist ("L]; DO Wnf[seg.pages,0]; pgs←pgs+seg.pages; IF (seg←seg.link)#NIL THEN Wc[',] ELSE EXIT; ENDLOOP; Ws[") unused"L]; Wnf[unused,6]; Cr; END; END; Clobbered: ERROR = CODE; thresh: CARDINAL←1; indent: CARDINAL←0; nitems: CARDINAL←5; Indent: PROCEDURE = BEGIN Cr; THROUGH [1..indent] DO Wc['.] ENDLOOP; END; DumpNodeList: PROCEDURE[p: NodePtr] = BEGIN ENABLE Clobbered => BEGIN Ws["***???***"]; CONTINUE END; c: CARDINAL←0; q: NodePtr; IF indent>thresh THEN RETURN; FOR q←p,q.link UNTIL q=NIL DO Indent; IF (c←c+1)>nitems THEN BEGIN Ws["etc."]; RETURN END; ShowNode[q]; ENDLOOP; END; ShowNode: PUBLIC PROCEDURE[p: NodePtr] = BEGIN OPEN TexIODefs; DumpSubList: PROCEDURE[q: NodePtr] = BEGIN indent←indent+1; DumpNodeList[q]; indent←indent-1 END; WITH pp:p SELECT FROM char,disc => BEGIN IF pp.type=disc THEN Ws["\discretionary"]; WFChar[pp.c] END; box => BEGIN SELECT pp.dir FROM hlist => Ws["\hbox"]; vlist => Ws["\vbox"]; ENDCASE => ERROR Clobbered; Wc['(]; Wn[pp.height]; Ws["+"]; Wn[pp.depth]; Ws[")x"]; Wn[pp.width]; IF pp.glueset#zeroGlueSet THEN BEGIN Ws[", glueset "]; WGlueSet[pp.glueset] END; IF pp.shiftamt#0 THEN BEGIN Ws[", shifted "]; Wn[pp.shiftamt] END; DumpSubList[pp.head]; END; rule => BEGIN Wr: PROCEDURE[x: Dimn] = BEGIN IF x=nilDimn THEN Wc['*] ELSE Wn[x] END; Ws["\rule"]; Wc['(]; Wr[pp.height]; Ws["+"]; Wr[pp.depth]; Ws[")x"]; Wr[pp.width]; END; glue => BEGIN Ws["\glue "]; WGlue[pp.g] END; space => BEGIN Ws["\space "]; Wn[pp.s] END; kern => BEGIN Ws["\kern "]; Wn[pp.s] END; leader => BEGIN Ws["\leaders"]; DumpSubList[pp.p] END; hyph => BEGIN Ws["\hyphenation "]; SELECT pp.auto FROM on => Ws["on"]; off => Ws["off"]; ENDCASE => ERROR Clobbered; END; penalty => BEGIN Ws["\penalty "]; Wn[pp.pts] END; eject => Ws["\eject"]; mark => BEGIN Ws["\mark"]; Wc['{]; TexSynDefs.DumpTokens[NIL,pp.t.link]; END; ins => BEGIN SELECT pp.where FROM top => Ws["\topinsert "]; bot => Ws["\botinsert "]; ENDCASE => ERROR Clobbered; IF pp.dir=vlist THEN Ws["(can wait) "]; WGlue[pp.glue]; DumpSubList[pp.vlist]; END; unset => Ws["\unset"]; -- *** more here ENDCASE => ERROR Clobbered; END; WGlue: PROCEDURE[g: GluePtr] = BEGIN f: Flex; Wn[g.space]; IF (f←g.flex[str])#zeroFlex THEN BEGIN Ws[" plus "]; WFlex[f] END; IF (f←g.flex[shr])#zeroFlex THEN BEGIN Ws[" minus "]; WFlex[f] END; END; WFlex: PROCEDURE[f: Flex] = BEGIN SELECT f.order FROM regular => NULL; lowerfill => Ws["lowerfill "]; fill => Ws["fill "]; ENDCASE => ERROR Clobbered; Wn[f.val]; END; WGlueSet: PROCEDURE[gs: GlueSet] = BEGIN SELECT gs.dir FROM str => Ws["str "]; shr => Ws["shr "]; ENDCASE => ERROR Clobbered; SELECT gs.order FROM regular => NULL; lowerfill => Ws["lowerfill "]; fill => Ws["fill "]; ENDCASE => ERROR Clobbered; Wn[gs.num]; Wc['/]; Wn[gs.den]; END; -- * * * Node statistics: page -- NodeType Nodes Words -- char xx xx -- string xxx xxxx -- box xx xxx -- glue xxx xxxx -- gluespecs xx xxx -- hyph xx xx -- penalty x xx -- total xxxx xxxx -- Len Strings Words -- 1 xxx xxxx -- 2 xxx xxxx -- 3 xx xxx -- * * * * * * * * * * * * * * nodetype: ARRAY NodeType OF STRING ← ["char", "string", "box", "rule", "glue", "space", "kern", "leader", "hyph", "penalty", "disc", "eject", "mark", "ins", "unset", "listhead"]; nodes: ARRAY NodeType OF CARDINAL; sizes: ARRAY NodeType OF CARDINAL; stringvec: ARRAY StringLength OF CARDINAL; gluespecs: CARDINAL; ShowNodeStatistics: PUBLIC PROCEDURE[p: NodePtr, string: STRING] = BEGIN IF showNodes THEN NodeStats[p,string] END; NodeStats: PROCEDURE[p: NodePtr, string: STRING] = BEGIN OPEN node; t: NodeType; tnodes,twords: CARDINAL←0; n,w: CARDINAL; l: StringLength; FOR t IN NodeType DO nodes[t]←sizes[t]←0 ENDLOOP; FOR l IN StringLength DO stringvec[l]←0 ENDLOOP; gluespecs←0; AddNodeList[p]; Cr; Ws["* * * Node statistics: "L]; Ws[string]; Cr; Ws[" NodeType Nodes Words"L]; Cr; FOR t IN NodeType DO tnodes←tnodes+(n←nodes[t]); twords←twords+(w←sizes[t]); IF n=0 THEN LOOP; Wrjs[nodetype[t],9]; Wnf[n,8]; Wnf[w,8]; Cr; IF t=glue AND gluespecs>0 THEN BEGIN n←gluespecs; w←n*SIZE[GlueSpec]; Wrjs["gluespecs"L,9]; Wnf[n,8]; Wnf[w,8]; Cr; END; ENDLOOP; Wrjs["total"L,9]; Wnf[tnodes,8]; Wnf[twords,8]; Cr; StringStats; Ws["* * * * * * * * * * * * * *"L]; Cr; END; StringStats: PROCEDURE = BEGIN l: StringLength; lmin,lmax: StringLength; n,w: CARDINAL; FOR lmin IN StringLength UNTIL stringvec[lmin]>0 DO ENDLOOP; FOR lmax DECREASING IN StringLength UNTIL stringvec[lmax]>0 DO ENDLOOP; Ws[" Len Strings Words"L]; Cr; FOR l IN [lmin..lmax] DO n←stringvec[l]; w←n*StringNodeSize[l]; Wnf[l,3]; Wnf[n,9]; Wnf[w,7]; Sp; THROUGH [0..(n+3)/5) DO Wc['#] ENDLOOP; Cr; ENDLOOP; END; -- write right-justified string Wrjs: PROCEDURE[s: STRING, w: CARDINAL] = BEGIN THROUGH [s.length..w) DO Sp ENDLOOP; Ws[s] END; AddNode: PROCEDURE[p: NodePtr] = BEGIN t: NodeType←p.type; s: CARDINAL←0; WITH pp:p SELECT FROM char => s←SIZE[char Node]; disc => s←SIZE[disc Node]; string => BEGIN l: StringLength←pp.length; stringvec[l]←stringvec[l]+1; s←StringNodeSize[l]; END; box => BEGIN AddNodeList[pp.head]; s←SIZE[box Node] END; rule => s←SIZE[rule Node]; glue => BEGIN g: GluePtr←pp.g; IF g.refs=1 THEN gluespecs←gluespecs+1; s←SIZE[glue Node]; END; space => s←SIZE[space Node]; kern => s←SIZE[kern Node]; leader => s←SIZE[leader Node]; hyph => s←SIZE[hyph Node]; penalty => s←SIZE[penalty Node]; eject => s←SIZE[eject Node]; mark => s←SIZE[mark Node]; ins => BEGIN AddNodeList[pp.vlist]; s←SIZE[ins Node] END; unset => BEGIN AddNode[pp.box]; s←SIZE[unset Node] END; listhead => s←SIZE[listhead Node]; ENDCASE => ERROR; nodes[t]←nodes[t]+1; sizes[t]←sizes[t]+s; END; AddNodeList: PROCEDURE[p: NodePtr] = BEGIN q: NodePtr; FOR q←p,q.link UNTIL q=NIL DO AddNode[q] ENDLOOP; END; END.