Browse Source

* best match for main freelist
* removed root field, saves 4 bytes per block
* fixed crash in dumpblocks

peter 26 years ago
parent
commit
b659954bc3
1 changed files with 159 additions and 108 deletions
  1. 159 108
      rtl/inc/heap.inc

+ 159 - 108
rtl/inc/heap.inc

@@ -23,17 +23,23 @@
 { Allocate small blocks at heapptr instead of walking the freelist }
 {$define SMALLATHEAPPTR}
 
-{ Dump info when the heap needs to grow }
+{ Try to find the best matching block in general freelist }
+{$define BESTMATCH}
+
+{ DEBUG: Dump info when the heap needs to grow }
 { define DUMPGROW}
 
 { Default heap settings }
 const
   blocksize    = 16;  { at least size of freerecord }
   blockshr     = 4;   { shr value for blocksize=2^blockshr}
-  maxblocksize = 1024+blocksize; { 1024+8 needed for heaprecord }
+  maxblocksize = 512+blocksize; { 1024+8 needed for heaprecord }
   maxblock     = maxblocksize div blocksize;
   maxreusebigger = 8; { max reuse bigger tries }
 
+  usedmask = $80000000;
+  sizemask = not usedmask;
+
 {****************************************************************************}
 
 {$ifdef DUMPGROW}
@@ -54,17 +60,15 @@ type
   pfreerecord  = ^tfreerecord;
   tfreerecord  = record
     size  : longint;
-    root  : ppfreerecord;
     next,
     prev  : pfreerecord;
-  end; { 16 bytes }
+  end; { 12 bytes }
 
   pheaprecord = ^theaprecord;
   theaprecord = record
   { this should overlap with tfreerecord }
     size  : longint;
-    root  : ppfreerecord;
-  end; { 8 bytes }
+  end; { 4 bytes }
 
   tfreelists   = array[0..maxblock] of pfreerecord;
   pfreelists   = ^tfreelists;
@@ -73,7 +77,6 @@ var
   internal_memavail  : longint;
   internal_heapsize  : longint;
   freelists          : tfreelists;
