29 Dec, 2011, Rarva.Riendf wrote in the 1st comment:
Votes: 0
for a quest purpose I am killing like 9k mobs at once, and it takes like 2 seconds in my code base, I find this quite slow even if it goes through all the death methods.
I shortcircuited some messages when I do stuff like that, but I was wondering just how fast you made it.
And if you knew wich is the best tool to use and how to configure it to only watch what time is spent and where between two breakpoints.
I use Eclipse CDT on Linux (for Valgrind) and Windows (Cygwin) for convenience. And it is C code.
29 Dec, 2011, Runter wrote in the 2nd comment:
Votes: 0
Two solutions.

A) Multithread the process so that it doesn't block the main thread while the process is happening. You just have to be vigilant about locking resources. (Probably just the npc you're currently removing from the game.) This would probably totally solve the underlying problem you have. That your game is probably stalling for 2 seconds during this time. This is how almost any transient processing should happen in a program. Once the blocking is out of the picture, that 2 seconds doesn't really matter. 2 seconds isn't that much for a job to process something, unless it's not done as a background task. I admit this may be easier said than done, since locking the resource may be very difficult since your program may use it all over the place.

B) Make the process more efficient. Maybe you can drop the time from 2 seconds to 1. The problem with this in my view is it's dependent upon the hardware you're using. You could probably drop it down dramatically just by using beefier hardware in conjunction with code modification. Ultimately, the minimum stuff you must do for 9000 removals of NPCs from the game is going to be a load of stuff. That means there's no magical way to lower that. However, there is a usecase here for a memory pool. So that instead of having to free each pointer you could free all 9000 npcs with a single call. Boost::Pool is very useful for this type of thing.

