[Opensim-dev] Memory cache

Imaze Rhiano imaze.rhiano at gmail.com
Wed May 27 22:39:35 UTC 2009


Hi!

I have done some research about asset server. I used lates trunk from 
this morning.

Here are my findings:
1. CoreAssetCache's CacheBuckets configuration is not working properly. 
Cache's size is limited to 1024 buckets, because of bug or by design. So 
"default" configuration value 32768 - didn't never happen.
    See:  private void SetSize(int newSize) in Cache.cs
             lock (m_Index)
            {
                if (Count <= Size)
                    return;
                .....
             }
    During initialization phase, Count is 0 - so initial size value 1024 
is used. (And Count never can't grow up bigger than Size)

2. GlynnTucker cache is basically Hashtable that contains all assets  
they are never removed from cache unless assets is exlusively removed by 
calling Expire method. It definately can provide huge performance impact 
for short time - but eventually your server is going to run out of  memory.

3. To evaluate different cache's performance I first tried to do some 
testing in stand alone SIM. Unfortunately single client, just didn't 
provide enough caching to really to measure performance, so I adopted 
different strategy. I did write simple Window$ console application with 
4 different test cases.

Test Case 1 "EnumerateAllTest": Just add assets to cache by predefined 
order and then try to get them from cache in same order. (Basically 
caches were pretty much guranteed to forgot first few thousands assets.)
Test Case 2 "GetRandom":  Try to get random asset from cache, and if 
asset is not found, add it to there.
Test Case 3 "GetRandomMoreFrequentTest": Try to get random asset from 
cache, and if asset is not found, add it to there. However, this time 
there 1000 assets that are more likely asked than other assets (80% chance).
Test Case 4 "GetRandomMoreFrequentWithExpireTest": Same as Test Case 3 - 
except that there is 25% chance to remove (expire) random assets from 
cache for each item retrieve iteration. Remove assets didn't actually 
need to be in cache.

 From these test cases, case 4 is maybe most realistic. Assets are 
requested randomly, but some of assets are requested more often. And 
sometimes assets are also expired explicitely.

Test program did measure used time for each test case and cache hit rate 
(how frequently cache actually did return requested assets). I also did 
write two additional caches - Cenome Assets Cache (this is very basic 
memory cache coming from commercial database project that I am currently 
working on) and simple Dictionary based cache (to see difference between 
real caches and maximal possible performance). There was 100 000 
randomly generated "assets" with data length between 393 170 and 10 
bytes - total asset size 7 361 310 300 bytes.

Here are performance results:

TIME
                                      Test Case
                                                1                
2               3                        4
CoreAssetCache                      6.552s       33.446s     1m 
10.668s        1m 16.222s
GlynnTuckerAssetCache          0.359s       0.811s       
3.292s                7.691s
CenomeAssetsCache               0.156s       0.764s       
2.309s                4.165s
DictionaryAssets                      0.203s       0.468s       
2.231s                3.900s

HIT COUNT
                                      Test Case
                                                1                
2               3                        4
CoreAssetCache                      1.0%          1.0%         
55.1%               55.0%
GlynnTuckerAssetCache          100%         75.4%       95.1% 
               83.3%
CenomeAssetsCache               4.0%          5.9%         
81.0%                80.8%
DictionaryAssets                      100%         75.4%       
95.1%                83.3%

As you can see, CoreAssetCache is 15-20 times slower than more optimal 
solutions. And GlynnTucker assets cache hit rate is optimal - because it 
is storing all assets - and never forget them.

4. To find out why, CoreAssetsCache's performance is so poor compared to 
other caches, I did use JetBrain's dotTrace profiler. For profiling, I 
did lower assets count to 10000 and reduced iterations to lower 
(profiling is taking lot's of time) - so profiling measurements are not 
directly comparable with performance measurements.

Major cause for CoreAssetsCache bad performance was 
"OpenSim.Framework.Cache.Store(String, Object, Type, Object [])" methods 
line "if (m_Index.Contains(new CacheItemBase(index)))". About 75% of 
time in Test Case 4 was used in this line. m_index is 
List<CacheItemBase> object. Contains call is basically linear search 
algorithm - instead of Contains method, BinarySearch should have been used.

I thing that CoreAssetsCache class might be salvageable, but it really 
need some serious refactoring - like why there is two collection of keys 
m_Index and m_Loopup? It might be easier to either implement new cache 
class or maybe use CenomeCache as base of new implementation.

5. There is "some" weirdness in other parts of code:
- Cache class is also used directly in FriendsModule and 
LandManagementModule
- There is interface called: IAssetCache that is used in several places 
and modules, however just one Test class is implementing interface 
(TestAssetCache) (CoreAssetsCache, GlynnTuckerAssetCache and 
CenomeAssetsCache are implementing IImprovedAssetCache interface)

You can (hopefully) download test program from 
http://imazer.x10hosting.com/CacheTesting.zip
Please note CenomeAssetCache is not ready for production - it is missing 
thread safety. (And I don't have update rights to Open SIM's version 
control system.)
This was first day when I took serious look to Open SIMs code - so I 
might be wrong several things here...

- Imaze Rhiano

PS: It is possible that I could contribute licence to Cenome database 
for Open SIM project. Database is designed to store BLOB like objects 
with full transaction and threading support to single file. However - 
database is closed source and still under development. If closed source 
implementation is not acceptable - then alternative is B-tree variant 
implemation that I might be able to release to open source.



More information about the Opensim-dev mailing list