- took VMFunction out of the DObject hierarchy.

As it stood, just compiling the internal ZScript code created more than 9000 DObjects, none of which really need to be subjected to garbage collection, aside from allowing lazy deallocation.
This puts an incredible drag on the garbage collector which often needs several minutes to finish processing before actual deletion can start.

The VM functions with roughly 1800 of these objects were by far the easiest to refactor so they are now. They also use a memory arena now which significantly reduces their memory footprint.
This commit is contained in:
Christoph Oelckers 2017-02-08 11:13:41 +01:00
parent 3cddcc8524
commit 3cbd62479b
8 changed files with 59 additions and 73 deletions

View file

@ -361,17 +361,6 @@ static void MarkRoot()
} }
Mark(SectorMarker); Mark(SectorMarker);
Mark(interpolator.Head); Mark(interpolator.Head);
// Mark action functions
if (!FinalGC)
{
FAutoSegIterator probe(ARegHead, ARegTail);
while (*++probe != NULL)
{
AFuncDesc *afunc = (AFuncDesc *)*probe;
Mark(*(afunc->VMPointer));
}
}
// Mark types // Mark types
TypeTable.Mark(); TypeTable.Mark();
for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i) for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i)
@ -776,7 +765,7 @@ CCMD(gc)
{ {
if (argv.argc() == 1) if (argv.argc() == 1)
{ {
Printf ("Usage: gc stop|now|full|pause [size]|stepmul [size]\n"); Printf ("Usage: gc stop|now|full|count|pause [size]|stepmul [size]\n");
return; return;
} }
if (stricmp(argv[1], "stop") == 0) if (stricmp(argv[1], "stop") == 0)
@ -791,6 +780,12 @@ CCMD(gc)
{ {
GC::FullGC(); GC::FullGC();
} }
else if (stricmp(argv[1], "count") == 0)
{
int cnt = 0;
for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++)
Printf("%d active objects counted\n", cnt);
}
else if (stricmp(argv[1], "pause") == 0) else if (stricmp(argv[1], "pause") == 0)
{ {
if (argv.argc() == 2) if (argv.argc() == 2)
@ -814,3 +809,4 @@ CCMD(gc)
} }
} }
} }

View file

@ -2698,7 +2698,6 @@ size_t PFunction::PropagateMark()
for (unsigned i = 0; i < Variants.Size(); ++i) for (unsigned i = 0; i < Variants.Size(); ++i)
{ {
GC::Mark(Variants[i].Proto); GC::Mark(Variants[i].Proto);
GC::Mark(Variants[i].Implementation);
} }
return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark();
} }
@ -2947,6 +2946,7 @@ void PClass::StaticShutdown ()
*p = nullptr; *p = nullptr;
} }
FunctionPtrList.Clear(); FunctionPtrList.Clear();
VMFunction::DeleteAll();
// Make a full garbage collection here so that all destroyed but uncollected higher level objects // Make a full garbage collection here so that all destroyed but uncollected higher level objects
// that still exist are properly taken down before the low level data is deleted. // that still exist are properly taken down before the low level data is deleted.

View file

@ -351,32 +351,6 @@ void PClassActor::DeriveData(PClass *newclass)
} }
//==========================================================================
//
// PClassActor :: PropagateMark
//
//==========================================================================
size_t PClassActor::PropagateMark()
{
// Mark state functions
for (int i = 0; i < NumOwnedStates; ++i)
{
if (OwnedStates[i].ActionFunc != NULL)
{
GC::Mark(OwnedStates[i].ActionFunc);
}
}
// Mark damage function
if (Defaults != NULL)
{
GC::Mark(((AActor *)Defaults)->DamageFunc);
}
// marked += ActorInfo->NumOwnedStates * sizeof(FState);
return Super::PropagateMark();
}
//========================================================================== //==========================================================================
// //
// PClassActor :: SetReplacement // PClassActor :: SetReplacement

View file

@ -256,7 +256,6 @@ public:
void RegisterIDs(); void RegisterIDs();
void SetDamageFactor(FName type, double factor); void SetDamageFactor(FName type, double factor);
void SetPainChance(FName type, int chance); void SetPainChance(FName type, int chance);
size_t PropagateMark();
bool SetReplacement(FName replaceName); bool SetReplacement(FName replaceName);
void SetDropItems(DDropItem *drops); void SetDropItems(DDropItem *drops);

View file

@ -146,6 +146,26 @@ void FMemArena::FreeAllBlocks()
FreeBlockChain(FreeBlocks); FreeBlockChain(FreeBlocks);
} }
//==========================================================================
//
// FMemArena :: DumpInfo
//
// Prints some info about this arena
//
//==========================================================================
void FMemArena::DumpInfo()
{
size_t allocated = 0;
size_t used = 0;
for (auto block = TopBlock; block != NULL; block = block->NextBlock)
{
allocated += BlockSize;
used += BlockSize - ((char*)block->Limit - (char*)block->Avail);
}
Printf("%zu bytes allocated, %zu bytes in use\n", allocated, used);
}
//========================================================================== //==========================================================================
// //
// FMemArena :: FreeBlockChain // FMemArena :: FreeBlockChain