-  checkfreememsize   : boolean;
 
 {*****************************************************************************
                              Memory Manager
@@ -172,8 +175,8 @@ begin
      j:=0;
      while assigned(hp) do
       begin
-        hp:=hp^.next;
         inc(j);
+        hp:=hp^.next;
       end;
      writeln('Block ',i*blocksize,': ',j);
    end;
@@ -183,10 +186,10 @@ begin
   s:=0;
   while assigned(hp) do
    begin
-     hp:=hp^.next;
      inc(j);
      if hp^.size>s then
       s:=hp^.size;
+     hp:=hp^.next;
    end;
   writeln('Main: ',j,' maxsize: ',s);
 end;
@@ -204,9 +207,11 @@ var
   proc  : heaperrorproc;
   pcurr : pfreerecord;
   again : boolean;
-  heapfree,
   s,s1,i,
   sizeleft : longint;
+{$ifdef BESTMATCH}
+  pbest : pfreerecord;
+{$endif}
 begin
 { Something to allocate ? }
   if size<=0 then
@@ -222,114 +227,143 @@ begin
   size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
   dec(internal_memavail,size);
 { try to find a block in one of the freelists per size }
-  pcurr:=nil;
   s:=size shr blockshr;
   if s<=maxblock then
    begin
+     pcurr:=freelists[s];
      { correct size match ? }
-     if assigned(freelists[s]) then
+     if assigned(pcurr) then
       begin
         { create the block we should return }
-        p:=pointer(freelists[s])+sizeof(theaprecord);
+        p:=pointer(pcurr)+sizeof(theaprecord);
+        { fix size }
+        pcurr^.size:=pcurr^.size or usedmask;
         { update freelist }
-        freelists[s]:=freelists[s]^.next;
+        freelists[s]:=pcurr^.next;
         if assigned(freelists[s]) then
          freelists[s]^.prev:=nil;
         exit;
       end;
+{$ifdef SMALLATHEAPPTR}
+     if heapend-heapptr>size then
+      begin
+        p:=heapptr;
+        pheaprecord(p)^.size:=size;
+        inc(p,sizeof(theaprecord));
+        inc(heapptr,size);
+        exit;
+      end;
+{$endif}
 {$ifdef REUSEBIGGER}
      { try a bigger block }
      s1:=s+s;
      i:=0;
      while (s1<=maxblock) and (i<maxreusebigger) do
       begin
-        if assigned(freelists[s1]) then
+        pcurr:=freelists[s1];
+        if assigned(pcurr) then
          begin
-           pcurr:=freelists[s1];
+           s:=s1;
            break;
          end;
-        inc(s1,s);
+        inc(s1);
         inc(i);
       end;
 {$endif}
    end
   else
-   s:=0;
+   pcurr:=nil;
+{ not found, then check the main freelist for the first match }
+  if not(assigned(pcurr)) then
+   begin
+     s:=0;
+{$ifdef BESTMATCH}
+     pbest:=nil;
+{$endif}
+     pcurr:=freelists[0];
+     while assigned(pcurr) do
+      begin
+{$ifdef BESTMATCH}
+        if pcurr^.size=size then
+         break
+        else
+         begin
+           if (pcurr^.size>size) then
+            begin
+              if (not assigned(pbest)) or
+                 (pcurr^.size<pbest^.size) then
+               pbest:=pcurr;
+            end;
+         end;
+{$else}
+        if pcurr^.size>=size then
+         break;
+{$endif}
+        pcurr:=pcurr^.next;
+      end;
+{$ifdef BESTMATCH}
+     if not assigned(pcurr) then
+      pcurr:=pbest;
+{$endif}
+   end;
+  { have we found a block, then get it and free up the other left part,
+    if no blocks are found then allocated at the heapptr or grow the heap }
+  if assigned(pcurr) then
+   begin
+     { get pointer of the block we should return }
+     p:=pointer(pcurr);
+     { remove the current block from the freelist }
+     if assigned(pcurr^.next) then
+      pcurr^.next^.prev:=pcurr^.prev;
+     if assigned(pcurr^.prev) then
+      pcurr^.prev^.next:=pcurr^.next
+     else
+      freelists[s]:=pcurr^.next;
+     { create the left over freelist block, if at least 16 bytes are free }
+     sizeleft:=pcurr^.size-size;
+     if sizeleft>sizeof(tfreerecord) then
+      begin
+        pcurr:=pfreerecord(pointer(pcurr)+size);
+        pcurr^.size:=sizeleft;
+        { insert the block in the freelist }
+        pcurr^.prev:=nil;
+        s1:=sizeleft shr blockshr;
+        if s1>maxblock then
+         s1:=0;
+        pcurr^.next:=freelists[s1];
+        if assigned(freelists[s1]) then
+         freelists[s1]^.prev:=pcurr;
+        freelists[s1]:=pcurr;
+      end;
+     { create the block we need to return }
+     pheaprecord(p)^.size:=size;
+     inc(p,sizeof(theaprecord));
+     exit;
+   end;
+  { Lastly, the top of the heap is checked, to see if there is }
+  { still memory available.                                   }
   repeat
-    { not found, then check the main freelist for the first match }
-    heapfree:=heapend-heapptr;
-    if not(assigned(pcurr)) and
-       ((size>maxblocksize) or (heapfree<size)) then
-     begin
-       pcurr:=freelists[0];
-       while assigned(pcurr) do
-        begin
-          if pcurr^.size>=size then
-           break;
-          pcurr:=pcurr^.next;
-        end;
-     end;
-    { have we found a block, then get it and free up the other left part,
-      if no blocks are found then allocated at the heapptr or grow the heap }
-    if assigned(pcurr) then
+    again:=false;
+    if heapend-heapptr>size then
      begin
-       { get pointer of the block we should return }
-       p:=pointer(pcurr);
-       { remove the current block from the freelist }
-       if assigned(pcurr^.next) then
-        pcurr^.next^.prev:=pcurr^.prev;
-       if assigned(pcurr^.prev) then
-        pcurr^.prev^.next:=pcurr^.next
-       else
-        pcurr^.root^:=pcurr^.next;
-       { create the left over freelist block, if at least 16 bytes are free }
-       sizeleft:=pcurr^.size-size;
-       s1:=sizeleft shr blockshr;
-       if s1>0 then
-        begin
-          if s1>maxblock then
-           s1:=0;
-          pcurr:=pfreerecord(pointer(pcurr)+size);
-          pcurr^.size:=sizeleft;
-          pcurr^.root:=@freelists[s1];
-          { insert the block in the freelist }
-          pcurr^.next:=freelists[s1];
-          pcurr^.prev:=nil;
-          if assigned(freelists[s1]) then
-           freelists[s1]^.prev:=pcurr;
-          freelists[s1]:=pcurr;
-        end;
-       { create the block we need to return }
+       p:=heapptr;
        pheaprecord(p)^.size:=size;
-       pheaprecord(p)^.root:=@freelists[s];
        inc(p,sizeof(theaprecord));
+       inc(heapptr,size);
        exit;
      end;
-    { Lastly, the top of the heap is checked, to see if there is }
-    { still memory available.                                   }
-    again:=false;
-    if heapfree<size then
+    { Call the heaperror proc }
+    if assigned(heaperror) then
      begin
-       if assigned(heaperror) then
-        begin
-          proc:=heaperrorproc(heaperror);
-          case proc(size) of
-           0 : HandleError(203);
-           1 : p:=nil;
-           2 : again:=true;
-          end;
-        end
-       else
-        HandleError(203);
+       proc:=heaperrorproc(heaperror);
+       case proc(size) of
+        0 : HandleError(203);
+        1 : p:=nil;
+        2 : again:=true;
+       end;
      end
     else
-     begin
-       p:=heapptr;
-       pheaprecord(p)^.size:=size;
-       pheaprecord(p)^.root:=@freelists[s];
-       inc(p,sizeof(theaprecord));
-       inc(heapptr,size);
-     end;
+     HandleError(203);
   until not again;
 end;
 
@@ -339,23 +373,33 @@ end;
 *****************************************************************************}
 
 procedure SysFreeMem(var p : pointer);
