home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / tug__002 / heapchek.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-08-14  |  14.2 KB  |  478 lines

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