I've done some relevant testing (comparing performance cost of /image and /atom/movable), with very different results.

SkyMarshal wrote:
Creation of new objects appears to take O(n^2) time, with n being the number of objects created before the present object.

I can confirm this for /image:



I'm no statistician, but that looks pretty clear to me.

/atom/movable is another story.
It showed linear scaling with a surprisingly low coefficient on the exact same test.
For example, the 500th iteration took roughly 5ds.
Compare that to the above graph for /image, which ends at only the75th iteration, which took roughly 150ds.
(After doing the /atom/movable test, I had what I wanted, so I didn't bother to graph it)

SkyMarshal wrote:
In addition, deletion of previous objects does not alleviate the problem.

All of my results contradicted this.
In the graph above, this is the difference between the 2 series. In "with deletion", all of the created instances were deleted every 25 iterations (2500 instances). This very obviously cut run time down to near-zero.

Ter13 wrote:
I've yet to see even a cursory understanding of maintaining sane data-structures from the code I see on a daily basis.

One of the problems is that in SS13, "letting it GC" is more like "hoping it GC's". It's nigh-impossible to know whether or not, somewhere deep in tens of thousands of lines of spaghetti code, something is holding a reference to that object.
After seeing things like the data in the graph above, it'd be insane to take those odds.
At the moment, the risk/benefit ratio favors force del().


Back to BYOND in general, /atom/movable shows linear scaling, while /image shows quadratic.
Then there's the OP test using /datum, with different results entirely.
There's obviously huge differences between the various classes.

It'd be good to try and pin down what's behind this.
For starters, the data I got looks worryingly regular. Definitely doesn't look like a fluke.
What exactly does /image do that /atom/movable doesn't?

The main thing that strikes me is that this is yet another thing that looks like a memleak.
At the extreme end of the /atom/movable tests, my laptop was at 100% CPU usage.
It still managed to choke out more iterations in under 10ds.
On the other hand, during the /image tests, CPU never went above 70%, even though the iterations were taking more than 100ds to process.
As for memory usage? The usual. Daemon eats only a tiny chunk of memory.
Would really help to have just about any profiling tools right now...



Interesting. What is the test code you are running? Are you using the latest build (which had improvements mainly to the dereferencing of these objects). I'm sure we can isolate the problem but it would be good to running the same tests so we are on the same page.
The set in the graph was from a proc that looked something like this:

//what changed for the /atom/movable version
/*what changed for the "with" version*/

/mob/verb/test_images_without_deletion()
var/list/imgs = list() // atms
var/image/img = null // var/atom/movable/atm
var/init = 0
world << "Starting test..."
file("code/modules/graphics/test.txt") << "Begin images - without/*with*/ deletion"
for(var/h=1,h<=3,h++)
for(var/i=1,i<=25,i++)
for(var/j=1,j<=100,j++)
img = image(icon='icons/test.dmi',loc=src.loc,icon_state="test",layer=20)
//atm = new/atom/movable{icon='icons/test.dmi';icon_state="test";layer=20}(src.loc)
usr << img //commented out
animate(img,pixel_x=(rand(-32,32)),pixel_y=(rand(-32,32)),time=20,easing=CIRCULAR_EASING)
imgs += img
file("code/modules/graphics/test.txt") << "[i]: [world.timeofday-init]"
for(var/I in imgs) del(I) /*commented out*/
file("code/modules/graphics/test.txt") << "End images - without/*with*/ deletion."
world << "Finished"
return


Used that as a template and tweaked the numbers around. Meant for comparing /atom/movable and /image, could be cleaned up a lot.
After a few trials, I realized that /images were taking noticeably longer each time, so I tossed a force del() in there to see if it'd help. Helped quite a bit, figured it'd make a pretty striking graph.

Ran all this on 504, along with all kinds of other tests, mostly creating/animating/deleting huge numbers of objects. Story was pretty much the same on everything. /images absolutely had to be del()d/GC'd or else performance would drop like a rock. /atom/movable's didn't have that problem: could create and delete thousands per tick without immediate problems. For example:



Also got several other odd results. Off the top of my head, a 10,000-member object pool took twice as long to initialize with /a/m than with /image (~8 ds vs ~4ds). Destroying it though, was another story.
With /a/m, deleting all the members took ~6ds. With /image, it crashed Daemon every time I tried.


Don't /images always have a reference, in the case that they're outputted to the client via usr << I?

I'm pretty sure that adds them to the client.images list...which would be a reference, and therefore not GC'd, no?
In response to Super Saiyan X
Super Saiyan X wrote:
Don't /images always have a reference, in the case that they're outputted to the client via usr << I?

I'm pretty sure that adds them to the client.images list...which would be a reference, and therefore not GC'd, no?

Absolutely correct.
Just an update; with threading disabled Eternia is running smoother than I've ever seen it run. Averaging 20%-30% CPU with 60-70 players, which is down from 60%-70% in similar circumstances.

I'm also not noticing a gradual increase over time, but we'll know more after it's been running some hours.
Update after running some tests with the most recent build (506.1244 (without VS2013, no threading)):
Big improvement on new/image and new/datum. new/image was about twice as fast as new/atom/movable, now it's about an order of magnitude.
new/atom/movable doesn't show any noticeable boost, but it could just be overshadowed by the rest of its initialization overhead.

Still trying to narrow down what's causing that quadratic growth. Can rule out new(), at least.


Edit: Found it.
It's the images' loc. Unlike atoms, putting them inside "usr" does... something bad.
Put them both in usr.loc, and /image is faster than /atom/movable by a 3 to 1 margin.
Further info: http://www.byond.com/forum/?post=1560083
Page: 1 2