home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / packer / arc / arctool / heapchek.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-09-28  |  12.5 KB  |  440 lines

  1. {
  2.  
  3. * DESCRIPTION
  4. Unit that contains procedures developed to help debug a program that uses
  5. the heap extensively, and other routines to return more information about
  6. the free list and to influence the behaviour of the heap manager. Requires
  7. the use of units from the commercial product Turbo Professional 4.0, by
  8. TurboPower Software.
  9.  
  10. * ASSOCIATED FILES
  11. HEAPCHEK.PAS
  12. DEMO.EXE
  13. DEMO.PAS
  14. HEAPCHEK.TPU
  15.  
  16. }
  17. Unit HeapChek;
  18.  
  19. { This unit contains some procedures which I developed to help debug a program
  20.   that uses the heap extensively, and some other routines to return more info
  21.   about the free list and to influence the behaviour of the heap manager.
  22.  
  23.   Note: the procedures and functions which return information about the heap
  24.   are safe -- they use information published by Borland and only read from
  25.   the free list.  FirstFitHeap, BestFitHeap and WorstFitHeap operate by
  26.   directly manipulating the heap, and as such cannot be guaranteed to work
  27.   in Turbo 4.0, and may not work at all if Borland "improves" the heap manager
  28.   in future releases of Turbo Pascal.
  29.  
  30.   For those who are interested, the free list behaves as follows:  When
  31.   a block of memory is allocted, the Heap Manager first checks the free
  32.   list, starting with the first item.  If there are no items on the free
  33.   list, or no blocks big enough, memory is allocated starting at HeapPtr
  34.   and HeapPtr is raised.
  35.  
  36.   If there is a suitable block, the Heap Manager removes the block from
  37.   the free list, creates a pointer to a suitable block on the heap, and
  38.   places the remaining block (if any) at the front of the free list.
  39.  
  40.   When a block is disposed, the free list is checked for any adjacent
  41.   blocks (i.e. a block just before or after in memory which has already
  42.   been disposed), adds these to the block being released, and places the
  43.   new entry at the front of the free list.
  44.  
  45.   If the new free block appears at the end of the heap, HeapPtr is
  46.   adjusted and no new entry appears on the free list.
  47.  
  48.   As a consequence, the free list is arranged from most recently used to
  49.   least recently used.
  50.  
  51.   Because NEW always takes the first block, FirstFitHeap, BestFitHeap
  52.   and WorstFitHeap operate by finding a block which meets the desired
  53.   criteria, and swaps the first entry and the desired entry on the free
  54.   list.
  55.  
  56.   For more info, see Chapter 26 of the Turbo Pascal manual
  57.  
  58.   Placed in the public domain by Lynn W. Taylor  (CIS 74176,52) }
  59.  
  60. Interface
  61.  
  62. uses TpString;  { Write your own HexW and HexPtr routines and you can
  63.                   eliminate this, or get Turbo Professional 4.0 from
  64.                   TurboPower Software }
  65.  
  66.  
  67. const AlwaysShowHeapStatus: boolean = false;
  68.  
  69. { if you set AlwaysShowHeapStatus to true, the heap status will be shown
  70.   automatically on exit.  If false (default), it will be displayed only
  71.   if an appropriate error occurs }
  72.  
  73. Function FreeCount: integer;
  74.  
  75. { returns the number of free blocks on the free list }
  76.  
  77. Function MinAvail: longint;
  78.  
  79. { returns the size of the smallest available block (in bytes) -- useful for
  80.   checking to see if the heap is fragmented.  If FreeCount is zero, MinAvail
  81.   returns MaxAvail. }
  82.  
  83. Function MaxFreeListBlock: longint;
  84.  
  85. { returns the size of largest block on the free list -- which may be smaller
  86.   than MaxAvail.  Function returns 0 if the free list is empty }
  87.  
  88. Procedure ShowFreeList;
  89.  
  90. { Displays the free list using WRITEs to StdOut }
  91.  
  92. Procedure HeapCheck;
  93.  
  94. { Displays a number of useful heap parameters -- useful for debugging.  Also
  95.   called by the exit procedure if the appropriate error ocurs, or if
  96.   AlwaysShowHeapStatus is true }
  97.  
  98. Procedure WorstFitHeap;
  99.  
  100. { Finds largest block on the Free List, and swaps it with the first block
  101.   so the next allocation will use part of the largest free block.  It works
  102.   fine for me but use at your own risk }
  103.  
  104. Procedure BestFitHeap(Size: word);
  105.  
  106. { Finds smallest block which is "Size" or bigger on the Free List, and swaps
  107.   it with the first block so the next allocation will use part of this block.
  108.   It works fine for me but use at your own risk }
  109.  
  110. Procedure FirstFitHeap(Size: word);
  111.  
  112. { Finds lowest block which is "Size" or bigger on the Free List, and swaps
  113.   it with the first block so the next allocation will use part of this block.
  114.   It works fine for me but use at your own risk
  115.  
  116.   Lowest means the one closest to HeapOrg }
  117.  
  118. Procedure LastFitHeap(Size: word);
  119.  
  120. { Finds highest block which is "Size" or bigger on the Free List, and swaps
  121.   it with the first block so the next allocation will use part of this block.
  122.   It works fine for me but use at your own risk
  123.  
  124.   Highest means the one farthest from HeapOrg }
  125.  
  126. Procedure ExactFitHeap(Size: word);
  127.  
  128. { A cross between BestFitHeap and FirstFitHeap.  If a block that exactly
  129.   matches Size exists, it is used, otherwise the first block is used. }
  130.  
  131. Procedure SwapFreeHeap;
  132.  
  133. { Exchanges first and last free list entries.  Since the heap manager always
  134.   puts it's result on the front of the free list, this makes sure that the
  135.   block just disposed is the LAST block to be used.  This usually means that
  136.   the block will hang around long enough that it is most likely to get merged
  137.   into another block }
  138.  
  139. Implementation
  140.  
  141. type FreeRec=record
  142.                OrgOfs, OrgSeg, EndOfs, EndSeg: word;
  143.              end;
  144.      FreeList=array[0..8190] of FreeRec;
  145.      FreeListP=^FreeList;
  146.  
  147. var SaveExit: pointer;
  148.  
  149. Function FreeAddr(P: FreeRec): LongInt;
  150.  
  151. Begin
  152.   FreeAddr:=(16*P.OrgSeg)+P.OrgOfs;
  153. End;
  154.  
  155. Function FreeSize(P: FreeRec): LongInt;
  156.  
  157. Begin
  158.   FreeSize:=((16*P.EndSeg)+P.EndOfs)-((16*P.OrgSeg)+P.OrgOfs)
  159. End;
  160.  
  161. Function FreeCount: integer;
  162.  
  163. Begin
  164.   If Ofs(FreePtr^)=0
  165.     then FreeCount:=0
  166.     else FreeCount:=(8192-Ofs(FreePtr^) div 8) mod 8192;
  167. End;  {FreeCount}
  168.  
  169. Function MinAvail: longint;
  170.  
  171. var Ctr: integer;
  172.     SmallestSize, BlockSize: longint;
  173.     TheFreeList: FreeListP;
  174.  
  175. Begin
  176.   SmallestSize:=MemAvail;
  177.   If FreeCount=0 then Exit;
  178.   TheFreeList:=FreePtr;
  179.   For Ctr:=0 to FreeCount-1 do
  180.     Begin
  181.       BlockSize:=FreeSize(TheFreeList^[Ctr]);
  182.       If BlockSize<SmallestSize then SmallestSize:=BlockSize
  183.     End;
  184.   MinAvail:=SmallestSize
  185. End;  {MinAvail}
  186.  
  187. Function MaxFreeListBlock: longint;
  188.  
  189. var Ctr: integer;
  190.     BiggestSize, BlockSize: longint;
  191.     TheFreeList: FreeListP;
  192.  
  193. Begin
  194.   BiggestSize:=0;
  195.   TheFreeList:=FreePtr;
  196.   For Ctr:=0 to FreeCount-1 do
  197.     Begin
  198.       BlockSize:=FreeSize(TheFreeList^[Ctr]);
  199.       If BlockSize>BiggestSize then BiggestSize:=BlockSize
  200.     End;
  201.   MaxFreeListBlock:=BiggestSize
  202. End;  {MaxFreeListBlock}
  203.  
  204. Procedure ShowFreeList;
  205.  
  206. var Ctr: integer;
  207.     TheFreeList: FreeListP;
  208.  
  209. Begin
  210.   WriteLn('Free list:');
  211.   WriteLn;
  212.   TheFreeList:=FreePtr;
  213.   For Ctr:=0 to FreeCount-1 do
  214.     WriteLn('$', HexW(TheFreeList^[Ctr].OrgSeg), ':',
  215.                  HexW(TheFreeList^[Ctr].OrgOfs), ' - ',
  216.             '$', HexW(TheFreeList^[Ctr].EndSeg), ':',
  217.                  HexW(TheFreeList^[Ctr].EndOfs));
  218. End;  {ShowFreeList}
  219.  
  220. Procedure WorstFitHeap;
  221.  
  222. var Ctr: integer;
  223.     BiggestSize, BiggestBlock, BlockSize: longint;
  224.     TheFreeList: FreeListP;
  225.     Temp: FreeRec;
  226.  
  227. Begin
  228.   If FreeCount<2 then Exit;
  229.   TheFreeList:=FreePtr;
  230.   BiggestSize:=0;
  231.   BiggestBlock:=0;
  232.   For Ctr:=0 to FreeCount-1 do
  233.     Begin
  234.       BlockSize:=FreeSize(TheFreeList^[Ctr]);
  235.       If BlockSize>BiggestSize then
  236.         Begin
  237.           BiggestSize:=BlockSize;
  238.           BiggestBlock:=Ctr
  239.         End
  240.     End;
  241.   If BiggestBlock=0 then Exit;
  242.   Temp:=TheFreeList^[0];
  243.   TheFreeList^[0]:=TheFreeList^[BiggestBlock];
  244.   TheFreeList^[BiggestBlock]:=Temp
  245. End;  {WorstFitHeap}
  246.  
  247. Procedure BestFitHeap(Size: word);
  248.  
  249. var Ctr: integer;
  250.     SmallestSize, SmallestBlock, BlockSize: longint;
  251.     TheFreeList: FreeListP;
  252.     Temp: FreeRec;
  253.  
  254. Begin
  255.   If FreeCount<2 then Exit;
  256.   TheFreeList:=FreePtr;
  257.   SmallestSize:=FreeSize(TheFreeList^[0]);
  258.   SmallestBlock:=0;
  259.   Ctr:=FreeCount-1;
  260.   Repeat
  261.     BlockSize:=FreeSize(TheFreeList^[Ctr]);
  262.     If (BlockSize>=Size) and (BlockSize<=SmallestSize) then
  263.       Begin
  264.         SmallestSize:=BlockSize;
  265.         SmallestBlock:=Ctr
  266.       End;
  267.     Ctr:=Ctr-1
  268.   Until (SmallestSize=Size) or (Ctr=0);
  269.   If SmallestBlock=0 then Exit;
  270.   Temp:=TheFreeList^[0];
  271.   TheFreeList^[0]:=TheFreeList^[SmallestBlock];
  272.   TheFreeList^[SmallestBlock]:=Temp
  273. End;  {BestFitHeap}
  274.  
  275. Procedure ExactFitHeap(Size: word);
  276.  
  277. var Ctr: integer;
  278.     LowestBlock, LowestAddr, BlockSize: longint;
  279.     TheFreeList: FreeListP;
  280.     Temp: FreeRec;
  281.  
  282. Begin
  283.   If FreeCount<2 then Exit;
  284.   TheFreeList:=FreePtr;
  285.   LowestAddr:=FreeAddr(TheFreeList^[0]);
  286.   LowestBlock:=0;
  287.   Ctr:=FreeCount-1;
  288.   Repeat
  289.     BlockSize:=FreeSize(TheFreeList^[Ctr]);
  290.     If (BlockSize=Size)
  291.       then LowestBlock:=Ctr
  292.       else
  293.         If LowestAddr>FreeAddr(TheFreeList^[Ctr]) then
  294.           Begin
  295.             LowestAddr:=FreeAddr(TheFreeList^[Ctr]);
  296.             LowestBlock:=Ctr
  297.           End;
  298.     Ctr:=Ctr-1
  299.   Until (BlockSize=Size) or (Ctr=0);
  300.   If LowestBlock=0 then Exit;
  301.   Temp:=TheFreeList^[0];
  302.   TheFreeList^[0]:=TheFreeList^[LowestBlock];
  303.   TheFreeList^[LowestBlock]:=Temp
  304. End;  {ExactFitHeap}
  305.  
  306. Procedure FirstFitHeap(Size: word);
  307.  
  308. var Ctr: integer;
  309.     FirstAddress, FirstAddressBlock, BlockSize: longint;
  310.     TheFreeList: FreeListP;
  311.     Temp: FreeRec;
  312.  
  313. Begin
  314.   If FreeCount<2 then Exit;
  315.   TheFreeList:=FreePtr;
  316.   FirstAddress:=FreeAddr(TheFreeList^[0]);
  317.   FirstAddressBlock:=0;
  318.   For Ctr:=1 to FreeCount-1 do
  319.     Begin
  320.       BlockSize:=FreeSize(TheFreeList^[Ctr]);
  321.       If (BlockSize>=Size) and
  322.          (FreeAddr(TheFreeList^[Ctr])<FirstAddress) then
  323.         Begin
  324.           FirstAddress:=FreeAddr(TheFreeList^[Ctr]);
  325.           FirstAddressBlock:=Ctr
  326.         End
  327.     End;
  328.   If FirstAddressBlock=0 then Exit;
  329.   Temp:=TheFreeList^[0];
  330.   TheFreeList^[0]:=TheFreeList^[FirstAddressBlock];
  331.   TheFreeList^[FirstAddressBlock]:=Temp
  332. End;  {FirstFitHeap}
  333.  
  334. Procedure LastFitHeap(Size: word);
  335.  
  336. var Ctr: integer;
  337.     LastAddress, LastAddressBlock, BlockSize: longint;
  338.     TheFreeList: FreeListP;
  339.     Temp: FreeRec;
  340.  
  341. Begin
  342.   If FreeCount<2 then Exit;
  343.   TheFreeList:=FreePtr;
  344.   LastAddress:=FreeAddr(TheFreeList^[0]);
  345.   LastAddressBlock:=0;
  346.   For Ctr:=1 to FreeCount-1 do
  347.     Begin
  348.       BlockSize:=FreeSize(TheFreeList^[Ctr]);
  349.       If (BlockSize>=Size) and
  350.          (FreeAddr(TheFreeList^[Ctr])<LastAddress) then
  351.         Begin
  352.           LastAddress:=FreeAddr(TheFreeList^[Ctr]);
  353.           LastAddressBlock:=Ctr
  354.         End
  355.     End;
  356.   If LastAddressBlock=0 then Exit;
  357.   Temp:=TheFreeList^[0];
  358.   TheFreeList^[0]:=TheFreeList^[LastAddressBlock];
  359.   TheFreeList^[LastAddressBlock]:=Temp
  360. End;  {LastFitHeap}
  361.  
  362. Procedure SwapFreeHeap;
  363.  
  364. var Top: integer;
  365.     TheFreeList: FreeListP;
  366.     Temp: FreeRec;
  367.  
  368. Begin
  369.   If FreeCount<2 then Exit;
  370.   TheFreeList:=FreePtr;
  371.   Top:=FreeCount-1;
  372.   Temp:=TheFreeList^[0];
  373.   TheFreeList^[0]:=TheFreeList^[Top];
  374.   TheFreeList^[Top]:=Temp
  375. End;  {SwapFreeHeap}
  376.  
  377. Procedure HeapCheck;
  378.  
  379. var TheFreeList: FreeListP;
  380.     Ctr: integer;
  381.     BlockSize: LongInt;
  382.     SmallestSize, SmallestCount: LongInt;
  383.  
  384. Begin
  385.   WriteLn('HeapOrg:    $',HexPtr(HeapOrg));
  386.   WriteLn('HeapPtr:    $',HexPtr(HeapPtr));
  387.   WriteLn('FreePtr:    $',HexPtr(FreePtr));
  388.   WriteLn('FreeMin:    ',FreeMin);
  389.   WriteLn('MemAvail:   ',MemAvail);
  390.   WriteLn('MaxAvail:   ',MaxAvail);
  391.   WriteLn;
  392.   SmallestSize:=MemAvail;
  393.   SmallestCount:=0;
  394.   TheFreeList:=FreePtr;
  395.   For Ctr:=0 to FreeCount-1 do
  396.     Begin
  397.       BlockSize:=FreeSize(TheFreeList^[Ctr]);
  398.       If BlockSize=SmallestSize then SmallestCount:=SmallestCount+1;
  399.       If BlockSize<SmallestSize then
  400.         Begin
  401.           SmallestSize:=BlockSize;
  402.           SmallestCount:=1
  403.         End
  404.     End;
  405.   WriteLn('Free Block Count: ', FreeCount);
  406.   If FreeCount<>0
  407.     then
  408.       Begin
  409.     WriteLn('Largest Block:    ', MaxFreeListBlock);
  410.         WriteLn('Smallest Block:   ', SmallestSize);
  411.         WriteLn('Blocks this size: ', SmallestCount)
  412.       End
  413.     else
  414.       Begin
  415.     WriteLn('Largest Block:    - ');
  416.         WriteLn('Smallest Block:   - ');
  417.         WriteLn('Blocks this size: - ')
  418.       End;
  419.   WriteLn;
  420. End;  {HeapCheck}
  421.  
  422. {$F+}
  423. Procedure HeapExit;
  424.  
  425. Begin
  426.   ExitProc:=SaveExit;
  427. { If ExitCode<>0 then Write(#7, #7, #7, #7, #7); }
  428.   If (ExitCode=203) or (ExitCode=204) or AlwaysShowHeapStatus
  429.     then HeapCheck;
  430.   { Don't show heap information unless error is Heap Overflow or
  431.     Invalid pointer operation, or if AlwaysShowHeapStatus is true }
  432. End;  {HeapExit}
  433. {$F-}
  434.  
  435. Begin
  436.   SaveExit:=ExitProc;
  437.   ExitProc:=@HeapExit;
  438. End.
  439. 
  440.