I've just finished my first pass optimization of Epoch, bringing the loading time down from 30 seconds to 2 seconds on my machine.
The brunt of the overhead in Epoch is "appearance churn". The trouble with appearance churn? It doesn't show up in the profiler. It increases world.cpu, but doesn't show the full effect honestly. Unless you understand how appearances work to any degree of certainty (and I'll admit it's a black box on the how, in some places but I've got a grasp enough to know how to work around it) you just assume that BYOND is slow and there's nothing wrong with your code.
There's been a lot of talk about implementing a new proc for changing multiple appearance values in one go, but I think this is a mistake, because procs can only use assignment operators for their arguments. This means that we'll have to be making a ton of local variables and inducing a ton of access overhead, or worse yet, we'll be creating a ton of lists and then using argslist() to call the proc. This will result in ugly, unreadable syntax becoming the "ideal".
Let's take a look at what I imagine the current suggestion would look like:
This is super ugly and unmaintainable code. It makes the engine's syntax look like hot garbage from New Jersey.
Instead, this is what I'm proposing:
var/mutable_appearance/m = src.appearance.values
m.overlays += 'herp.dmi'
m.underlays += 'derp.dmi'
m.maptext = "<span class='combat'>[maptext]"
m.icon_state += "1"
src.appearance = m
This should result in only one appearance lookup and two overlay/underlay lookups.
Notice the parity with the current method of changing appearances:
overlays += 'herp.dmi'
underlays += 'derp.dmi'
maptext = "<span class='combat'>[maptext]"
icon_state += "1"
The above results in two overlay/underlay lookups, and then four appearance lookups.
Converting to this approach would be painless for most projects, as compared to a new proc.
Attacking the problem of appearance churn has already solved a lot of problems for Epoch.
And while the above example only saves three appearance lookups, there are functions in Epoch where I've managed to reduce the churn from 3-9 overlay lookups per object using more complex techniques than the one shown above, and even using list.Copy() liberally, it's still saved us a net of over 20 seconds just on world startup time alone.
That's a speed improvement of 1000% just because I changed a small handful of functions that did nothing more offensive than:
underlays += o1
underlays += o2
underlays += o3
underlays += o4
Who is going to think the correct way to append to an overlay/underlay list is:
underlays = underlays.Copy() + list(o1,o2,o3,o4)
The suggested syntax just makes more sense and preserves a lot of what introductory programmers are already familiar with.
appearance.values is a read-only variable that creates a mutable appearance. The mutable appearance reference does not update the appearance it was copied from. When assigned to an atom.appearance, or added to an overlays/underlays list, it's converted into an appearance then and there, making for a single appearance lookup.
All values in the mutable appearance type are volatile, and therefore don't need to worry about being unique-only. It'd be just like working with an atom, but without all the appearance churn.