Is SendMessage really that bad?

Discussion in 'iOS Development' started by steddyman, Jan 2, 2010.

  1. steddyman

    steddyman

    Member

    Joined:
    Apr 10, 2009
    Messages:
    231
    I am thinking of using the NotificationCenter code off the Wiki:

    http://www.unifycommunity.com/wiki/index.php?title=NotificationCenter

    As far as simplicity of use and implementation for a message system between components, this seems unbeatable.

    Without the use of Generics, the only other code I have seen is this using Delegates:

    http://forum.unity3d.com/viewtopic.php?p=249862#249862

    However using that code requires considerably more implementation work and plumbing for every new message.

    I have seen multiple posts on the forums suggesting SendMessage is extremely slow but no information in the Documentation and no concrete examples of performance differences between SendMessage and direct calls.

    I do not want to implement public properties for calling components because during development I constantly delete and recreate objects and this mechanism is complex to manage.

    I want a notification system where the sender needs to know nothing about the receiver and this code seems perfect.

    Thanks
  2. steddyman

    steddyman

    Member

    Joined:
    Apr 10, 2009
    Messages:
    231
    Well, in the absence of any hard evidence on what percentage slower a SendMessage is compared to a direct call, I am going to go with the simpler option and use SendMessage.

    I will only ever have a single script assigned to each GameObject so the fact it will try to call it on each MonoBehaviour of a GameObject should not have a performance impact.

    BTW does SendMessage require Reflection since it is calling a function based on a string name?
  3. prime31

    prime31

    Member

    Joined:
    Oct 9, 2008
    Messages:
    6,424
    SendMessage more than likely uses Reflection, which is probably why it is so expensive. I made a very simple NotificationCenter that might suit your situation. It does the minimum amount of casting/unboxing/boxing and is super simple to add new event types. All you need to do is add a new enum. The post with the sample code and details is here:
    http://forum.unity3d.com/viewtopic.php?t=40311&start=15#249309
  4. steddyman

    steddyman

    Member

    Joined:
    Apr 10, 2009
    Messages:
    231
    Thanks uprise

    I've seen your other post which is what prompted me to post this one. You code isn't a million times for complex than the one on the wiki, but it is definitely more awkward to work with hence I'd prefer to use the Wiki one if possible.

    The one on the Wiki does need a few changes to work on the iPhone but I now have it working.

    Would love an answer from Unity on whether or not SendMessage is implemented via Reflection and if it does are the reflection calls cached or are they made every time?

    I noticed that the Penelope same is using SendMessage, so Unity must think its suitable for use on the iPhone.

    Thanks
  5. tomvds

    tomvds

    Member

    Joined:
    Oct 10, 2008
    Messages:
    1,024
    You should realize that "relatively expensive" is not always a problem. If you use a SendMessage every once in a blue moon to notify scripts of a certain collision for instance, it doesn't matter that SendMessage is more expensive than direct calls. However, if you program your game to have large numbers of SendMessage per frame, you are bound to run into problems on the iPhone.

    Optimization is not about avoiding expensive code. It's about avoiding expensive code where it matters.
  6. SteveB

    SteveB

    Member

    Joined:
    Jan 17, 2009
    Messages:
    990
    ^Exactly.

    No real difference than characters; sure skin deformation is a more expensive, so you simply reduce mesh complexity, bone count and weight influences. That and fewer characters on screen at any one time.

    Expensive sure but not to be avoided as Tom stated.
  7. steddyman

    steddyman

    Member

    Joined:
    Apr 10, 2009
    Messages:
    231
    Thanks Guys

    I do understand all this. My coding experience goes back to the C64 and TRS-80 so I understand about optimizing my code and the impact of small delays when executed multiple times.

    What I don't understand and would like to learn is how much slower is it. All i've seen so far is statements that it's much slower. Is it 10ms rather than 5ms on an iPhone 3G? Does it use reflection? If it does is it on every call.

    In order for us to make intelligent decisions around flexibility over performance we need to understand the specifics. Would really appreciate a comment from the Unity Dev's.

    Thanks
  8. SteveB

    SteveB

    Member

    Joined:
    Jan 17, 2009
    Messages:
    990
    Actually yea I don't believe we meant to state the obvious...

    ...so in all fairness I too would be curious what the difference is considering there are alternatives, albeit less 'simple'.

    :D

    -Steve
  9. prime31

    prime31

    Member

    Joined:
    Oct 9, 2008
    Messages:
    6,424
    If I was at my home computer I would throw together a quick test. Anyone care to see how long it takes to do n SendMessages vs n direct function calls? A few simple configurations would get a definitive answer quickly rather than speculating or waiting for a Unity dev.
  10. Dreamora

    Dreamora

    Member

    Joined:
    Apr 5, 2008
    Messages:
    26,586
    Yes and Yes


    If you have to care about performance, cache the target component(s) so you can call them directly
  11. steddyman

    steddyman

    Member

    Joined:
    Apr 10, 2009
    Messages:
    231
    Thanks Dreamora

    At least that is a confirmation of how it works. There is no tidy way to cache these things though.

    I want a broadcast / subscriber model and it is not possible to do that without using SendMessage unless you resort to hard coding messages and compiling them into other scripts.
  12. MatthewW

    MatthewW

    Member

    Joined:
    Nov 30, 2006
    Messages:
    1,260
    Actually, I don't think it uses reflection each call. They're doing internal caching via hashtables or something...
  13. steddyman

    steddyman

    Member

    Joined:
    Apr 10, 2009
    Messages:
    231
    Thanks for that.

    Again, would appreciate a post from a Unity internal dev team member on this one. I don't think anyone else could answer it for sure.

    If it does use Reflection, then shouldn't that mean the Asset Stripping feature which is a major benefit of the iPhone Advanced version cannot be used? It states clearly in the 1.51 manual that Asset Stripping it not safe even at the base level if Reflection is used. It makes no mention of SendMessage.
  14. bliprob

    bliprob

    Member

    Joined:
    May 13, 2007
    Messages:
    901
    You know, if you just made a test script that sent a bunch of messages and timed it, it would take less time than you've spent on this thread. In fact, I got so annoyed that I went and wrote your test for you. The results:

    Editor:

    Time for SendMessage 1000 times: 0.00137501955032349
    Time for direct functon call 1000 times: 0.000117003917694092

    iPhone, no stripping, "Slow and Safe" call optimization:

    Time for SendMessage 1000 times: 0.0327930450439453
    Time for direct functon call 1000 times: 0.00520801544189453

    iPhone, micro mscorlib, "Fast but no exceptions":

    Time for SendMessage 1000 times: 0.0356040000915527
    Time for direct functon call 1000 times: 0.00104284286499023


    There's your answers: (a) Direct function calls are an order of magnitude faster. (b) SendMessage doesn't use reflection. (b) Call optimizations only work on function calls (which is sort of obvious now that I'm typing it out).

    On the iPhone a thousand SendMessage() calls performed in a loop will take 1/30 of a second (so one SendMessage takes 0.0000033333 second), while a thousand function calls take 1/200 of a second.

    So -- like others already told you -- native function calls are faster, not so much faster that it really matters unless you use them near-constantly. So use the NotificationCenter script already.
  15. steddyman

    steddyman

    Member

    Joined:
    Apr 10, 2009
    Messages:
    231
    Hi bliprob

    Sorry if I annoyed you. I was simply asking for details from Unity devs who moderate these forums for support reasons how their code actually worked. Performance was my main interest, but we still don't know how it is implemented under the seams. I didn't think asking for clarity would have annoyed anyone.

    I didn't attempt to time this myself because I didn't understand what the impact of SendMessage would be on the timing. Many people have posted on this forum that a SendMessage would be received on the next Update cycle rather than the current, which makes timing it pointless. In fact if your frame rate is 30 frames per second no matter how many calls you push at the call it should complete them in 1/30th of a second (so long as its not a million). Even if its one. Also, by nature SendMessage must be asynchronous whereas a direct call will wait for a return.

    Thanks for going the extra mile to implement the code and time this. Given your results for SendMessage was 1/30th of a second suggests this was because of the fact it is sending Async calls into the next Frame update. If you send 1200 you will probably find it takes the same length of time.
  16. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Messages:
    25,579
    I haven't seen anyone post that SendMessage would be received on the next Update, and if they did, that's quite wrong, and doesn't even make any sense.

    When running benchmarks, I use a substantially large number of iterations and get the average of several runs, since I've found that execution times vary somewhat.

    So, on my (rather old) machine, a loop of 5000000 SendMessage calls, using an empty function, takes 9.872 seconds. A loop of 5000000 direct calls (using a cached GetComponent) takes .024 seconds. Therefore, direct calling seems to be about 400 times faster, although considering that the loop itself takes up some time, it's probably more than that.

    That is, of course, a highly artificial benchmark. In real-world situations, it still makes sense to use SendMessage if that suits your design, and occasional SendMessage calls won't cause any noticeable performance issues. But in a situation where a large numbers of calls is needed, then yes, direct calling would be much faster, assuming you're using a cached GetComponent and not using it repeatedly (which is probably at least as slow as SendMessage).

    --Eric
  17. steddyman

    steddyman

    Member

    Joined:
    Apr 10, 2009
    Messages:
    231
    Thanks Eric

    Wow, that sure is a big difference. With a performance difference like that it will definitely be worth the extra overhead of not using SendMessage for my message passing system (it uses lots of messages).

    I did a lot of searching and research on these forums before posting this. I found quite a few references to SendMessage being Async. It kind of makes senses given it isn't necessarily a single function call since it will call the named functioned on ALL MonoBehaviour scripts attached to a GO.

    I did a quick search, and here were just a couple of threads that mentioned that SendMessage is received by the GO on the next frame:

    http://forum.unity3d.com/viewtopic.php?t=27285&highlight=sendmessage
    http://forum.unity3d.com/viewtopic.php?t=19954&highlight=sendmessage

    Thanks
  18. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Messages:
    25,579
    Mistaken, I'm afraid; not sure where that idea came from. It's not like SendMessage is physically sending a message that actually travels to other components and takes time to arrive. All it does is go through the attached components, finds matches of the desired function, and executes them. This is very easy to verify:

    Code (csharp):
    1. function Start () {
    2.     SendMessage("Test");
    3.     print ("2");
    4.     yield;
    5.     print ("3");
    6. }
    7.  
    8. // The function below can be a separate script or not; doesn't make any difference
    9. function Test () {
    10.     print ("1");
    11. }
    If there was any sort of "delay to next frame", it would print 2, 1, 3, (or perhaps 2, 3, 1) but it doesn't; it prints 1, 2, 3. It would make some game logic very difficult and prone to breakage if there was any kind of async operation here. Hope this clears things up. :)

    --Eric
  19. steddyman

    steddyman

    Member

    Joined:
    Apr 10, 2009
    Messages:
    231
    It does and I appreciate you taking the time to explain that.

    I'm glad it works that way. It was hurting my head thinking about using it for sending collision messages. Now its is just the same as a function call.

    Thanks again
  20. bliprob

    bliprob

    Member

    Joined:
    May 13, 2007
    Messages:
    901
    A factor of 400 times is definitely not what I'm seeing. I re-ddi the tests (Unity iPhone 1.5.1) with 500,000 iterations, averaged over ten runs:

    Desktop SendMessage: .0565 average
    Desktop direct call: 0.0635 average

    iPhone SendMessage: 16.9 average
    iPhone direct calls: 0.529 average

    In my testing it's 9 times faster on the desktop, and 32 times faster on the iPhone. (It's possible the results are very different with Unity 2.6, but I'm using Unity iPhone almost exclusively, so this is all I tested.)

    After testing this yesterday I added the NotificationCenter to my project. By decoupling it simplifies my code. If I need to optimize, I can.
  21. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Messages:
    25,579
    Yeah, that was with the Unity 2.6.1 editor on my G5. With Unity iPhone 1.5.1, building to my iPod 2G, I get 11.20520 seconds with SendMessage and 500000 iterations (dropped from 5 million so it won't take so long), and .01510 seconds with direct calls, which is 742 times faster.... In the iPhone editor, I get .73935 seconds with SendMessage, and .00095 seconds with direct call; 778 times faster. Maybe my methodology is bad--I'm just using an empty function as the target, the idea being that I'm only timing the function calls and not what the function does--but that's pretty consistent given that the two environments are quite different.

    --Eric
  22. Neodrop

    Neodrop

    Member

    Joined:
    Oct 24, 2008
    Messages:
    1,342
    I have Event system for you (aka Antares Events Manager). My system is completely constructed on auto-generated Delegats (and Custom Delegats too) and five times faster than Messages.
    1 000 000 calls in my case: 0,14 seconds. About 7000 times per millisec.
    Messages: 0.7 seconds. About 1400 times per millisec.

    [​IMG]

    The system uses Generic classes which will be accessible in Unity iPhone 1.6 but I can fast correct it for 1.5.1

    Look at this topic (The fourth message from above) :
    http://forum.unity3d.com/viewtopic.php?t=34695&highlight=antares

    The description is a little obsolete. Since then I have strongly expanded a functional of my Events System.
    Sorry, but right now the new description has no English translation yet.

    Antares Events Manager is fast, flexible, user-friendly and stable code, which can work in any dotnet languages and even with non-monobeh classes.
    It is very convenient way for communications between C#, JS and Boo scripts.

    For reduction of size of the occupied memory and increase in speed of operation of the application, I often use it with the classes inherited from nothing or from UnityEngine.Object


    [​IMG]
  23. BogdanDude

    BogdanDude

    Member

    Joined:
    Jun 18, 2009
    Messages:
    74
    I'm not sure I got things right, so here's my scenario:

    I have 20 enemies active at a time.

    When hitting one, I have:
    Code (csharp):
    1. SendMessage("ApplyDamage",damage);
    And if I use a notification center, I'd have:
    Code (csharp):
    1. for (i=0;i<20;i++)
    2. {
    3. switch (enemytype)
    4. {
    5. case (typeA):
    6. {
    7. typeAenemy.ApplyDamage(damage);
    8. break;
    9. }
    10. case .....
    11. }
    12. }
    So, if on the iPhone the SendMessage is 19 times slower than direct calls, then would it still be recommended (faster) in my scenario?
  24. Neodrop

    Neodrop

    Member

    Joined:
    Oct 24, 2008
    Messages:
    1,342
    20 objects is not too many.
  25. steddyman

    steddyman

    Member

    Joined:
    Apr 10, 2009
    Messages:
    231
    That looks interesting Neodrop.

    Where does your information come from on Unity iPhone 1.6? I didn't know there were plans to implement .NET 2.0 into 1.6.

    Have you heard of any time frame for that?
  26. n0mad

    n0mad

    Member

    Joined:
    Jan 27, 2009
    Messages:
    3,731
    I once found an alternative to SendMessage ( this thread, bottom of page).

    But it is still 3 times slower than direct calling :/
  27. Neodrop

    Neodrop

    Member

    Joined:
    Oct 24, 2008
    Messages:
    1,342
    Hm. Sorry, this is closed info. I told too many now.
  28. imtrobin

    imtrobin

    Member

    Joined:
    Nov 30, 2009
    Messages:
    1,184
    You should test SendMessage against virtual functions. That is use of it, instead of creating interfaces for subclass to override.
  29. Overunity3d

    Overunity3d

    New Member

    Joined:
    Sep 5, 2010
    Messages:
    14
    Why not do the housekeeping of getting the calls of getcomponent up front in a loading page then the variables are setup for communication?
    Consume memory statically instead of memory and time dynamically....
  30. Souliloquy

    Souliloquy

    Member

    Joined:
    Jul 23, 2012
    Messages:
    2
  31. ImogenPoot

    ImogenPoot

    New Member

    Joined:
    Jul 2, 2012
    Messages:
    214
    To leave a note on the gravestone: C# events sure have its reason for existing, but the are to be taken with a grain of salt. You have to be extremely careful not to introduce memory leaks, which is particularly easy with events. There are tons of threads about this issue in various C# corners ^^. You could easily write your own, typesafe replacement of sendmessage which also caches all reflection data and thus is not noticable slower than the usual method call.

    What was said in the thread above, that SendMessage would compete with method call is highly questionable, unless Mono does some very aggressive optimizations. I rather believe what Eric said, that it is about 400 times slower, which is the usual overhead of most kinds of dynamic method invocation, not only SendMessage.
  32. JoeStrout

    JoeStrout

    Member

    Joined:
    Jan 14, 2011
    Messages:
    632
    I'm not sure I buy that memory leaks argument. Any message-passing system that doesn't crawl the object graph on every call is going to require some reference to the receivers. But if your objects are MonoBehaviours, you have a very convenient place to unregister for the event: the OnDestroy call. As long as you deregister at that point, you have no leaks. This seems like a small (and easy) price to pay for a strongly typed, fast, and built-in decoupling idiom.

    I've just spent most of the day developing my own message-passing system, which has some nifty refinements when it comes to scoping of messages (both into channels such as "Game" or "UnitTest", as well as by the scene graph). But compared to .NET events, it has some serious drawbacks too. I'm on the fence at the moment — I might throw that out and go with .NET events instead. With a bit of support code for finding the right publisher(s), it could be really nice.
  33. Noktai

    Noktai

    Member

    Joined:
    Feb 11, 2013
    Messages:
    9
    Has there been optimzations for SendMessage? Maybe I'm just testing it wrong, but I don't see a big impact in performance.

    I'm on a windows surface, so those numbers are quite high haha.
    But it doesn't seem nearly as slow as some people make it to be here.

    I was in the middle of writing my own messaging system, which uses reflection to look through all the class's methods, and stores them as a delegate for later use.
    I might still consider it because SendMessage only accepts 1 argument, but if SendMessage's performance has been improved I might just use that.
  34. Tepei

    Tepei

    Member

    Joined:
    Mar 29, 2014
    Messages:
    10
    Yes but it's possible to send a string and to extract from it more than one argument.

    Example :

    #pragma strict

    var stringer = "aabcd123dd2";
    var damagevalue = "0";
    private var damavalue = 0;
    function Start () {}

    function Update () {

    SendMessage ("ApplyDamage", stringer);
    }

    function ApplyDamage (damage : String) {
    damagevalue = damage.Substring(5,3);
    damavalue = float.Parse( damagevalue );

    Debug.Log(damavalue);
    }
  35. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Messages:
    25,579
    That's not really a good idea; it's far better just to use a custom class. For example, if you wanted to pass a string and an int, make a class that has a string and an int, and pass an instance of that class with the desired values.

    --Eric
  36. Tepei

    Tepei

    Member

    Joined:
    Mar 29, 2014
    Messages:
    10
    Oh thanks ! so i will do that !)
    But must i use again send message or direct call for class ?
    I try to send a class by message but i get unexpected token when i replace String for class in my function.
    And excuse me cause i'm a absolute beginner; must i use a public or static class or maybe a public static class ?
    Last edited: Sep 19, 2014
  37. Tepei

    Tepei

    Member

    Joined:
    Mar 29, 2014
    Messages:
    10
    Finally i try to not use SendMessage and no getcomponent.

    I just have to make a = float.Parse(collider.name). (with 15000 float.Parse by frame it begin to slow down a bit.)

    I Make a GameMaster that do a lot of static array.

    When any object start it make a new entry in the name array.

    Then every object change it's name for the number of the entry.

    [​IMG]

    Accesing this name i could change every var related to him that is stored in my gamemaster ..
    Do you thing it's good or bad ?
    Last edited: Sep 24, 2014
  38. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Messages:
    10,941
    Using sendmessage once per frame really can't slow down any game, it's just absorbed into background noise. The problem is when you start having a lot of them per frame. You can't do that on mobile and expect great performance. But one here and there never hurt anyone tbh.

    It's probably bad if you have a lot of different components on an object though.
    Tepei likes this.