RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Experimental Feature: DynamicSaveStrategy

ASayre

RunUO Developer
If you look on the SVN (or attached), you'll find what's been keeping me busy the past few days: A new Save strategy to take the place of the never-quite-working ParallelSaveStrategy.

The Dynamic save strategy parallelizes the Serialization of the world, allowing us to take full advantage of today's multi processor, multi core systems.

I make heavy use of the .NET 4.0 TPL (Task Parallel Library). If you're not on .NET 4.0, you'll need to upgrade to use this. Don't forget to compile with /d:Framework_4_0

What it does for each serialized type (item/mobile/guild):

Divides up the list of that type into large chunks. Each of these chunks gets it's own thread. Each of these threads Serialize to their own MemoryStream. As each of these chunks complete (in parallel), we add each completed memory stream to a queue, to be processed by another Thread.

We also launch up a thread for each type which watches this queue and waits for incoming memoryStreams. This thread then takes the memory stream, copies it to disk, writes the relevent index entries, and continues waiting until the other threads are done adding.

Because of the TPL's dynamic partitioning of the chunks, we have a form of load balancing. I won't go into how it works, as MSDN can provide prettier pictures. Just know that it's a conscious decision to not divide it into numberOfProcessors threads, each with the same number of entities. I toyed with the idea of creating a custom Partitioner, but empirical evidence shows that the TPL's partitioning is already damn good.

Since we're using our IO resources as fast as we can process the entities, and we're using whatever CPU power available, we won't (in theory) be wasting any idle cycles or io left unused.

However, theory is only theory. In practicality, the task parallelism has a bit of overhead. Also, with writes coming in when they come in, total i/o speed drops way down.

This is designed for servers with a lot of spare cycles. It works best on those that would've been otherwise (using the DualSaveStrategy) CPU bound.

Because of the way the system is designed, it's easy enough to have the write to file threads continue even though everything else is finished. This is not enabled by default, because it's dangerous, if you close RunUO during the save, or save again while it's still flushing to disk, bad things happen. These can be avoided, but that's a future work item.

For now, ONLY if you don't want to wait for the IO threads to continue, comment out
Task.WaitAll(saveTasks);
CloseFiles();

And then Uncomment
//Task.Factory.ContinueWhenAll(saveTasks, _ => CloseFiles());
in DynamicSaveStrategy.cs ~ line 75
Note that the above is dangerous as stated for the reasons above. If you're IO bound, the above will help with the save times. If not, there's no reason to do it.


For everyone else who just wants to try out the rest of the Save Strategy (This is mostly untested, except for the most basic of tests so don't use on a production shard!)

Change the if (processorCount > 16) in SaveStrategy.cs to a more reasonable number, like '4'. The reasons for the 16 there is just so it doesn't get used by anyone by default while this code is still in it's infancy.

Please let me know of any comments/concerns/bugs/optimizations!
 

Attachments

  • DynamicSaveStrategy.zip
    3.7 KB · Views: 27

Ravenal

Knight
Nice job man =) Keep it up I am really interested in seeing what this will do for big servers like Hybrid.
 

Pure Insanity

Sorceror
I was under the assumption that RunUO already used multiple cores and processors? Does it not...?

And this new method...it lowers save time down a lot if the person had a newer processor? That's all this does? I'm not sure I understand the entire point of this...and I'm also guessing that once finish all of this will be tied into 2.x?
 

Ravenal

Knight
I was under the assumption that RunUO already used multiple cores and processors? Does it not...?

And this new method...it lowers save time down a lot if the person had a newer processor? That's all this does? I'm not sure I understand the entire point of this...and I'm also guessing that once finish all of this will be tied into 2.x?

Single Core is for core processors who only have a single processor. Dual Core are for two or more up until you have about 16. The problem is Parallel right now I believe just uses the typical Dual Core strategy, because it was never completed and what not but because of the new TPL System in .NET Framework 4.0. ASayre is experimenting to see if he can complete what was difficult in the past.
 

Pure Insanity

Sorceror
Ah...I see. Well I only have a dual core processor, probably why I've never noticed? Lol.

Anyways, I think it's awesome that all of this work is being done to RunUO. Seems like RunUO has really been getting a lot of attention lately...which is awesome. =D
 

ASayre

RunUO Developer
I was under the assumption that RunUO already used multiple cores and processors? Does it not...?

And this new method...it lowers save time down a lot if the person had a newer processor? That's all this does? I'm not sure I understand the entire point of this...and I'm also guessing that once finish all of this will be tied into 2.x?

Elaborating on this:
RunUO currently has three save Strategies. Standard, Dual and Parallel.
Standard uses one thread. Saves the Items, Saves the Mobiles, Saves the Guilds. In that order.
Dual uses two threads. Saves the Items and Saves the Mobile concurrently. Then saves the guilds.
Parallel uses a thread for each processor to do the saving. However, this feature was never completed as it had synchronization issues.

Dynamic is intended to replace Parallel. Dynamic uses a variable number of threads based on what's needed to try and minimize idleness.

This system will help more with larger shards, where the bottleneck is the CPU. This system has a higher I/O cost because it writes as it gets data instead of in single passes, and there's a bit of overhead for the parallelization.

There's a work item to make the background saving safer so that shards which are I/O bound can still get a performance benefit from the parallelization.
 

Jeff

Lord
I've been doing some testing with ASayre today.

1,757,035 items
251,002 mobiles

DualSaveStrategy (most commonly used)
2.2 seconds

DynamicSaveStrategy:
1.1 seconds

50% improvement... not to shabby.
 

ASayre

RunUO Developer
SVN Updated. Various performance improvements. Writes (safely!) in background except on manual save. To have manual save also write in background, use [backgroundSave ([bgsave).


To use, change the numberOfProcs check in SaveStrategy.cs per original post.


Everything should be ready for use in a production environment. However, we've only had one machine to test (Jeff's) as mine is only a dual-core.

For all the brave souls out there, please give this a run using this new save strategy and post the performance difference (if any)
 

Pure Insanity

Sorceror
Awesome, just wish I had a quad core. Would be pretty neat to not have the world pause for every save. And just let players continue on without ever having to pause. Can't wait to get a new server to test it out on. =D
 

Jeff

Lord
Awesome, just wish I had a quad core. Would be pretty neat to not have the world pause for every save. And just let players continue on without ever having to pause. Can't wait to get a new server to test it out on. =D
The world still pauses, its just a quicker pause now.
 

Pure Insanity

Sorceror
Does it still pause if you use a background save like ASayre mentioned...? I think I still don't understand this completely...lol. Thinking I'm just going to have to see it in action to understand it.
 

Jeff

Lord
Thats only to write the data to the disk. The server still pauses to save state to memory, then unpauses to write the state to the disk.
 
Top