From c25dc84da073a75dd7d78afb85e53808680ae8e5 Mon Sep 17 00:00:00 2001 From: LetterN <24603524+LetterN@users.noreply.github.com> Date: Wed, 8 Sep 2021 09:25:38 +0800 Subject: [PATCH] what the cat doing with the yarn dependencies?? --- .github/workflows/ci_suite.yml | 62 ++++-- .github/workflows/generate_documentation.yml | 4 +- code/__DEFINES/qdel.dm | 42 ++-- code/__DEFINES/time.dm | 6 + code/_compile_options.dm | 67 ++++-- .../configuration/entries/general.dm | 9 + code/controllers/subsystem/garbage.dm | 197 +++++++++--------- config/entries/general.txt | 6 + dependencies.sh | 18 +- 9 files changed, 243 insertions(+), 168 deletions(-) diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index f36055dab0..34c1ec1b0e 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -13,11 +13,20 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - - name: Setup cache + - name: Restore SpacemanDMM cache uses: actions/cache@v2 with: - path: $HOME/SpacemanDMM - key: ${{ runner.os }}-spacemandmm + path: ~/SpacemanDMM + key: ${{ runner.os }}-spacemandmm-${{ secrets.CACHE_PURGE_KEY }} + - name: Restore Yarn cache + uses: actions/cache@v2 + with: + path: tgui/.yarn/cache + key: ${{ runner.os }}-yarn-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('tgui/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-build-${{ secrets.CACHE_PURGE_KEY }}- + ${{ runner.os }}-build- + ${{ runner.os }}- - name: Install Tools run: | pip3 install setuptools @@ -28,11 +37,10 @@ jobs: run: | bash tools/ci/check_filedirs.sh tgstation.dme bash tools/ci/check_changelogs.sh + bash tools/ci/check_grep.sh find . -name "*.php" -print0 | xargs -0 -n1 php -l find . -name "*.json" -not -path "*/node_modules/*" -print0 | xargs -0 python3 ./tools/json_verifier.py - tgui/bin/tgui --lint - tgui/bin/tgui --test - bash tools/ci/check_grep.sh + tools/build/build --ci lint tools/bootstrap/python -m dmi.test tools/bootstrap/python -m mapmerge2.dmm_test ~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1 @@ -48,19 +56,16 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - - name: Setup cache + - name: Restore BYOND cache uses: actions/cache@v2 with: - path: $HOME/BYOND - key: ${{ runner.os }}-byond + path: ~/BYOND + key: ${{ runner.os }}-byond-${{ secrets.CACHE_PURGE_KEY }} - name: Compile All Maps run: | bash tools/ci/install_byond.sh source $HOME/BYOND/byond/bin/byondsetup - python3 tools/ci/template_dm_generator.py - tools/build/build - env: - CBT_BUILD_MODE : ALL_MAPS + tools/build/build --ci dm -DCIBUILDING -DCITESTING -DALL_MAPS run_all_tests: if: "!contains(github.event.head_commit.message, '[ci skip]')" @@ -76,11 +81,20 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - uses: actions/checkout@v2 - - name: Setup cache + - name: Restore BYOND cache uses: actions/cache@v2 with: - path: $HOME/BYOND - key: ${{ runner.os }}-byond + path: ~/BYOND + key: ${{ runner.os }}-byond-${{ secrets.CACHE_PURGE_KEY }} + - name: Restore Yarn cache + uses: actions/cache@v2 + with: + path: tgui/.yarn/cache + key: ${{ runner.os }}-yarn-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('tgui/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-build-${{ secrets.CACHE_PURGE_KEY }}- + ${{ runner.os }}-build- + ${{ runner.os }}- - name: Setup database run: | sudo systemctl start mysql @@ -88,7 +102,7 @@ jobs: mysql -u root -proot tg_ci < SQL/tgstation_schema.sql mysql -u root -proot -e 'CREATE DATABASE tg_ci_prefixed;' mysql -u root -proot tg_ci_prefixed < SQL/tgstation_schema_prefixed.sql - - name: Install rust dependencies + - name: Install rust-g run: | sudo dpkg --add-architecture i386 sudo apt update || true @@ -96,15 +110,14 @@ jobs: bash tools/ci/install_rust_g.sh - name: Install auxmos run: | + sudo apt update || true bash tools/ci/install_auxmos.sh - name: Compile and run tests run: | bash tools/ci/install_byond.sh source $HOME/BYOND/byond/bin/byondsetup - tools/build/build -DCIBUILDING + tools/build/build --ci -DCIBUILDING bash tools/ci/run_server.sh - env: - CBT_BUILD_MODE: TEST_RUN test_windows: if: "!contains(github.event.head_commit.message, '[ci skip]')" @@ -112,6 +125,15 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v2 + - name: Restore Yarn cache + uses: actions/cache@v2 + with: + path: tgui/.yarn/cache + key: ${{ runner.os }}-yarn-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('tgui/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-build-${{ secrets.CACHE_PURGE_KEY }}- + ${{ runner.os }}-build- + ${{ runner.os }}- - name: Compile run: pwsh tools/ci/build.ps1 env: diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_documentation.yml index 0fa3f315be..265e179ff0 100644 --- a/.github/workflows/generate_documentation.yml +++ b/.github/workflows/generate_documentation.yml @@ -12,8 +12,8 @@ jobs: - name: Setup cache uses: actions/cache@v2 with: - path: $HOME/SpacemanDMM - key: ${{ runner.os }}-spacemandmm + path: ~/SpacemanDMM + key: ${{ runner.os }}-spacemandmm-${{ secrets.CACHE_PURGE_KEY }} - name: Install SpacemanDMM run: bash tools/ci/install_spaceman_dmm.sh dmdoc - name: Generate documentation diff --git a/code/__DEFINES/qdel.dm b/code/__DEFINES/qdel.dm index 63259774fa..32e0025ab2 100644 --- a/code/__DEFINES/qdel.dm +++ b/code/__DEFINES/qdel.dm @@ -1,30 +1,44 @@ -//defines that give qdel hints. these can be given as a return in destory() or by calling +//! Defines that give qdel hints. +//! +//! These can be given as a return in [/atom/proc/Destroy] or by calling [/proc/qdel]. + +/// `qdel` should queue the object for deletion. +#define QDEL_HINT_QUEUE 0 +/// `qdel` should let the object live after calling [/atom/proc/Destroy]. +#define QDEL_HINT_LETMELIVE 1 +/// Functionally the same as the above. `qdel` should assume the object will gc on its own, and not check it. +#define QDEL_HINT_IWILLGC 2 +/// Qdel should assume this object won't GC, and queue a hard delete using a hard reference. +#define QDEL_HINT_HARDDEL 3 +// Qdel should assume this object won't gc, and hard delete it posthaste. +#define QDEL_HINT_HARDDEL_NOW 4 -#define QDEL_HINT_QUEUE 0 //qdel should queue the object for deletion. -#define QDEL_HINT_LETMELIVE 1 //qdel should let the object live after calling destory. -#define QDEL_HINT_IWILLGC 2 //functionally the same as the above. qdel should assume the object will gc on its own, and not check it. -#define QDEL_HINT_HARDDEL 3 //qdel should assume this object won't gc, and queue a hard delete using a hard reference. -#define QDEL_HINT_HARDDEL_NOW 4 //qdel should assume this object won't gc, and hard del it post haste. - -#ifdef LEGACY_REFERENCE_TRACKING -/** If LEGACY_REFERENCE_TRACKING is enabled, qdel will call this object's find_references() verb. - * - * Functionally identical to QDEL_HINT_QUEUE if GC_FAILURE_HARD_LOOKUP is not enabled in _compiler_options.dm. +#ifdef REFERENCE_TRACKING +/** If REFERENCE_TRACKING is enabled, qdel will call this object's find_references() verb. + * + * Functionally identical to [QDEL_HINT_QUEUE] if [GC_FAILURE_HARD_LOOKUP] is not enabled in _compiler_options.dm. */ -#define QDEL_HINT_FINDREFERENCE 5 -/// Behavior as QDEL_HINT_FINDREFERENCE, but only if the GC fails and a hard delete is forced. +#define QDEL_HINT_FINDREFERENCE 5 +/// Behavior as [QDEL_HINT_FINDREFERENCE], but only if the GC fails and a hard delete is forced. #define QDEL_HINT_IFFAIL_FINDREFERENCE 6 #endif - #define GC_QUEUE_CHECK 1 #define GC_QUEUE_HARDDELETE 2 #define GC_QUEUE_COUNT 2 //increase this when adding more steps. +#define QDEL_ITEM_ADMINS_WARNED (1<<0) //! Set when admins are told about lag causing qdels in this type. +#define QDEL_ITEM_SUSPENDED_FOR_LAG (1<<1) //! Set when a type can no longer be hard deleted on failure because of lag it causes while this happens. + +// Defines for the [gc_destroyed][/datum/var/gc_destroyed] var. #define GC_QUEUED_FOR_QUEUING -1 #define GC_CURRENTLY_BEING_QDELETED -2 +// Defines for the time left for an item to get its reference cleaned +#define GC_FILTER_QUEUE 5 MINUTES +#define GC_DEL_QUEUE 10 SECONDS + #define QDELING(X) (X.gc_destroyed) #define QDELETED(X) (!X || QDELING(X)) #define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) diff --git a/code/__DEFINES/time.dm b/code/__DEFINES/time.dm index 01990ddc17..252fe0910e 100644 --- a/code/__DEFINES/time.dm +++ b/code/__DEFINES/time.dm @@ -49,10 +49,16 @@ When using time2text(), please use "DDD" to find the weekday. Refrain from using #define TICKS *world.tick_lag +#define MILLISECONDS * 0.01 + #define DS2TICKS(DS) ((DS)/world.tick_lag) #define TICKS2DS(T) ((T) TICKS) +#define MS2DS(T) ((T) MILLISECONDS) + +#define DS2MS(T) ((T) * 100) + #define GAMETIMESTAMP(format, wtime) time2text(wtime, format) #define WORLDTIME2TEXT(format) GAMETIMESTAMP(format, world.time) #define WORLDTIMEOFDAY2TEXT(format) GAMETIMESTAMP(format, world.timeofday) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 64b4129024..b19b2eba6d 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -1,7 +1,7 @@ -//#define TESTING //By using the testing("message") proc you can create debug-feedback for people with this +//#define TESTING //By using the testing("message") proc you can create debug-feedback for people with this //uncommented, but not visible in the release version) -//#define DATUMVAR_DEBUGGING_MODE //Enables the ability to cache datum vars and retrieve later for debugging which vars changed. +//#define DATUMVAR_DEBUGGING_MODE //Enables the ability to cache datum vars and retrieve later for debugging which vars changed. // Comment this out if you are debugging problems that might be obscured by custom error handling in world/Error #ifdef DEBUG @@ -11,34 +11,41 @@ #ifdef TESTING #define DATUMVAR_DEBUGGING_MODE -/* -* Enables extools-powered reference tracking system, letting you see what is referencing objects that refuse to hard delete. -* -* * Requires TESTING to be defined to work. -*/ +///Used to find the sources of harddels, quite laggy, don't be surpised if it freezes your client for a good while //#define REFERENCE_TRACKING +#ifdef REFERENCE_TRACKING -///Method of tracking references without using extools. Slower, kept to avoid over-reliance on extools. -//#define LEGACY_REFERENCE_TRACKING -#ifdef LEGACY_REFERENCE_TRACKING +///Should we be logging our findings or not +#define REFERENCE_TRACKING_LOG -///Use the legacy reference on things hard deleting by default. +///Used for doing dry runs of the reference finder, to test for feature completeness +//#define REFERENCE_TRACKING_DEBUG + +///Run a lookup on things hard deleting by default. //#define GC_FAILURE_HARD_LOOKUP #ifdef GC_FAILURE_HARD_LOOKUP #define FIND_REF_NO_CHECK_TICK #endif //ifdef GC_FAILURE_HARD_LOOKUP -#endif //ifdef LEGACY_REFERENCE_TRACKING +#endif //ifdef REFERENCE_TRACKING -//#define VISUALIZE_ACTIVE_TURFS //Highlights atmos active turfs in green +/* +* Enables debug messages for every single reaction step. This is 1 message per 0.5s for a SINGLE reaction. Useful for tracking down bugs/asking me for help in the main reaction handiler (equilibrium.dm). +* +* * Requires TESTING to be defined to work. +*/ +//#define REAGENTS_TESTING +// #define VISUALIZE_ACTIVE_TURFS //Highlights atmos active turfs in green +// #define TRACK_MAX_SHARE //Allows max share tracking, for use in the atmos debugging ui #endif //ifdef TESTING -//#define UNIT_TESTS //Enables unit tests via TEST_RUN_PARAMETER -#ifndef PRELOAD_RSC //set to: -#define PRELOAD_RSC 2 // 0 to allow using external resources or on-demand behaviour; -#endif // 1 to use the default behaviour; - // 2 for preloading absolutely everything; +//#define UNIT_TESTS //If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between + +#ifndef PRELOAD_RSC //set to: +#define PRELOAD_RSC 2 // 0 to allow using external resources or on-demand behaviour; +#endif // 1 to use the default behaviour; + // 2 for preloading absolutely everything; #ifdef LOWMEMORYMODE #define FORCE_MAP "_maps/runtimestation.json" @@ -47,7 +54,7 @@ //Update this whenever you need to take advantage of more recent byond features #define MIN_COMPILER_VERSION 513 #define MIN_COMPILER_BUILD 1514 -#if DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD +#if (DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD) && !defined(SPACEMAN_DMM) //Don't forget to update this part #error Your version of BYOND is too out-of-date to compile this project. Go to https://secure.byond.com/download and update. #error You need version 513.1514 or higher @@ -58,10 +65,6 @@ #warn compiling in TESTING mode. testing() debug messages will be visible. #endif -#ifdef GC_FAILURE_HARD_LOOKUP -#define FIND_REF_NO_CHECK_TICK -#endif - #ifdef CIBUILDING #define UNIT_TESTS #endif @@ -70,6 +73,24 @@ #define TESTING #endif +#if defined(UNIT_TESTS) +//Hard del testing defines +#define REFERENCE_TRACKING +#define REFERENCE_TRACKING_DEBUG +#define FIND_REF_NO_CHECK_TICK +#endif + +#ifdef TGS +// TGS performs its own build of dm.exe, but includes a prepended TGS define. +#define CBT +#endif + // A reasonable number of maximum overlays an object needs // If you think you need more, rethink it #define MAX_ATOM_OVERLAYS 100 + +#if !defined(CBT) && !defined(SPACEMAN_DMM) +#warn Building with Dream Maker is no longer supported and will result in errors. +#warn In order to build, run BUILD.bat in the root directory. +#warn Consider switching to VSCode editor instead, where you can press Ctrl+Shift+B to build. +#endif diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 8ecd7c0c60..d828457fa7 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -333,3 +333,12 @@ config_entry_value = 0.333 min_val = 0 integer = FALSE + +/datum/config_entry/number/hard_deletes_overrun_threshold + integer = FALSE + min_val = 0 + default = 0.5 + +/datum/config_entry/number/hard_deletes_overrun_limit + default = 0 + min_val = 0 diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 2d2fac1d13..7f7d301a1d 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -29,37 +29,35 @@ SUBSYSTEM_DEF(garbage) runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY init_order = INIT_ORDER_GARBAGE - var/list/collection_timeout = list(2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level + var/list/collection_timeout = list(GC_FILTER_QUEUE, GC_DEL_QUEUE) // deciseconds to wait before moving something up in the queue to the next level //Stat tracking - var/delslasttick = 0 // number of del()'s we've done this tick - var/gcedlasttick = 0 // number of things that gc'ed last tick + var/delslasttick = 0 // number of del()'s we've done this tick + var/gcedlasttick = 0 // number of things that gc'ed last tick var/totaldels = 0 var/totalgcs = 0 - var/highest_del_time = 0 - var/highest_del_tickusage = 0 + var/highest_del_ms = 0 + var/highest_del_type_string = "" var/list/pass_counts var/list/fail_counts - var/list/items = list() // Holds our qdel_item statistics datums + var/list/items = list() // Holds our qdel_item statistics datums //Queue var/list/queues - #ifdef LEGACY_REFERENCE_TRACKING + #ifdef REFERENCE_TRACKING var/list/reference_find_on_fail = list() + #ifdef REFERENCE_TRACKING_DEBUG + //Should we save found refs. Used for unit testing + var/should_save_refs = FALSE + #endif #endif /datum/controller/subsystem/garbage/PreInit() - queues = new(GC_QUEUE_COUNT) - pass_counts = new(GC_QUEUE_COUNT) - fail_counts = new(GC_QUEUE_COUNT) - for(var/i in 1 to GC_QUEUE_COUNT) - queues[i] = list() - pass_counts[i] = 0 - fail_counts[i] = 0 + InitQueues() /datum/controller/subsystem/garbage/stat_entry(msg) var/list/counts = list() @@ -90,13 +88,18 @@ SUBSYSTEM_DEF(garbage) for(var/path in items) var/datum/qdel_item/I = items[path] dellog += "Path: [path]" + if (I.qdel_flags & QDEL_ITEM_SUSPENDED_FOR_LAG) + dellog += "\tSUSPENDED FOR LAG" if (I.failures) dellog += "\tFailures: [I.failures]" dellog += "\tqdel() Count: [I.qdels]" dellog += "\tDestroy() Cost: [I.destroy_time]ms" if (I.hard_deletes) - dellog += "\tTotal Hard Deletes [I.hard_deletes]" + dellog += "\tTotal Hard Deletes: [I.hard_deletes]" dellog += "\tTime Spent Hard Deleting: [I.hard_delete_time]ms" + dellog += "\tHighest Time Spent Hard Deleting: [I.hard_delete_max]ms" + if (I.hard_deletes_over_threshold) + dellog += "\tHard Deletes Over Threshold: [I.hard_deletes_over_threshold]" if (I.slept_destroy) dellog += "\tSleeps: [I.slept_destroy]" if (I.no_respect_force) @@ -122,6 +125,15 @@ SUBSYSTEM_DEF(garbage) +/datum/controller/subsystem/garbage/proc/InitQueues() + if (isnull(queues)) // Only init the queues if they don't already exist, prevents overriding of recovered lists + queues = new(GC_QUEUE_COUNT) + pass_counts = new(GC_QUEUE_COUNT) + fail_counts = new(GC_QUEUE_COUNT) + for(var/i in 1 to GC_QUEUE_COUNT) + queues[i] = list() + pass_counts[i] = 0 + fail_counts[i] = 0 /datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK) if (level == GC_QUEUE_CHECK) @@ -153,7 +165,6 @@ SUBSYSTEM_DEF(garbage) if(GCd_at_time > cut_off_time) break // Everything else is newer, skip them count++ - var/refID = L[2] var/datum/D D = locate(refID) @@ -162,8 +173,8 @@ SUBSYSTEM_DEF(garbage) ++gcedlasttick ++totalgcs pass_counts[level]++ - #ifdef LEGACY_REFERENCE_TRACKING - reference_find_on_fail -= refID //It's deleted we don't care anymore. + #ifdef REFERENCE_TRACKING + reference_find_on_fail -= refID //It's deleted we don't care anymore. #endif if (MC_TICK_CHECK) return @@ -171,35 +182,43 @@ SUBSYSTEM_DEF(garbage) // Something's still referring to the qdel'd object. fail_counts[level]++ + + #ifdef REFERENCE_TRACKING + var/ref_searching = FALSE + #endif + switch (level) if (GC_QUEUE_CHECK) #ifdef REFERENCE_TRACKING - D.find_references() - #elif defined(LEGACY_REFERENCE_TRACKING) if(reference_find_on_fail[refID]) - D.find_references_legacy() + INVOKE_ASYNC(D, /datum/proc/find_references) + ref_searching = TRUE #ifdef GC_FAILURE_HARD_LOOKUP else - D.find_references_legacy() + INVOKE_ASYNC(D, /datum/proc/find_references) + ref_searching = TRUE #endif reference_find_on_fail -= refID #endif var/type = D.type var/datum/qdel_item/I = items[type] - #ifdef TESTING + log_world("## TESTING: GC: -- \ref[D] | [type] was unable to be GC'd --") + #ifdef TESTING for(var/c in GLOB.admins) //Using testing() here would fill the logs with ADMIN_VV garbage var/client/admin = c if(!check_rights_for(admin, R_ADMIN)) continue to_chat(admin, "## TESTING: GC: -- [ADMIN_VV(D)] | [type] was unable to be GC'd --") - testing("GC: -- \ref[src] | [type] was unable to be GC'd --") - #endif - #ifdef REFERENCE_TRACKING - GLOB.deletion_failures += D //It should no longer be bothered by the GC, manual deletion only. - continue #endif I.failures++ + + if (I.qdel_flags & QDEL_ITEM_SUSPENDED_FOR_LAG) + #ifdef REFERENCE_TRACKING + if(ref_searching) + return //ref searching intentionally cancels all further fires while running so things that hold references don't end up getting deleted, so we want to return here instead of continue + #endif + continue if (GC_QUEUE_HARDDELETE) HardDelete(D) if (MC_TICK_CHECK) @@ -208,27 +227,17 @@ SUBSYSTEM_DEF(garbage) Queue(D, level+1) + #ifdef REFERENCE_TRACKING + if(ref_searching) + return + #endif + if (MC_TICK_CHECK) return if (count) queue.Cut(1,count+1) count = 0 -#ifdef LEGACY_REFERENCE_TRACKING -/datum/controller/subsystem/garbage/proc/add_type_to_findref(type) - if(!ispath(type)) - return "NOT A VAILD PATH" - reference_find_on_fail_types |= typecacheof(type) - -/datum/controller/subsystem/garbage/proc/remove_type_from_findref(type) - if(!ispath(type)) - return "NOT A VALID PATH" - reference_find_on_fail_types -= typesof(type) - -/datum/controller/subsystem/garbage/proc/clear_findref_types() - reference_find_on_fail_types = list() -#endif - /datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK) if (isnull(D)) return @@ -238,63 +247,66 @@ SUBSYSTEM_DEF(garbage) var/gctime = world.time var/refid = "\ref[D]" -#ifdef LEGACY_REFERENCE_TRACKING - if(reference_find_on_fail_types[D.type]) - SSgarbage.reference_find_on_fail[REF(D)] = TRUE -#endif - D.gc_destroyed = gctime var/list/queue = queues[level] + queue[++queue.len] = list(gctime, refid) // not += for byond reasons //this is mainly to separate things profile wise. /datum/controller/subsystem/garbage/proc/HardDelete(datum/D) - var/time = world.timeofday - var/tick = TICK_USAGE - var/ticktime = world.time ++delslasttick ++totaldels var/type = D.type var/refID = "\ref[D]" + var/tick_usage = TICK_USAGE del(D) - - tick = (TICK_USAGE-tick+((world.time-ticktime)/world.tick_lag*100)) + tick_usage = TICK_USAGE_TO_MS(tick_usage) var/datum/qdel_item/I = items[type] - I.hard_deletes++ - I.hard_delete_time += TICK_DELTA_TO_MS(tick) + I.hard_delete_time += tick_usage + if (tick_usage > I.hard_delete_max) + I.hard_delete_max = tick_usage + if (tick_usage > highest_del_ms) + highest_del_ms = tick_usage + highest_del_type_string = "[type]" + var/time = MS2DS(tick_usage) - if (tick > highest_del_tickusage) - highest_del_tickusage = tick - time = world.timeofday - time - if (!time && TICK_DELTA_TO_MS(tick) > 1) - time = TICK_DELTA_TO_MS(tick)/100 - if (time > highest_del_time) - highest_del_time = time - if (time > 10) - log_game("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete)") - message_admins("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete).") + if (time > 0.1 SECONDS) postpone(time) + var/threshold = CONFIG_GET(number/hard_deletes_overrun_threshold) + if (threshold && (time > threshold SECONDS)) + if (!(I.qdel_flags & QDEL_ITEM_ADMINS_WARNED)) + log_game("Error: [type]([refID]) took longer than [threshold] seconds to delete (took [round(time/10, 0.1)] seconds to delete)") + message_admins("Error: [type]([refID]) took longer than [threshold] seconds to delete (took [round(time/10, 0.1)] seconds to delete).") + I.qdel_flags |= QDEL_ITEM_ADMINS_WARNED + I.hard_deletes_over_threshold++ + var/overrun_limit = CONFIG_GET(number/hard_deletes_overrun_limit) + if (overrun_limit && I.hard_deletes_over_threshold >= overrun_limit) + I.qdel_flags |= QDEL_ITEM_SUSPENDED_FOR_LAG /datum/controller/subsystem/garbage/Recover() + InitQueues() //We first need to create the queues before recovering data if (istype(SSgarbage.queues)) for (var/i in 1 to SSgarbage.queues.len) queues[i] |= SSgarbage.queues[i] - +/// Qdel Item: Holds statistics on each type that passes thru qdel /datum/qdel_item - var/name = "" - var/qdels = 0 //Total number of times it's passed thru qdel. - var/destroy_time = 0 //Total amount of milliseconds spent processing this type's Destroy() - var/failures = 0 //Times it was queued for soft deletion but failed to soft delete. - var/hard_deletes = 0 //Different from failures because it also includes QDEL_HINT_HARDDEL deletions - var/hard_delete_time = 0//Total amount of milliseconds spent hard deleting this type. - var/no_respect_force = 0//Number of times it's not respected force=TRUE - var/no_hint = 0 //Number of times it's not even bother to give a qdel hint - var/slept_destroy = 0 //Number of times it's slept in its destroy + var/name = "" //!Holds the type as a string for this type + var/qdels = 0 //!Total number of times it's passed thru qdel. + var/destroy_time = 0 //!Total amount of milliseconds spent processing this type's Destroy() + var/failures = 0 //!Times it was queued for soft deletion but failed to soft delete. + var/hard_deletes = 0 //!Different from failures because it also includes QDEL_HINT_HARDDEL deletions + var/hard_delete_time = 0 //!Total amount of milliseconds spent hard deleting this type. + var/hard_delete_max = 0 //!Highest time spent hard_deleting this in ms. + var/hard_deletes_over_threshold = 0 //!Number of times hard deletes took longer than the configured threshold + var/no_respect_force = 0 //!Number of times it's not respected force=TRUE + var/no_hint = 0 //!Number of times it's not even bother to give a qdel hint + var/slept_destroy = 0 //!Number of times it's slept in its destroy + var/qdel_flags = 0 //!Flags related to this type's trip thru qdel. /datum/qdel_item/New(mytype) name = "[mytype]" @@ -307,12 +319,12 @@ SUBSYSTEM_DEF(garbage) if(!istype(D)) del(D) return + var/datum/qdel_item/I = SSgarbage.items[D.type] if (!I) I = SSgarbage.items[D.type] = new /datum/qdel_item(D.type) I.qdels++ - if(isnull(D.gc_destroyed)) if (SEND_SIGNAL(D, COMSIG_PARENT_PREQDELETED, force)) // Give the components a chance to prevent their parent from being deleted return @@ -328,12 +340,12 @@ SUBSYSTEM_DEF(garbage) if(!D) return switch(hint) - if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion. + if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion. SSgarbage.Queue(D) if (QDEL_HINT_IWILLGC) D.gc_destroyed = world.time return - if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory. + if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory. if(!force) D.gc_destroyed = null //clear the gc variable (important!) return @@ -350,17 +362,17 @@ SUBSYSTEM_DEF(garbage) I.no_respect_force++ SSgarbage.Queue(D) - if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete + if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete SSgarbage.Queue(D, GC_QUEUE_HARDDELETE) - if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. + if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. SSgarbage.HardDelete(D) - #ifdef LEGACY_REFERENCE_TRACKING - if (QDEL_HINT_FINDREFERENCE) //qdel will, if LEGACY_REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion. + #ifdef REFERENCE_TRACKING + if (QDEL_HINT_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion. SSgarbage.Queue(D) - D.find_references_legacy() - if (QDEL_HINT_IFFAIL_FINDREFERENCE) + D.find_references() + if (QDEL_HINT_IFFAIL_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled and the object fails to collect, display all references to this object. SSgarbage.Queue(D) - SSgarbage.reference_find_on_fail[REF(D)] = TRUE + SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE #endif else #ifdef TESTING @@ -371,18 +383,3 @@ SUBSYSTEM_DEF(garbage) SSgarbage.Queue(D) else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic") - -#ifdef TESTING -/proc/writeDatumCount() - var/list/datums = list() - for(var/datum/D in world) - datums[D.type] += 1 - for(var/datum/D) - datums[D.type] += 1 - datums = sortTim(datums, /proc/cmp_numeric_dsc, associative = TRUE) - if(fexists("data/DATUMCOUNT.txt")) - fdel("data/DATUMCOUNT.txt") - var/outfile = file("data/DATUMCOUNT.txt") - for(var/path in datums) - outfile << "[datums[path]]\t\t\t\t\t[path]" -#endif diff --git a/config/entries/general.txt b/config/entries/general.txt index 3584af63c7..b3130565e4 100644 --- a/config/entries/general.txt +++ b/config/entries/general.txt @@ -491,3 +491,9 @@ ALLOW_CUSTOM_SKINTONES ## Allows pAI custom holoforms PAI_CUSTOM_HOLOFORMS + +## How long in seconds after which a hard delete is treated as causing lag. This can be a float and supports a precision as low as nanoseconds. +#HARD_DELETES_OVERRUN_THRESHOLD 0.5 + +## Once a typepath causes overrun from hard deletes this many times, stop hard deleting it on garbage collection failures. (set to 0 to disable) +#HARD_DELETES_OVERRUN_LIMIT 0 diff --git a/dependencies.sh b/dependencies.sh index cdbdcd98df..aca82a3a05 100644 --- a/dependencies.sh +++ b/dependencies.sh @@ -8,20 +8,20 @@ export BYOND_MAJOR=514 export BYOND_MINOR=1556 #rust_g git tag -export RUST_G_VERSION=0.4.8 - -#auxmos git tag -export AUXMOS_VERSION=v0.2.3 +export RUST_G_VERSION=0.4.10 #node version export NODE_VERSION=12 -export NODE_VERSION_PRECISE=12.20.0 +export NODE_VERSION_PRECISE=12.22.4 # SpacemanDMM git tag -export SPACEMAN_DMM_VERSION=suite-1.6 - -# Extools git tag -export EXTOOLS_VERSION=v0.0.7 +export SPACEMAN_DMM_VERSION=suite-1.7 # Python version for mapmerge and other tools export PYTHON_VERSION=3.6.8 + +# Auxmos git tag +export AUXMOS_VERSION=v0.2.3 + +# Extools git tag +export EXTOOLS_VERSION=v0.0.7