From 3cbd62479b827a69d59f15cee7ea1c614c9d533e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Feb 2017 11:13:41 +0100 Subject: [PATCH] - 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. --- src/dobjgc.cpp | 20 ++++++++------------ src/dobjtype.cpp | 2 +- src/info.cpp | 26 -------------------------- src/info.h | 1 - src/memarena.cpp | 20 ++++++++++++++++++++ src/memarena.h | 1 + src/scripting/vm/vm.h | 33 ++++++++++++++++++++++++++------- src/scripting/vm/vmframe.cpp | 29 +++-------------------------- 8 files changed, 59 insertions(+), 73 deletions(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index df1760dd70..5b6a34bdc1 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -361,17 +361,6 @@ static void MarkRoot() } Mark(SectorMarker); Mark(interpolator.Head); - // Mark action functions - if (!FinalGC) - { - FAutoSegIterator probe(ARegHead, ARegTail); - - while (*++probe != NULL) - { - AFuncDesc *afunc = (AFuncDesc *)*probe; - Mark(*(afunc->VMPointer)); - } - } // Mark types TypeTable.Mark(); for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i) @@ -776,7 +765,7 @@ CCMD(gc) { 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; } if (stricmp(argv[1], "stop") == 0) @@ -791,6 +780,12 @@ CCMD(gc) { 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) { if (argv.argc() == 2) @@ -814,3 +809,4 @@ CCMD(gc) } } } + diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 54cc646756..6dc4483a00 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2698,7 +2698,6 @@ size_t PFunction::PropagateMark() for (unsigned i = 0; i < Variants.Size(); ++i) { GC::Mark(Variants[i].Proto); - GC::Mark(Variants[i].Implementation); } return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); } @@ -2947,6 +2946,7 @@ void PClass::StaticShutdown () *p = nullptr; } FunctionPtrList.Clear(); + VMFunction::DeleteAll(); // 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. diff --git a/src/info.cpp b/src/info.cpp index c86486b5e0..18eecc2d18 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -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 diff --git a/src/info.h b/src/info.h index 3a20994f54..64be2d92f3 100644 --- a/src/info.h +++ b/src/info.h @@ -256,7 +256,6 @@ public: void RegisterIDs(); void SetDamageFactor(FName type, double factor); void SetPainChance(FName type, int chance); - size_t PropagateMark(); bool SetReplacement(FName replaceName); void SetDropItems(DDropItem *drops); diff --git a/src/memarena.cpp b/src/memarena.cpp index 8ea8b5806b..af9f915471 100644 --- a/src/memarena.cpp +++ b/src/memarena.cpp @@ -146,6 +146,26 @@ void FMemArena::FreeAllBlocks() 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 diff --git a/src/memarena.h b/src/memarena.h index 3601469bf8..14b735eda5 100644 --- a/src/memarena.h +++ b/src/memarena.h @@ -46,6 +46,7 @@ public: void *Alloc(size_t size); void FreeAll(); void FreeAllBlocks(); + void DumpInfo(); protected: struct Block; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 8b8e3c8643..6d758f1bc4 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -6,6 +6,7 @@ #include "vectors.h" #include "cmdlib.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_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: bool Native; bool Final = false; // cannot be overridden @@ -709,7 +708,30 @@ public: 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 AllFunctions; +protected: }; // VM frame layout: @@ -838,11 +860,9 @@ struct FStatementInfo class VMScriptFunction : public VMFunction { - DECLARE_CLASS(VMScriptFunction, VMFunction); public: VMScriptFunction(FName name=NAME_None); ~VMScriptFunction(); - size_t PropagateMark(); void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers); VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } @@ -910,7 +930,6 @@ private: class VMNativeFunction : public VMFunction { - DECLARE_CLASS(VMNativeFunction, VMFunction); public: typedef int (*NativeCallType)(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret); diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index c44fbb2ea6..5fa82ad0c2 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -42,14 +42,10 @@ cycle_t VMCycles[10]; int VMCalls[10]; IMPLEMENT_CLASS(VMException, false, false) -IMPLEMENT_CLASS(VMFunction, true, true) -IMPLEMENT_POINTERS_START(VMFunction) - IMPLEMENT_POINTER(Proto) -IMPLEMENT_POINTERS_END +FMemArena VMFunction::Allocator(32768); +TArray VMFunction::AllFunctions; -IMPLEMENT_CLASS(VMScriptFunction, false, false) -IMPLEMENT_CLASS(VMNativeFunction, false, false) VMScriptFunction::VMScriptFunction(FName name) { @@ -87,7 +83,6 @@ VMScriptFunction::~VMScriptFunction() 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(numkonsta >= 0 && numkonsta <= 65535); assert(numlinenumbers >= 0 && numlinenumbers <= 65535); - void *mem = M_Malloc(numops * sizeof(VMOP) + + void *mem = Allocator.Alloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + numkonsts * sizeof(FString) + @@ -166,24 +161,6 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko 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) { char *caddr = (char*)addr;