diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 9350ce35f37..35b720aee3d 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -32,6 +32,10 @@ ///Slightly slower, higher in memory. Just not optimal //#define REFERENCE_TRACKING_DEBUG +///Skips over a bunch of types that are "unlikely" to have any hanging refs, +///MASSIVELY speeding up finding references. Relatively speaking. The reftracker is still not very fast. +//#define FAST_REFERENCE_TRACKING + ///Run a lookup on things hard deleting by default. //#define GC_FAILURE_HARD_LOOKUP #ifdef GC_FAILURE_HARD_LOOKUP @@ -69,6 +73,8 @@ #define GC_FAILURE_HARD_LOOKUP // Log references in their own file #define REFERENCE_TRACKING_LOG_APART +// use fast reftracking +#define FAST_REFERENCE_TRACKING #endif // REFERENCE_DOING_IT_LIVE /// Sets up the reftracker to be used locally, to hunt for hard deletions diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm index 858af794365..ee79bd8b5c1 100644 --- a/code/modules/admin/view_variables/reference_tracking.dm +++ b/code/modules/admin/view_variables/reference_tracking.dm @@ -1,6 +1,65 @@ #ifdef REFERENCE_TRACKING #define REFSEARCH_RECURSE_LIMIT 64 +#ifdef FAST_REFERENCE_TRACKING +// typecache of types that almost certainly have no refs, and thus can be safely skipped when finding references +GLOBAL_ALIST_INIT(reftracker_skip_typecache, init_reftracker_skip_typecache()) +// empty alist we swap with GLOB.reftracker_skip_typecache whenever someone calls toggle_fast_reftracking +GLOBAL_ALIST_EMPTY(reftracker_skip_typecache_b) + +/proc/toggle_fast_reftracking() + var/alist/a = GLOB.reftracker_skip_typecache + var/alist/b = GLOB.reftracker_skip_typecache_b + GLOB.reftracker_skip_typecache = b + GLOB.reftracker_skip_typecache_b = a + +/proc/init_reftracker_skip_typecache() + . = alist() + for(var/base_type in list( + /icon, + /matrix, + /regex, + /atom/movable/mirage_holder, + /atom/movable/render_step/emissive_blocker, + /datum/armor, + /datum/asset_cache_item, + /datum/book_info, + /datum/card, + /datum/chat_payload, + /datum/comm_log_entry, + /datum/gas_mixture, + /datum/greyscale_layer, + /datum/icon_transformer, + /datum/instrument_key, + /datum/lighting_object, // only contains turf and MA refs + /datum/movespeed_modifier, + /datum/painting, + /datum/paper_input, + /datum/physiology, + /datum/plant_gene/reagent, + /datum/qdel_item, + /datum/stack_recipe, + /datum/tlv, + /datum/universal_icon, + /datum/weakref, + /datum/z_pillar, + /obj/effect/abstract/z_holder, + // stuff below isn't 100% guaranteed to be ref-free, but they're prolly not an issue + /turf/closed/mineral, + /turf/open/lava, + /turf/open/misc/asteroid, + /turf/open/openspace, + /turf/open/space, + /obj/structure/flora, // icebox and such has a LOT of these + /datum/chatmessage, + /datum/lighting_corner, + /datum/log_entry, // hopefully nobody's silly enough to accidentally pass a reference to these... right??? + /datum/reagent/consumable/nutriment, + )) + for(var/type in typesof(base_type)) + .[type] = TRUE +#endif + /datum/proc/find_references(references_to_clear = INFINITY) if(usr?.client) if(tgui_alert(usr,"Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", list("Yes", "No")) != "Yes") @@ -36,7 +95,15 @@ if(src.references_to_clear == 0) return +#ifdef FAST_REFERENCE_TRACKING + var/alist/skip_types = GLOB.reftracker_skip_typecache +#endif + for(var/datum/thing in world) //atoms (don't beleive its lies) +#ifdef FAST_REFERENCE_TRACKING + if(skip_types[thing.type]) + continue +#endif DoSearchVar(thing, "World -> [thing.type]", starting_time) if(src.references_to_clear == 0) break @@ -45,6 +112,10 @@ return for(var/datum/thing) //datums +#ifdef FAST_REFERENCE_TRACKING + if(skip_types[thing.type]) + continue +#endif DoSearchVar(thing, "Datums -> [thing.type]", starting_time) if(src.references_to_clear == 0) break