View file

@ -46,6 +46,7 @@ public:
void *Alloc(size_t size); void *Alloc(size_t size);
void FreeAll(); void FreeAll();
void FreeAllBlocks(); void FreeAllBlocks();
void DumpInfo();
protected: protected:
struct Block; struct Block;

View file

@ -6,6 +6,7 @@
#include "vectors.h" #include "vectors.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "doomerrors.h" #include "doomerrors.h"
#include "memarena.h"
#define MAX_RETURNS 8 // Maximum number of results a function called by script code can return #define MAX_RETURNS 8 // Maximum number of results a function called by script code can return
#define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function #define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function
@ -693,10 +694,8 @@ do_double: if (inexact)
} }
}; };
class VMFunction : public DObject class VMFunction
{ {
DECLARE_ABSTRACT_CLASS(VMFunction, DObject);
HAS_OBJECT_POINTERS;
public: public:
bool Native; bool Native;
bool Final = false; // cannot be overridden bool Final = false; // cannot be overridden
@ -709,7 +708,30 @@ public:
class PPrototype *Proto; class PPrototype *Proto;
VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) {} VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL)
{
AllFunctions.Push(this);
}
virtual ~VMFunction() {}
void *operator new(size_t size)
{
return Allocator.Alloc(size);
}
void operator delete(void *block) {}
void operator delete[](void *block) {}
static void DeleteAll()
{
for (auto f : AllFunctions)
{
f->~VMFunction();
}
AllFunctions.Clear();
}
static FMemArena Allocator;
static TArray<VMFunction *> AllFunctions;
protected:
}; };
// VM frame layout: // VM frame layout:
@ -838,11 +860,9 @@ struct FStatementInfo
class VMScriptFunction : public VMFunction class VMScriptFunction : public VMFunction
{ {
DECLARE_CLASS(VMScriptFunction, VMFunction);
public: public:
VMScriptFunction(FName name=NAME_None); VMScriptFunction(FName name=NAME_None);
~VMScriptFunction(); ~VMScriptFunction();
size_t PropagateMark();
void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers); void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers);
VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); }
@ -910,7 +930,6 @@ private:
class VMNativeFunction : public VMFunction class VMNativeFunction : public VMFunction
{ {
DECLARE_CLASS(VMNativeFunction, VMFunction);
public: public:
typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret); typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);

View file

@ -42,14 +42,10 @@ cycle_t VMCycles[10];
int VMCalls[10]; int VMCalls[10];
IMPLEMENT_CLASS(VMException, false, false) IMPLEMENT_CLASS(VMException, false, false)
IMPLEMENT_CLASS(VMFunction, true, true)
IMPLEMENT_POINTERS_START(VMFunction) FMemArena VMFunction::Allocator(32768);
IMPLEMENT_POINTER(Proto) TArray<VMFunction *> VMFunction::AllFunctions;
IMPLEMENT_POINTERS_END
IMPLEMENT_CLASS(VMScriptFunction, false, false)
IMPLEMENT_CLASS(VMNativeFunction, false, false)
VMScriptFunction::VMScriptFunction(FName name) VMScriptFunction::VMScriptFunction(FName name)
{ {
@ -87,7 +83,6 @@ VMScriptFunction::~VMScriptFunction()
KonstS[i].~FString(); KonstS[i].~FString();
} }
} }
M_Free(Code);
} }
} }
@ -100,7 +95,7 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko
assert(numkonsts >= 0 && numkonsts <= 65535); assert(numkonsts >= 0 && numkonsts <= 65535);
assert(numkonsta >= 0 && numkonsta <= 65535); assert(numkonsta >= 0 && numkonsta <= 65535);
assert(numlinenumbers >= 0 && numlinenumbers <= 65535); assert(numlinenumbers >= 0 && numlinenumbers <= 65535);
void *mem = M_Malloc(numops * sizeof(VMOP) + void *mem = Allocator.Alloc(numops * sizeof(VMOP) +
numkonstd * sizeof(int) + numkonstd * sizeof(int) +
numkonstf * sizeof(double) + numkonstf * sizeof(double) +
numkonsts * sizeof(FString) + numkonsts * sizeof(FString) +
@ -166,24 +161,6 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko
NumKonstA = numkonsta; NumKonstA = numkonsta;
} }
size_t VMScriptFunction::PropagateMark()
{
if (KonstA != NULL)
{
FVoidObj *konsta = KonstA;
VM_UBYTE *atag = KonstATags();
for (int count = NumKonstA; count > 0; --count)
{
if (*atag++ == ATAG_OBJECT)
{
GC::Mark(konsta->o);
}
konsta++;
}
}
return NumKonstA * sizeof(void *) + Super::PropagateMark();
}
void VMScriptFunction::InitExtra(void *addr) void VMScriptFunction::InitExtra(void *addr)
{ {
char *caddr = (char*)addr; char *caddr = (char*)addr;