As far as profiling this goes, you could probably put it into a function of some kind and just use gprof or something similar, only looking at the time in that function.
29 Dec, 2011, plamzi wrote in the 3rd comment:
Votes: 0
Another idea is to do it in batches of, say, 1k max, with appropriate intervals in between for normal game events. That should be a lot simpler than multi-threading, but it depends on whether you care whether all these mobs die in one fell swoop (can't imagine why you would) vs. 9 fell swoops.
29 Dec, 2011, Runter wrote in the 4th comment:
Votes: 0
plamzi said:
Another idea is to do it in batches of, say, 1k max, with appropriate intervals in between for normal game events. That should be a lot simpler than multi-threading, but it depends on whether you care whether all these mobs die in one fell swoop (can't imagine why you would) vs. 9 fell swoops.


It would be ideal to break it down to the minimum amount of work that could be done in one pass. Then through each pass of the main game loop just pop one of these from the queue until all 9000 are gone. Considering that's like 9000 passes at 4 passes a second, it might take a while, though. So it would be great if you could do the work in place of sleeping (as most rom based games do between pulses). It would require reworking this part of the system, though.

Basically the logic for that would be

loop 
break if time for next pulse

if work queue is empty
sleep
else
pop queue and do task
end
sleep if work queue is empty
end
29 Dec, 2011, Rarva.Riendf wrote in the 5th comment:
Votes: 0
Multithreading in this case is very dodgy as mprog on death can do pretty much anything so I would have lock all over the place, not sure I would gain a lot.
A memory pool would be too many modification for just one case that bother me, but Plamzi made me rethink the thing and I think I wlll do it like he suggests, timed event, clearring everything but in some rounds instead of a single one, so players wont notice it.

Why I did it in the first place ? Well it is a realm based quest where the immortals are getting fed up with their creation and kill them all, and when it starts to repop 1/3 of the mobs are zmbies that will prey on any living. That and many other realm modification. Works perfectly except for the annoying 2sec lag at the start of the quest.
But I could simply spread it area per area , some of them each round. Way better idea than trying to optimize code, Thank a lot Plamzi :)
29 Dec, 2011, Runter wrote in the 6th comment:
Votes: 0
Why bother implementing a timer system? Why bother "spreading work out across areas" at different events? Do the work when your system is normally sleeping between pulses… It's not much work and it meets basic hurdles for separation of concerns. In other words, it's maintainable.
29 Dec, 2011, Rarva.Riendf wrote in the 7th comment:
Votes: 0
Runter said:
Why bother implementing a timer system? Why bother "spreading work out across areas" at different events? Do the work when your system is normally sleeping between pulses… It's not much work and it meets basic hurdles for separation of concerns. In other words, it's maintainable.

I do not bother implementing a timer system, I already have one to deal with bombs not exploding right when you enter a room :P Otherwise I would agree.
29 Dec, 2011, David Haley wrote in the 8th comment:
Votes: 0
I think you should clarify what exactly you are doing. When you kill every single mob, do you want them to die normally? Are you wanting to wipe the world and you don't care about how they die?

The exact parameters will make a big difference here. If you're just wiping out all mobs, you can take all kinds of shortcuts that will make the process very quick. If you truly need to invoke normal death routines, then what people have been saying here is good; doing it in phases, etc.
29 Dec, 2011, Rarva.Riendf wrote in the 9th comment:
Votes: 0
Yeah killing them normally, leaving corpses, running the death mprogs , eveyrything that should occur if a player killed them.
I just remove the message feedback while I do massive commands like this.
30 Dec, 2011, David Haley wrote in the 10th comment:
Votes: 0
OK. A priori it is surprising that it takes so long to kill 9k mobs. I suspect that there is a fair bit of cleanup that is happening that you don't need, although it's hard to know for sure. Maybe you can separate mobs with death progs and mobs without; I suspect that the ones without will be quicker to destroy.

There are profiling tools that you can run on Linux but they're not always easy to use, and additionally, most are "always on" and not turn-on/turn-off. You could try doing something like this: do manual timing, and for each vnum, maintain a list of cleanup times for that vnum. Then average them. That will help you see if a particular vnum is slow to destroy, or if it's uniform.

It might also matter if mobs are in the same room as players when they are destroyed. Those might invoke additional messages that you didn't turn off, slowing things down.

It's also possible that the deallocation is slowing things down. You might want to defer deallocation if you're not already doing so, although 9000 objects isn't that much. (9001 however would be… OVER NINE THOUSAND)
30 Dec, 2011, Runter wrote in the 11th comment:
Votes: 0
There's so many variables we don't know about for why it might take 2 seconds… for example, it would be no surprise if it were running on really weak or shared/limited hardware. Anyways, profiling might let you know what part is actually so slow.
30 Dec, 2011, Rarva.Riendf wrote in the 12th comment:
Votes: 0
Yeah many parameters, I know, that is why I asked if it was 'surprising' or not. The hardware is not that weak, but 9k mobs to clean does not seen that big. I think i should probably run a stock rom and test in it. I added a lot of stuff in death, so who knows.
Thanks for all the input, helps me find new path to explore.
30 Dec, 2011, Runter wrote in the 13th comment:
Votes: 0
9k mobs can be multiplied by the number of strings allocated on the struct. Or items in their inventory * allocated fields. Depending on how many frees/clean ups that actually adds up to, it could be a lot. So I disagree that it's freeing 9,000 objects. It's free n * 9000 objects, whereas we don't even know what n is. Therefore, it shouldn't be surprising to anyone unless they're working under the assumption that n is very small.
30 Dec, 2011, David Haley wrote in the 14th comment:
Votes: 0
Sorry, I should have been more precise… I meant 9000 objects-with-fields, not just objects. I was thinking C++ terms where deleting an object invokes its destructor; the free_mob routines are, basically, destructors.

EDIT:
That said, many systems allocate and destroy many, many, many thousands of objects every single second, so I'd tend to assume the slowness is elsewhere than allocation. It's still worth checking though.
30 Dec, 2011, Rarva.Riendf wrote in the 15th comment:
Votes: 0
Will look into it, even if I have a strong work around solution. Especially as the repop is quite instant for 6k mob.
0.0/15