{"action":"created","issue":{"url":"https://api.github.com/repos/bennidi/eventbus-performance/issues/1","repository_url":"https://api.github.com/repos/bennidi/eventbus-performance","labels_url":"https://api.github.com/repos/bennidi/eventbus-performance/issues/1/labels{/name}","comments_url":"https://api.github.com/repos/bennidi/eventbus-performance/issues/1/comments","events_url":"https://api.github.com/repos/bennidi/eventbus-performance/issues/1/events","html_url":"https://github.com/bennidi/eventbus-performance/issues/1","id":57326422,"number":1,"title":"Large amount of ram used by MBassador","user":{"login":"dorkbox","id":5301521,"avatar_url":"https://avatars.githubusercontent.com/u/5301521?v=3","gravatar_id":"","url":"https://api.github.com/users/dorkbox","html_url":"https://github.com/dorkbox","followers_url":"https://api.github.com/users/dorkbox/followers","following_url":"https://api.github.com/users/dorkbox/following{/other_user}","gists_url":"https://api.github.com/users/dorkbox/gists{/gist_id}","starred_url":"https://api.github.com/users/dorkbox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dorkbox/subscriptions","organizations_url":"https://api.github.com/users/dorkbox/orgs","repos_url":"https://api.github.com/users/dorkbox/repos","events_url":"https://api.github.com/users/dorkbox/events{/privacy}","received_events_url":"https://api.github.com/users/dorkbox/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":77,"created_at":"2015-02-11T15:00:18Z","updated_at":"2016-03-13T13:34:02Z","closed_at":"2016-03-12T17:43:45Z","body":"Here's some initial tests. I also included JVM memory usage, to help understand the data. I don't think I have the disruptor completely worked out, as it seems really, really slow. One thing I did notice is that the default LBQ setting on MBassador used up to 1 GB of ram. Changing it to have an LBQ of size 16 dropped it to about 512 MB without affecting too much. The disruptor with a ring buffer of size 16 uses ~62 MB. I suspect pooling objects would help.\r\n\r\n\r\n**Linked Blocking Queue (size:Integer.MAX_VALUE)**\r\n![LBQ-intmax-chart](https://cloud.githubusercontent.com/assets/5301521/6149125/d20f15ec-b206-11e4-9526-5b8460f9e72e.jpg)\r\n\r\n**Linked Blocking Queue (size:16)**\r\n![LBQ-16-chart](https://cloud.githubusercontent.com/assets/5301521/6149128/d750f3b8-b206-11e4-8ea1-09d9e4365c80.jpg)\r\n\r\n**Disruptor (2 worker) + ReflectASM**\r\n![Disruptor-2-worker-pool-reflectasm-chart](https://cloud.githubusercontent.com/assets/5301521/6149140/e7c2cc76-b206-11e4-9716-9f1b10095a24.jpg)\r\n"},"comment":{"url":"https://api.github.com/repos/bennidi/eventbus-performance/issues/comments/195958360","html_url":"https://github.com/bennidi/eventbus-performance/issues/1#issuecomment-195958360","issue_url":"https://api.github.com/repos/bennidi/eventbus-performance/issues/1","id":195958360,"user":{"login":"dorkbox","id":5301521,"avatar_url":"https://avatars.githubusercontent.com/u/5301521?v=3","gravatar_id":"","url":"https://api.github.com/users/dorkbox","html_url":"https://github.com/dorkbox","followers_url":"https://api.github.com/users/dorkbox/followers","following_url":"https://api.github.com/users/dorkbox/following{/other_user}","gists_url":"https://api.github.com/users/dorkbox/gists{/gist_id}","starred_url":"https://api.github.com/users/dorkbox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dorkbox/subscriptions","organizations_url":"https://api.github.com/users/dorkbox/orgs","repos_url":"https://api.github.com/users/dorkbox/repos","events_url":"https://api.github.com/users/dorkbox/events{/privacy}","received_events_url":"https://api.github.com/users/dorkbox/received_events","type":"User","site_admin":false},"created_at":"2016-03-13T13:34:02Z","updated_at":"2016-03-13T13:34:02Z","body":"@bennidi You're very welcome, and thank you for the mention. This has been an interesting *journey*, and I have learned an incredible amount about concurrent programming, what works and what doesn't. Also, I'm really happy with my results, and it *feels great* to claim <100ns per message dispatched.\r\n\r\nThe **major** performance contribution was applying the `single-writer-principle` (I recommend reading the this blog post for details http://mechanical-sympathy.blogspot.co.za/2011/09/single-writer-principle.html). \r\n\r\nThe other optimizations (in order of how much they enhanced the performance) were to remove as many branch conditions as possible -- which had the side affect of removing a bunch of features; to use faster collections (the Kryo [IdentitiyMap](https://github.com/EsotericSoftware/kryo/blob/master/src/com/esotericsoftware/kryo/util/IdentityMap.java) instead of HashMap); and to modify the use of your ConcurrentSet Iterators ([Strong](https://github.com/bennidi/mbassador/blob/master/src/main/java/net/engio/mbassy/common/StrongConcurrentSet.java#L21) and [Weak](https://github.com/bennidi/mbassador/blob/master/src/main/java/net/engio/mbassy/common/WeakConcurrentSet.java#L26)) to not generate objects - ([here](https://github.com/dorkbox/MessageBus/blob/master/src/dorkbox/messagebus/subscription/reflection/SubscriptionReflectionStrong.java#L95) and [here](https://github.com/dorkbox/MessageBus/blob/master/src/dorkbox/messagebus/subscription/reflection/SubscriptionReflectionWeak.java#L116)). Removing object generation was a goal of mine, and I'm not convinced that change had much of an impact on the performance... If the charts were a *straight line* it would be easier to measure.\r\n\r\n\r\nYou'll see that anywhere there is concurrent access to a collection, the `single-writer-principle` is applied -- and for some areas, it just wouldn't be easy to apply to MBassador without changing the architecture. I think the main area it could be applied (and this would be what my pull request would be) is to replace the re-entrant locks in the SubscriptionManager and HashMap with IdentityMap.\r\n\r\n> RE: Async dispatch\r\n\r\nThose graphs are a bit tricky to interpret for me as well. The *best* I can think of to explain the differences... Since MBassador queues all of the publications (which is what originally started me down this \"rabbit hole\") the tests finish running with nothing/very little actually getting published. The difference is that via the Disruptor, it's fast enough to be able to \"stay on top\" of processing the publications.\r\n\r\n\r\n> RE: The LMAX-Disruptor.\r\n\r\nYes - I was really, really struggling with the Disruptor - this was a year ago and so my memory is a little fuzzy on the details, so I will explain how I got it to work in *round 2*.  I don't know the exact problem a year ago, but I tried to modify the example and use \"it all at once\", and it failed to perform; and then again on my first \"retry\" a few months ago, I modified it all at once - and it failed to perform. My success came when I took a [performance test example](https://github.com/LMAX-Exchange/disruptor/blob/master/src/perftest/java/com/lmax/disruptor/workhandler/TwoToTwoWorkProcessorThroughputTest.java) and **very slowly** adapted it ([while benchmarking after each modification](https://github.com/dorkbox/Benchmarks/blob/master/src/dorkbox/benchmark/Test_Queue_Disruptor.java)) to my own use.  The best I can say, is that the Disruptor is *extremely sensitive* to all of it's parameters, and any changes made that differ from the examples have to be benchmarked to make sure those changes didn't break anything in the process."}}