mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-12 17:29:10 +02:00
+ make use of the mremap syscall of linux to re-allocate large memory blocks faster
git-svn-id: trunk@42713 -
This commit is contained in:
parent
880f7d7c1c
commit
f0213a2c46
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -14601,6 +14601,7 @@ tests/test/tgenfunc8.pp svneol=native#text/pascal
|
|||||||
tests/test/tgenfunc9.pp svneol=native#text/pascal
|
tests/test/tgenfunc9.pp svneol=native#text/pascal
|
||||||
tests/test/tgoto.pp svneol=native#text/plain
|
tests/test/tgoto.pp svneol=native#text/plain
|
||||||
tests/test/theap.pp svneol=native#text/plain
|
tests/test/theap.pp svneol=native#text/plain
|
||||||
|
tests/test/theap2.pp svneol=native#text/pascal
|
||||||
tests/test/theapthread.pp svneol=native#text/plain
|
tests/test/theapthread.pp svneol=native#text/plain
|
||||||
tests/test/thintdir.pp svneol=native#text/plain
|
tests/test/thintdir.pp svneol=native#text/plain
|
||||||
tests/test/thintdir1.pp svneol=native#text/pascal
|
tests/test/thintdir1.pp svneol=native#text/pascal
|
||||||
|
@ -61,6 +61,8 @@ const
|
|||||||
{ DEBUG: Dump info when the heap needs to grow }
|
{ DEBUG: Dump info when the heap needs to grow }
|
||||||
{ define DUMPGROW}
|
{ define DUMPGROW}
|
||||||
|
|
||||||
|
{ define DEBUG_SYSOSREALLOC}
|
||||||
|
|
||||||
{ Memory profiling: at moment in time of max heap size usage,
|
{ Memory profiling: at moment in time of max heap size usage,
|
||||||
keep statistics of number of each size allocated
|
keep statistics of number of each size allocated
|
||||||
(with 16 byte granularity) }
|
(with 16 byte granularity) }
|
||||||
@ -1066,6 +1068,9 @@ begin
|
|||||||
{$endif}
|
{$endif}
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
{$ifdef DEBUG_SYSOSREALLOC}
|
||||||
|
writeln('Allocated block at: $',hexstr(PtrUInt(pcurr),SizeOf(PtrUInt)*2),', size: ',hexstr(PtrUInt(pcurr^.size and sizemask),SizeOf(PtrUInt)*2));
|
||||||
|
{$endif DEBUG_SYSOSREALLOC}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function SysGetMem(size : ptruint):pointer;
|
function SysGetMem(size : ptruint):pointer;
|
||||||
@ -1183,7 +1188,9 @@ begin
|
|||||||
waitfree_var(pmcv);
|
waitfree_var(pmcv);
|
||||||
exit(chunksize);
|
exit(chunksize);
|
||||||
end;
|
end;
|
||||||
|
{$ifdef DEBUG_SYSOSREALLOC}
|
||||||
|
writeln('Releasing block at: $',hexstr(PtrUInt(pmcv),SizeOf(PtrUInt)*2));
|
||||||
|
{$endif DEBUG_SYSOSREALLOC}
|
||||||
{ insert the block in its freelist }
|
{ insert the block in its freelist }
|
||||||
pmcv^.size := pmcv^.size and (not usedflag);
|
pmcv^.size := pmcv^.size and (not usedflag);
|
||||||
append_to_list_var(pmcv);
|
append_to_list_var(pmcv);
|
||||||
@ -1334,13 +1341,21 @@ end;
|
|||||||
function SysTryResizeMem(var p: pointer; size: ptruint): boolean;
|
function SysTryResizeMem(var p: pointer; size: ptruint): boolean;
|
||||||
var
|
var
|
||||||
chunksize,
|
chunksize,
|
||||||
|
newsize,
|
||||||
oldsize,
|
oldsize,
|
||||||
currsize : ptruint;
|
currsize : ptruint;
|
||||||
pcurr : pmemchunk_var;
|
pcurr : pmemchunk_var;
|
||||||
loc_freelists : pfreelists;
|
loc_freelists : pfreelists;
|
||||||
|
poc : poschunk;
|
||||||
|
pmcv : pmemchunk_var;
|
||||||
begin
|
begin
|
||||||
SysTryResizeMem := false;
|
SysTryResizeMem := false;
|
||||||
|
|
||||||
|
{$ifdef DEBUG_SYSOSREALLOC}
|
||||||
|
writeln('Resize block at: $',hexstr(PtrUInt(pcurr),SizeOf(PtrUInt)*2),
|
||||||
|
', from: ',hexstr(SysMemSize(p),SizeOf(PtrUInt)*2),
|
||||||
|
', to: ',hexstr(size,SizeOf(PtrUInt)*2));
|
||||||
|
{$endif DEBUG_SYSOSREALLOC}
|
||||||
{ fix p to point to the heaprecord }
|
{ fix p to point to the heaprecord }
|
||||||
chunksize := pmemchunk_fixed(p-sizeof(tmemchunk_fixed_hdr))^.size;
|
chunksize := pmemchunk_fixed(p-sizeof(tmemchunk_fixed_hdr))^.size;
|
||||||
|
|
||||||
@ -1395,6 +1410,62 @@ begin
|
|||||||
currsize := pcurr^.size and sizemask;
|
currsize := pcurr^.size and sizemask;
|
||||||
if size>currsize then
|
if size>currsize then
|
||||||
begin
|
begin
|
||||||
|
{$ifdef FPC_SYSTEM_HAS_SYSOSREALLOC}
|
||||||
|
{ if the os block is only occupied by the memory block which shall be resized,
|
||||||
|
it can be tried if the OS can reallocate the block. On linux, the OS often does
|
||||||
|
not need to move the data but it can just remap the memory pages }
|
||||||
|
if ((pcurr^.size and firstblockflag) <> 0) and ((pcurr^.size and lastblockflag) <> 0) then
|
||||||
|
begin
|
||||||
|
newsize:=(size+varfirstoffset+sizeof(tmemchunk_var_hdr)+$ffff) and not $ffff;
|
||||||
|
poc:=SysOSRealloc(pointer(pcurr)-varfirstoffset,poschunk(pointer(pcurr)-varfirstoffset)^.size,newsize);
|
||||||
|
if poc<>nil then
|
||||||
|
begin
|
||||||
|
with loc_freelists^.internal_status do
|
||||||
|
begin
|
||||||
|
inc(currheapsize,newsize-poc^.size);
|
||||||
|
if currheapsize > maxheapsize then
|
||||||
|
maxheapsize := currheapsize;
|
||||||
|
end;
|
||||||
|
{$ifdef DEBUG_SYSOSREALLOC}
|
||||||
|
writeln('Block successfully resized by SysOSRealloc to: ',hexstr(qword(poc),sizeof(pointer)*2),' new size: $',hexstr(newsize,sizeof(ptruint)*2));
|
||||||
|
{$endif DEBUG_SYSOSREALLOC}
|
||||||
|
poc^.size:=newsize;
|
||||||
|
{ remove old os block from list, while it is already moved, the data is still the same }
|
||||||
|
if assigned(poc^.prev_any) then
|
||||||
|
poc^.prev_any^.next_any := poc^.next_any
|
||||||
|
else
|
||||||
|
loc_freelists^.oslist_all := poc^.next_any;
|
||||||
|
if assigned(poc^.next_any) then
|
||||||
|
poc^.next_any^.prev_any := poc^.prev_any;
|
||||||
|
|
||||||
|
{ insert the block with the new data into oslist_all }
|
||||||
|
poc^.prev_any := nil;
|
||||||
|
poc^.next_any := loc_freelists^.oslist_all;
|
||||||
|
if assigned(loc_freelists^.oslist_all) then
|
||||||
|
loc_freelists^.oslist_all^.prev_any := poc;
|
||||||
|
loc_freelists^.oslist_all := poc;
|
||||||
|
|
||||||
|
{ setup new block location }
|
||||||
|
p:=pointer(poc)+varfirstoffset+sizeof(tmemchunk_var_hdr);
|
||||||
|
|
||||||
|
{ setup the block data }
|
||||||
|
pmcv:=pmemchunk_var(p-sizeof(tmemchunk_var_hdr));
|
||||||
|
pmcv^.size:=(ptruint(newsize-varfirstoffset) and sizemask) or (firstblockflag or lastblockflag);
|
||||||
|
pmcv^.prevsize:=0;
|
||||||
|
|
||||||
|
currsize:=size;
|
||||||
|
|
||||||
|
{ create the left over freelist block as we rounded up, if at least 16 bytes are free }
|
||||||
|
size:=split_block(pmcv,size);
|
||||||
|
|
||||||
|
{ the block is used }
|
||||||
|
pmcv^.size:=pmcv^.size or usedflag;
|
||||||
|
|
||||||
|
{ TryResizeMem is successful }
|
||||||
|
SysTryResizeMem:=true;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
{$endif FPC_SYSTEM_HAS_SYSOSREALLOC}
|
||||||
{ adjust statistics (try_concat_free_chunk_forward may have merged a free
|
{ adjust statistics (try_concat_free_chunk_forward may have merged a free
|
||||||
block into the current block, which we will subsequently free (so the
|
block into the current block, which we will subsequently free (so the
|
||||||
combined size will be freed -> make sure the combined size is marked as
|
combined size will be freed -> make sure the combined size is marked as
|
||||||
|
@ -603,6 +603,11 @@ begin
|
|||||||
Fpmunmap:=do_syscall(syscall_nr_munmap,TSysParam(Adr),TSysParam(Len));
|
Fpmunmap:=do_syscall(syscall_nr_munmap,TSysParam(Adr),TSysParam(Len));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{$define FPC_SYSTEM_HAS_MREMAP}
|
||||||
|
Function Fpmremap(adr:pointer;old_len,new_len:size_t;flags:cint;new_adr:pointer):pointer; [public, alias :'FPC_SYSC_MREMAP'];
|
||||||
|
begin
|
||||||
|
Fpmremap:=pointer(do_syscall(syscall_nr_mremap,TSysParam(Adr),TSysParam(old_len),TSysParam(new_len),TSysParam(flags),TSysParam(new_adr)));
|
||||||
|
end;
|
||||||
|
|
||||||
Function Fpmprotect(adr:pointer;len:size_t;prot:cint):cint; [public, alias : 'FPC_SYSC_MPROTECT'];
|
Function Fpmprotect(adr:pointer;len:size_t;prot:cint):cint; [public, alias : 'FPC_SYSC_MPROTECT'];
|
||||||
begin
|
begin
|
||||||
|
@ -31,3 +31,19 @@ begin
|
|||||||
fpmunmap(p, size);
|
fpmunmap(p, size);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{$ifdef FPC_SYSTEM_HAS_MREMAP}
|
||||||
|
const
|
||||||
|
MREMAP_MAYMOVE = 1;
|
||||||
|
|
||||||
|
{$define FPC_SYSTEM_HAS_SYSOSREALLOC}
|
||||||
|
function SysOSRealloc(p: pointer;oldsize,newsize: ptruint): pointer;
|
||||||
|
begin
|
||||||
|
result:=Fpmremap(p,oldsize,newsize,MREMAP_MAYMOVE,nil);
|
||||||
|
if result=pointer(-1) then
|
||||||
|
result:=nil
|
||||||
|
else
|
||||||
|
seterrno(0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$endif FPC_SYSTEM_HAS_MREMAP}
|
||||||
|
25
tests/test/theap2.pp
Normal file
25
tests/test/theap2.pp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
var
|
||||||
|
a : array[0..3] of pointer;
|
||||||
|
i,j : longint;
|
||||||
|
HeapStatus : THeapStatus;
|
||||||
|
begin
|
||||||
|
randomize;
|
||||||
|
{$if not(defined(CPU8)) and not(defined(CPU16))}
|
||||||
|
for i:=1 to 12 do
|
||||||
|
begin
|
||||||
|
j:=random(length(a));
|
||||||
|
if not(assigned(a[j])) then
|
||||||
|
getmem(a[j],1024*1024)
|
||||||
|
else
|
||||||
|
reallocmem(a[j],MemSize(a[j])*11 div 10);
|
||||||
|
end;
|
||||||
|
for i:=0 to high(a) do
|
||||||
|
freemem(a[i]);
|
||||||
|
HeapStatus:=GetHeapStatus;
|
||||||
|
with HeapStatus do
|
||||||
|
begin
|
||||||
|
writeln('TotalAllocated: ',TotalAllocated);
|
||||||
|
writeln('TotalFree: ',TotalFree);
|
||||||
|
end;
|
||||||
|
{$endif not(defined(CPU8)) and not(defined(CPU16))}
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user