+var
+  s : longint;
+  pcurr : pfreerecord;
 begin
   if p=nil then
    HandleError(204);
 { fix p to point to the heaprecord }
-  dec(p,sizeof(theaprecord));
-  inc(internal_memavail,pheaprecord(p)^.size);
+  pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
+  pcurr^.size:=pcurr^.size and sizemask;
+  inc(internal_memavail,pcurr^.size);
 { insert the block in it's freelist }
-  pfreerecord(p)^.prev:=nil;
-  pfreerecord(p)^.next:=pfreerecord(p)^.root^;
-  if assigned(pfreerecord(p)^.next) then
-   pfreerecord(p)^.next^.prev:=pfreerecord(p);
-  pfreerecord(p)^.root^:=pfreerecord(p);
+  pcurr^.prev:=nil;
+  s:=pcurr^.size shr blockshr;
+  if s>maxblock then
+   s:=0;
+  pcurr^.next:=freelists[s];
+  if assigned(pcurr^.next) then
+   pcurr^.next^.prev:=pcurr;
+  freelists[s]:=pcurr;
   p:=nil;
 end;
 
 
 procedure SysFreeMemSize(var p : pointer;size : longint);
+var
+  s : longint;
+  pcurr : pfreerecord;
 begin
   if size<=0 then
    begin
@@ -367,21 +411,22 @@ begin
   if p=nil then
    HandleError(204);
 { fix p to point to the heaprecord }
-  dec(p,sizeof(theaprecord));
-  inc(internal_memavail,pheaprecord(p)^.size);
+  pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
+  pcurr^.size:=pcurr^.size and sizemask;
+  inc(internal_memavail,pcurr^.size);
 { size check }
-  if checkfreememsize and (size<>-1) then
-   begin
-     size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
-     if size<>pheaprecord(p)^.size then
-      HandleError(204);
-   end;
+  size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
+  if size<>pcurr^.size then
+   HandleError(204);
 { insert the block in it's freelist }
-  pfreerecord(p)^.prev:=nil;
-  pfreerecord(p)^.next:=pfreerecord(p)^.root^;
-  if assigned(pfreerecord(p)^.next) then
-   pfreerecord(p)^.next^.prev:=pfreerecord(p);
-  pfreerecord(p)^.root^:=pfreerecord(p);
+  pcurr^.prev:=nil;
+  s:=pcurr^.size shr blockshr;
+  if s>maxblock then
+   s:=0;
+  pcurr^.next:=freelists[s];
+  if assigned(pcurr^.next) then
+   pcurr^.next^.prev:=pcurr;
+  freelists[s]:=pcurr;
   p:=nil;
 end;
 
@@ -416,6 +461,7 @@ end;
 
 function growheap(size :longint) : integer;
 var
+  sizeleft,
   NewPos,
   wantedsize : longint;
   pcurr      : pfreerecord;
@@ -463,11 +509,11 @@ begin
   else
    begin
      { create freelist entry for old heapptr-heapend }
-     if heapend-heapptr>blocksize then
+     sizeleft:=heapend-heapptr;
+     if sizeleft>sizeof(tfreerecord) then
       begin
         pcurr:=pfreerecord(heapptr);
-        pcurr^.size:=heapend-heapptr;
-        pcurr^.root:=@freelists[0];
+        pcurr^.size:=sizeleft;
         { insert the block in the freelist }
         pcurr^.next:=freelists[0];
         pcurr^.prev:=nil;
@@ -506,7 +552,12 @@ end;
 
 {
   $Log$
-  Revision 1.17  1999-09-20 14:17:37  peter
+  Revision 1.18  1999-09-22 21:59:02  peter
+    * best match for main freelist
+    * removed root field, saves 4 bytes per block
+    * fixed crash in dumpblocks
+
+  Revision 1.17  1999/09/20 14:17:37  peter
     * fixed growheap freelist addition when heapend-heapptr<blocksize
 
   Revision 1.16  1999/09/17 17:14:12  peter