diff --git a/baystation12.dme b/baystation12.dme index cf79ebe5caf..a624f05cc7f 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -776,6 +776,7 @@ #include "code\modules\admin\verbs\playsound.dm" #include "code\modules\admin\verbs\possess.dm" #include "code\modules\admin\verbs\pray.dm" +#include "code\modules\admin\verbs\profiling.dm" #include "code\modules\admin\verbs\randomverbs.dm" #include "code\modules\admin\verbs\striketeam.dm" #include "code\modules\admin\verbs\striketeam_syndicate.dm" diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm index a8629706611..8ae1c67ab59 100644 --- a/code/ATMOSPHERICS/components/unary/vent_pump.dm +++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm @@ -75,9 +75,10 @@ process() ..() + CHECK_DISABLED(vents) if(stat & (NOPOWER|BROKEN)) return - if(!node) + if (!node) on = 0 //broadcast_status() // from now air alarm/control computer should request update purposely --rastaf0 if(!on) diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm index 046f70fd10b..28dfe52f4c1 100644 --- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm @@ -98,9 +98,10 @@ process() ..() + CHECK_DISABLED(scrubbers) if(stat & (NOPOWER|BROKEN)) return - if(!node) + if (!node) on = 0 //broadcast_status() if(!on) diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index 12f621f12bf..17c34802845 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -1,232 +1,363 @@ -// simplified MC that is designed to fail when procs 'break'. When it fails it's just replaced with a new one. -// It ensures master_controller.process() is never doubled up by killing the MC (hence terminating any of its sleeping procs) - -var/global/datum/controller/game_controller/master_controller -var/global/last_tick_timeofday = world.timeofday -var/global/last_tick_duration = 0 -var/global/air_processing_killed = 0 -var/global/pipe_processing_killed = 0 - -datum/controller/game_controller - var/minimum_ticks = 20 - var/breather = 3 - var/airt = 0 - var/sunt = 0 - var/mobt = 0 - var/dist = 0 - var/mcht = 0 - var/objt = 0 - var/pipet = 0 - var/powt = 0 - var/nanot = 0 - var/tikt = 0 - -datum/controller/game_controller/New() - . = ..() - - if(master_controller != src) // THERE CAN ONLY BE ONE - log_debug("Rebuilding Master Controller") - - if(istype(master_controller)) - recover() - qdel(master_controller) - - master_controller = src - - if(job_master == null) - job_master = new /datum/controller/occupations() - job_master.SetupOccupations() - job_master.LoadJobs("config/jobs.txt") - world << "\red \b Job setup complete" - - if(!syndicate_code_phrase) syndicate_code_phrase = generate_code_phrase() - if(!syndicate_code_response) syndicate_code_response = generate_code_phrase() - if(!emergency_shuttle) emergency_shuttle = new /datum/shuttle_controller/emergency_shuttle() - -datum/controller/game_controller/proc/setup() - world.tick_lag = config.Ticklag - - // notify the other process that we started up - socket_talk = new /datum/socket_talk() - socket_talk.send_raw("type=startup") - - createRandomZlevel() - - if(!air_master) - air_master = new /datum/controller/air_system() - air_master.Setup() - - if(!ticker) - ticker = new /datum/controller/gameticker() - - if(!garbage) - garbage = new /datum/controller/garbage_collector() - - setup_objects() - setupgenetics() - setupfactions() - setup_economy() - SetupXenoarch() - - for(var/i=0, i 5) - world << "RUNTIMES IN ATMOS TICKER. Killing air simulation!" - world.log << "### ZAS SHUTDOWN" - message_admins("ZASALERT: unable to run [air_master.tick_progress], shutting down!") - log_admin("ZASALERT: unable run zone/process() -- [air_master.tick_progress]") - air_processing_killed = 1 - air_master.failed_ticks = 0 - airt++; - - sun.calc_position(); sunt++; sleep(breather) - processMobs(); mobt++; sleep(breather) - processDiseases(); dist++; sleep(breather) - processMachines(); mcht++; sleep(breather) - processObjects(); objt++; sleep(breather) - if(!pipe_processing_killed) - processPipenets(); pipet++; sleep(breather) - processPowernets(); powt++; sleep(breather) - processNano(); nanot++ - processEvents() - ticker.process(); tikt++ - - var/end_time = world.timeofday - if(end_time < start_time) - start_time -= 864000 //deciseconds in a day - sleep(round(minimum_ticks - (end_time-start_time), 1)) - else - sleep(10) - -/datum/controller/game_controller/proc/processMobs() - for(var/mob/M in mob_list) - if(M == null) - mob_list -= M - continue - M.Life() - -/datum/controller/game_controller/proc/processDiseases() - for(var/datum/disease/D in active_diseases) - if(D == null) - active_diseases -= D - continue - D.process() - -/datum/controller/game_controller/proc/processMachines() - for(var/obj/machinery/M in machines) - if(M == null || M.loc == null) - // Not sure if safe to remove from list - continue - - if(M.process() == PROCESS_KILL) - M.inMachineList = 0 - machines.Remove(M) - continue - - if(M.use_power) - M.auto_use_power() - -/datum/controller/game_controller/proc/processObjects() - for(var/obj/O in processing_objects) - if(O == null || O.loc == null) - processing_objects -= O - continue - O.process() - -/datum/controller/game_controller/proc/processPipenets() - for(var/datum/pipe_network/P in pipe_networks) - if(P == null) - pipe_networks -= P - continue - P.process() - -/datum/controller/game_controller/proc/processPowernets() - for(var/datum/powernet/P in powernets) - if(P == null) - powernets -= P - continue - P.reset() - -/datum/controller/game_controller/proc/processNano() - for(var/datum/nanoui/N in nanomanager.processing_uis) - if(N == null) - nanomanager.processing_uis -= N - continue - N.process() - -/datum/controller/game_controller/proc/processEvents() - for(var/datum/event/E in events) - if(E == null) - events -= E - continue - checkEvent() - -datum/controller/game_controller/recover() //Mostly a placeholder for now. - . = ..() - var/msg = "## DEBUG: [time2text(world.timeofday)] MC restarted. Reports:\n" - for(var/varname in master_controller.vars) - switch(varname) - if("tag","type","parent_type","vars") continue - else - var/varval = master_controller.vars[varname] - if(istype(varval,/datum)) - var/datum/D = varval - msg += "\t [varname] = [D.type]\n" - else - msg += "\t [varname] = [varval]\n" - world.log << msg +//simplified MC that is designed to fail when procs 'break'. When it fails it's just replaced with a new one. +//It ensures master_controller.process() is never doubled up by killing the MC (hence terminating any of its sleeping procs) +//WIP, needs lots of work still + +var/global/datum/controller/game_controller/master_controller //Set in world.New() + +var/global/last_tick_timeofday = world.timeofday +var/global/last_tick_duration = 0 + +var/global/air_processing_killed = 0 +var/global/pipe_processing_killed = 0 + +#ifdef PROFILE_MACHINES +// /type = time this tick +var/list/machine_profiling=list() +#endif + +datum/controller/game_controller + var/breather_ticks = 2 //a somewhat crude attempt to iron over the 'bumps' caused by high-cpu use by letting the MC have a breather for this many ticks after every loop + var/minimum_ticks = 20 //The minimum length of time between MC ticks + + var/air_cost = 0 + var/sun_cost = 0 + var/mobs_cost = 0 + var/diseases_cost = 0 + var/machines_cost = 0 + var/objects_cost = 0 + var/networks_cost = 0 + var/powernets_cost = 0 + var/nano_cost = 0 + var/events_cost = 0 + var/ticker_cost = 0 + var/total_cost = 0 + + var/last_thing_processed + var/mob/list/expensive_mobs = list() + var/rebuild_active_areas = 0 + +datum/controller/game_controller/New() + . = ..() + + // There can be only one master_controller. Out with the old and in with the new. + if (master_controller != src) + log_debug("Rebuilding Master Controller") + + if (istype(master_controller)) + recover() + qdel(master_controller) + + master_controller = src + + if (isnull(job_master)) + job_master = new /datum/controller/occupations() + job_master.SetupOccupations() + job_master.LoadJobs("config/jobs.txt") + world << "\red \b Job setup complete" + + if(!syndicate_code_phrase) syndicate_code_phrase = generate_code_phrase() + if(!syndicate_code_response) syndicate_code_response = generate_code_phrase() + if(!emergency_shuttle) emergency_shuttle = new /datum/shuttle_controller/emergency_shuttle() + +datum/controller/game_controller/proc/setup() + world.tick_lag = config.Ticklag + + // notify the other process that we started up + socket_talk = new /datum/socket_talk() + socket_talk.send_raw("type=startup") + + createRandomZlevel() + + if(!air_master) + air_master = new /datum/controller/air_system() + air_master.Setup() + + if(!ticker) + ticker = new /datum/controller/gameticker() + + if(!garbage) + garbage = new /datum/controller/garbage_collector() + + setup_objects() + setupgenetics() + setupfactions() + setup_economy() + SetupXenoarch() + + for(var/i=0, i 5) + world << "RUNTIMES IN ATMOS TICKER. Killing air simulation!" + world.log << "### ZAS SHUTDOWN" + message_admins("ZASALERT: unable to run [air_master.tick_progress], shutting down!") + log_admin("ZASALERT: unable run zone/process() -- [air_master.tick_progress]") + air_processing_killed = 1 + air_master.failed_ticks = 0 + + air_cost = (world.timeofday - timer) / 10 + + sleep(breather_ticks) + + //SUN + timer = world.timeofday + last_thing_processed = sun.type + sun.calc_position() + sun_cost = (world.timeofday - timer) / 10 + + sleep(breather_ticks) + + //MOBS + timer = world.timeofday + processMobs() + mobs_cost = (world.timeofday - timer) / 10 + + sleep(breather_ticks) + + //DISEASES + timer = world.timeofday + processDiseases() + diseases_cost = (world.timeofday - timer) / 10 + + sleep(breather_ticks) + + //MACHINES + timer = world.timeofday + processMachines() + machines_cost = (world.timeofday - timer) / 10 + + sleep(breather_ticks) + + //OBJECTS + timer = world.timeofday + processObjects() + objects_cost = (world.timeofday - timer) / 10 + + sleep(breather_ticks) + + //PIPENETS + if(!pipe_processing_killed) + timer = world.timeofday + processPipenets() + networks_cost = (world.timeofday - timer) / 10 + + sleep(breather_ticks) + + //POWERNETS + timer = world.timeofday + processPowernets() + powernets_cost = (world.timeofday - timer) / 10 + + sleep(breather_ticks) + + //NANO UIS + timer = world.timeofday + processNano() + nano_cost = (world.timeofday - timer) / 10 + + sleep(breather_ticks) + + //EVENTS + timer = world.timeofday + processEvents() + events_cost = (world.timeofday - timer) / 10 + + //TICKER + timer = world.timeofday + last_thing_processed = ticker.type + ticker.process() + ticker_cost = (world.timeofday - timer) / 10 + + //TIMING + total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + ticker_cost + + var/end_time = world.timeofday + if(end_time < start_time) + start_time -= 864000 //deciseconds in a day + sleep( round(minimum_ticks - (end_time - start_time),1) ) + else + sleep(10) + +datum/controller/game_controller/proc/processMobs() + var/i = 1 + expensive_mobs.Cut() + while(i<=mob_list.len) + var/mob/M = mob_list[i] + if(M) + var/clock = world.timeofday + last_thing_processed = M.type + M.Life() + if((world.timeofday - clock) > 1) + expensive_mobs += M + i++ + continue + mob_list.Cut(i,i+1) + +/datum/controller/game_controller/proc/processDiseases() + for (var/datum/disease/Disease in active_diseases) + if(Disease) + last_thing_processed = Disease.type + Disease.process() + continue + + active_diseases -= Disease + +/datum/controller/game_controller/proc/processMachines() + #ifdef PROFILE_MACHINES + machine_profiling.Cut() + #endif + + for (var/obj/machinery/Machinery in machines) + if (Machinery && Machinery.loc) + last_thing_processed = Machinery.type + + #ifdef PROFILE_MACHINES + var/start = world.timeofday + #endif + + if(PROCESS_KILL == Machinery.process()) + Machinery.inMachineList = 0 + machines.Remove(Machinery) + continue + + if (Machinery && Machinery.use_power) + Machinery.auto_use_power() + + #ifdef PROFILE_MACHINES + var/end = world.timeofday + + if (!(Machinery.type in machine_profiling)) + machine_profiling[Machinery.type] = 0 + + machine_profiling[Machinery.type] += (end - start) + #endif + + +/datum/controller/game_controller/proc/processObjects() + for (var/obj/Object in processing_objects) + if (Object && Object.loc) + last_thing_processed = Object.type + Object.process() + continue + + processing_objects -= Object + +/datum/controller/game_controller/proc/processPipenets() + last_thing_processed = /datum/pipe_network + + for (var/datum/pipe_network/Pipe_Network in pipe_networks) + if(Pipe_Network) + Pipe_Network.process() + continue + + pipe_networks -= Pipe_Network + +/datum/controller/game_controller/proc/processPowernets() + last_thing_processed = /datum/powernet + + for (var/datum/powernet/Powernet in powernets) + if (Powernet) + Powernet.reset() + continue + + powernets -= Powernet + +/datum/controller/game_controller/proc/processNano() + for (var/datum/nanoui/Nanoui in nanomanager.processing_uis) + if (Nanoui) + Nanoui.process() + continue + + nanomanager.processing_uis -= Nanoui + +/datum/controller/game_controller/proc/processEvents() + last_thing_processed = /datum/event + + for (var/datum/event/Event in events) + if (Event) + Event.process() + continue + + events -= Event + + checkEvent() + +datum/controller/game_controller/recover() //Mostly a placeholder for now. + . = ..() + var/msg = "## DEBUG: [time2text(world.timeofday)] MC restarted. Reports:\n" + for(var/varname in master_controller.vars) + switch(varname) + if("tag","type","parent_type","vars") continue + else + var/varval = master_controller.vars[varname] + if(istype(varval,/datum)) + var/datum/D = varval + msg += "\t [varname] = [D.type]\n" + else + msg += "\t [varname] = [varval]\n" + world.log << msg + diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index fae8899575c..611659ff840 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1125,6 +1125,21 @@ Pressure: [env.return_pressure()]"} usr << "\blue Dumped to instances.csv." +#ifdef PROFILE_MACHINES +/client/proc/cmd_admin_dump_macprofile() + set category = "Debug" + set name = "Dump Machine Profiling" + + var/F = file("machine_profiling.csv") + fdel(F) + F << "type,nanoseconds" + for(var/typepath in machine_profiling) + var/ns = machine_profiling[typepath] + F << "[typepath],[ns]" + + usr << "\blue Dumped to machine_profiling.csv." +#endif + /client/proc/gib_money() set category = "Fun" set name = "Dispense Money" diff --git a/code/modules/admin/verbs/profiling.dm b/code/modules/admin/verbs/profiling.dm new file mode 100644 index 00000000000..28536f3a063 --- /dev/null +++ b/code/modules/admin/verbs/profiling.dm @@ -0,0 +1,25 @@ +var/global/PROFILING_VERBS = list( + /client/proc/disable_scrubbers, + /client/proc/disable_vents, +) +/* +/client/proc/disable_scrubbers() + set category = "Debug" + set name = "Disable all scrubbers" + + disable_scrubbers = !disable_scrubbers + world << "\red Scrubbers are now [disable_scrubbers?"OFF":"ON"]." +*/ + +#define gen_disable_proc(TYPE,LABEL) \ +/client/proc/disable_##TYPE() { \ + set category = "Debug"; \ + set name = "Disable all "+LABEL; \ + disable_##TYPE = !disable_##TYPE; \ + world << "\red "+LABEL+" are now [disable_##TYPE?"OFF":"ON"]."; \ + } + +gen_disable_proc(scrubbers,"Scrubbers") +gen_disable_proc(vents, "Vents") + +#undef gen_disable_proc \ No newline at end of file diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index d486cb98e96..063fc7d0f7b 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1173,16 +1173,17 @@ note dizziness decrements automatically in the mob's Life() proc. if (master_controller) stat(null, "MasterController-[last_tick_duration] ([master_controller.processing?"On":"Off"]-[master_controller.iteration])") - stat(null, "Air-[master_controller.airt]") - stat(null, "Sun-[master_controller.sunt]") - stat(null, "Mob-[master_controller.mobt]\t#[mob_list.len]") - stat(null, "Dis-[master_controller.dist]\t#[active_diseases.len]") - stat(null, "Mch-[master_controller.mcht]\t#[machines.len]") - stat(null, "Obj-[master_controller.objt]\t#[processing_objects.len]") - stat(null, "Pip-[master_controller.pipet]\t#[pipe_networks.len]") - stat(null, "Pow-[master_controller.powt]\t#[powernets.len]") - stat(null, "NUI-[master_controller.nanot]\t#[nanomanager.processing_uis.len]") - stat(null, "Tik-[master_controller.tikt]") + stat(null, "Air-[master_controller.air_cost]") + stat(null, "Sun-[master_controller.sun_cost]") + stat(null, "Mob-[master_controller.mobs_cost]\t#[mob_list.len]") + stat(null, "Dis-[master_controller.diseases_cost]\t#[active_diseases.len]") + stat(null, "Mch-[master_controller.machines_cost]\t#[machines.len]") + stat(null, "Obj-[master_controller.objects_cost]\t#[processing_objects.len]") + stat(null, "PiNet-[master_controller.networks_cost]\t#[pipe_networks.len]") + stat(null, "Ponet-[master_controller.powernets_cost]\t#[powernets.len]") + stat(null, "NanoUI-[master_controller.nano_cost]\t#[nanomanager.processing_uis.len]") + stat(null, "Tick-[master_controller.ticker_cost]") + stat(null, "ALL-[master_controller.total_cost]") else stat(null, "master controller - ERROR") diff --git a/code/setup.dm b/code/setup.dm index 4b3440f37a1..38412c1e6eb 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -1,6 +1,16 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 #define DEBUG +#define PROFILE_MACHINES // Disable when not debugging. + +#ifdef PROFILE_MACHINES +#define CHECK_DISABLED(TYPE) if(disable_##TYPE) return +var/global/disable_scrubbers = 0 +var/global/disable_vents = 0 +#else +#define CHECK_DISABLED(TYPE) /* DO NOTHINK */ +#endif + #define PI 3.1415 #define R_IDEAL_GAS_EQUATION 8.31 //kPa*L/(K*mol) @@ -435,7 +445,7 @@ var/MAX_EXPLOSION_RANGE = 14 var/list/accessable_z_levels = list("1" = 5, "3" = 10, "4" = 15, "5" = 10, "6" = 60) //This list contains the z-level numbers which can be accessed via space travel and the percentile chances to get there. -//(Exceptions: extended and nuke) -Errorage +//(Exceptions: extended, sandbox and nuke) -Errorage //Was list("3" = 30, "4" = 70). //Spacing should be a reliable method of getting rid of a body -- Urist. //Go away Urist, I'm restoring this to the longer list. ~Errorage @@ -654,6 +664,7 @@ var/list/TAGGERLOCATIONS = list( //Please don't edit these values without speaking to Errorage first ~Carn //Admin Permissions +#define R_BUILDMODE 1 #define R_ADMIN 2 #define R_BAN 4 #define R_FUN 8