And others may thought that some un-optimized part of DOL is grieving their player max count
I may have something interesting (still pretty much at proof of concept stage) for those who cares to PROVE that some code may run better and that rewriting some "working" parts is worth anything
This isn't something that I'll care to advance too much, but it could be useful for other contributors to have some way of testing their updates (pretty much like Unit Test, but honestly I have no Idea how Unit Test must be done...)
Actually I made an in-game command "/benchmark" that takes some arguments to target specific method pre-set in the command handler...
This is what helped me in to track memory leaks around some of my work
Actual Benchs are targeted at skills, and use the current "player" to have some "variables" to work with, it would be better if some data could be gathered from the server objects to have a "standalone" benchmark that could be run from console (without needing any player to be logged in)
So before I start anything more general-purpose, I would like to gather some hints about what part of the game should be tested ?
Player Movements ? Mobs AI ? Spell Handlers ? Living Fighting Rules ? Geometric/Range Methods ? Loot Generator ? Mob Death Spam ?
And About how to run these tests without causing any players harm (allowing to bench in-game to look for long-run misbehavior), maybe by using a Instance Region and trying to instantiate scripted GamePlayer...
Here is my actual class handling a few tests, not really usefull but it's my starting point
- Code: Select all
using System; using System.Linq; using DOL.GS; using DOL.GS.PacketHandler; using DOL.Language; namespace DOL.GS.Commands { [CmdAttribute( "&benchmark", ePrivLevel.Admin, "Benchmark some aspects of DOL Server.", "/benchmark listskills|listspells|styles|respawns|deaths|tooltips")] public class BenchmarkCommand : AbstractCommandHandler, ICommandHandler { public void OnCommand(GameClient client, string[] args) { if (args.Length < 2 || client == null || client.Player == null) { DisplaySyntax(client); return; } long start,spent,largest; switch(args[1]) { case "hybrid": start = GameTimer.GetTickCount(); largest = 0; for (int i = 1000 ; i > 0 ; i--) { foreach (Specialization spec in client.Player.GetSpecList().Where(item => item.HybridSpellList)) { var tmp = spec.GetLinesSpellsForLiving(client.Player); if (tmp.Count > largest) largest = tmp.Count; } } spent = GameTimer.GetTickCount() - start; client.Player.Out.SendMessage(string.Format("Hybrid Benchmark took {0}ms for 1000 iterations... (Count: {1})", spent, largest), eChatType.CT_System, eChatLoc.CL_SystemWindow); break; case "listskills": start = GameTimer.GetTickCount(); largest = 0; for (int i = 1000 ; i > 0 ; i--) { var tmp = client.Player.GetAllUsableSkills(true); if (tmp.Count > largest) largest = tmp.Count; } spent = GameTimer.GetTickCount() - start; client.Player.Out.SendMessage(string.Format("Skills Benchmark took {0}ms for 1000 iterations... (Count: {1})", spent, largest), eChatType.CT_System, eChatLoc.CL_SystemWindow); break; case "listspells": start = GameTimer.GetTickCount(); largest = 0; for (int i = 1000 ; i > 0 ; i--) { var tmp = client.Player.GetAllUsableListSpells(true); if (tmp.Count > largest) largest = tmp.Count; } spent = GameTimer.GetTickCount() - start; client.Player.Out.SendMessage(string.Format("Spells Benchmark took {0}ms for 1000 iterations... (Count: {1})", spent, largest), eChatType.CT_System, eChatLoc.CL_SystemWindow); break; } } } }
I'm not too comfortable with Reflection but the Benchmark Code could be targeted at Scripted Object too, trying to Instantiate Custom Quest/Mob/Other... and test the various methods available, this way the benchmark could slowly become a "Shard Self-Test" command !