Announcement

Collapse
No announcement yet.

Mono 2.11 Release Brings Many Changes

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #51
    Originally posted by Ansla View Post
    Well, I did some micro-benchmarks with the corner-case suggested by ciplogic and this are the results:
    (...)
    Now, the obvious result is that Java is really slow! No excuses like long time spent unpacking archives or other bullshit, both the Icedtea and gcj implementations of Java are plain ridiculously slow. Mono actually does a decent job at this being faster then C++ with boost::shared_ptr, but still it doesn't justify switching to Mono if C++11 std::shared_pointer or boehm-gc are valid alternatives.( ...)
    Just as a reminder: C++ was the slowest, with no bullshit like "unpacking archives" or "I wanted to see just how much overhead copying the smart pointer could have" Wish to you a great time!

    Comment


    • #52
      LOL, when it's the only one being misused, yes

      Comment


      • #53
        Originally posted by Ansla View Post
        LOL, when it's the only one being misused, yes
        If you mean that C++ is misused by using smartpointers, I fully agree ( const & misses the point of using smartpointers in first place!), One platform (the VM) would have reference tracking for free, when other (native C++), will be an expensive feature, visibly slower than C#/Java.
        You can test other claims too, like:
        - new in C++ is much slower than new in C# (at least with generational collector, so add sgen to Mono's command line)/Java,
        - arrays in C#/Java (which are the closes equivalent with std::vector (as you cannot do pointer arithmetic, and you can also iterate over them) are in general faster than their C++ equivalent (on medium sized programs), because C#/Java have a bound's checking removal algorithms for these structures. You may also try if Java specializes OOP calls (using Polymorphic Inline Caching), making working with OOP a bliss
        - just upgrading Mono/JVM you can have faster programs with no change on your side (as Java VM or Mono's VM add optimizations, your applications will get them for free, but static compiled programs would not). You may try Jake2 game engine, and try the equivalent Quake2 demo, and tell me which is faster, as for my machine, Quake2/Java is faster than Quake2
        At the end, one very last cool thing Java/.Net world has, and C++ have harder times: to work with multiple (good) languages in parts of project and don't have "Invalid Read Address at 0x0ffaas5dda". I recommend to Kotlin (http://confluence.jetbrains.net/disp...etting+Started) which is Java based but brings some runtime warranties and is really nice to code in.

        Comment


        • #54
          Reddit-C++ page have a link one week ago, that states the same. And gave numbers how to improve 3x the reference counting, by removing the thread-save code.

          Comment


          • #55
            Originally posted by ciplogic View Post
            If you mean that C++ is misused by using smartpointers, I fully agree ( const & misses the point of using smartpointers in first place!), One platform (the VM) would have reference tracking for free, when other (native C++), will be an expensive feature, visibly slower than C#/Java.
            The misuse is not using smart pointers in the first place, but not passing them as const reference on the function call. Because if the function called is only using the pointer for the duration of its life time, not taking ownership by storing a copy of the pointer at some global level why increment the usage counter? Lets say your function actually does store it for later reference, then the code would look like this:
            Code:
            void ProcessItem(const std::shared_ptr<Item> &item) {
                someOtherSmartPointer = item;
            }
            This code will work as the assignment operator for shared_ptr (both the C++11 version and the boost version) take a const reference as parameter. So passing the smart pointer as value instead of reference is a misuse, especially because it can be passed around for many times before some function actually stores it for later use (or maybe it won't be stored at all).

            Originally posted by ciplogic View Post
            You can test other claims too, like:
            - new in C++ is much slower than new in C# (at least with generational collector, so add sgen to Mono's command line)/Java,
            That depends a lot on the malloc implementation wrapped around by C++ new. And also the average C#/Java program will do a lot more dynamic memory allocations then a C++ one because in C++ it's possible to place a temporary instance of a class on the stack, with C#/Java you can only store on the stack primitive types, any class has to be dynamically allocated.

            Originally posted by ciplogic View Post
            - arrays in C#/Java (which are the closes equivalent with std::vector (as you cannot do pointer arithmetic, and you can also iterate over them) are in general faster than their C++ equivalent (on medium sized programs), because C#/Java have a bound's checking removal algorithms for these structures. You may also try if Java specializes OOP calls (using Polymorphic Inline Caching), making working with OOP a bliss
            But an array in C#/Java can not be resized, and the main reason for using C++ std::vector is it's ability to resize at runtime, so they are not at all equivalent

            Originally posted by ciplogic View Post
            - just upgrading Mono/JVM you can have faster programs with no change on your side (as Java VM or Mono's VM add optimizations, your applications will get them for free, but static compiled programs would not).
            True, with C++ you only benefit from optimizations in the standard library without rebuilding the program, so it's a good reason for the big bad corporations that only release binary blobs, but you're talking to a Gentoo user here who is not scared of an `emerge -e world` after upgrading the toolchain

            Originally posted by ciplogic View Post
            You may try Jake2 game engine, and try the equivalent Quake2 demo, and tell me which is faster, as for my machine, Quake2/Java is faster than Quake2
            I am not familiar with Jake2, so I can only speculate on the possible reasons for that, ranging from Jake2 taking advantage of some newer features that were not available 15 years ago when the original Quake2 was written (like multithreading or maybe even newer OpenGL features) to some incompatibilities of Quake2 with newer OS versions, for example Diablo 2 runs like crap on Windows Vista or newer and it's only 12 years old.

            Originally posted by ciplogic View Post
            At the end, one very last cool thing Java/.Net world has, and C++ have harder times: to work with multiple (good) languages in parts of project and don't have "Invalid Read Address at 0x0ffaas5dda". I recommend to Kotlin (http://confluence.jetbrains.net/disp...etting+Started) which is Java based but brings some runtime warranties and is really nice to code in.
            So Kotlin tries to bring in features from C# and C++ while maintaining compatibility with JVM?

            Comment


            • #56
              Originally posted by ciplogic View Post
              Reddit-C++ page have a link one week ago, that states the same. And gave numbers how to improve 3x the reference counting, by removing the thread-save code.
              Well, their code is bogus, they increment/decrement the pointer to the counter, not the value itself. And you can only use their hack when you know multiple threads will never share a pointer, it's a lot better to make sure you only make a copy of the smart pointer when actually required to. In a multi threaded application there should be limited number of functions that are invoked on a different thread, and those function would take the smart pointer as value, while the rest of the functions as const reference.

              Comment


              • #57
                Originally posted by Ansla View Post
                The misuse is not using smart pointers in the first place, but not passing them as const reference on the function call. Because if the function called is only using the pointer for the duration of its life time, not taking ownership by storing a copy of the pointer at some global level why increment the usage counter? Lets say your function actually does store it for later reference, then the code would look like this:
                Code:
                void ProcessItem(const std::shared_ptr<Item> &item) {
                    someOtherSmartPointer = item;
                }
                This code will work as the assignment operator for shared_ptr (both the C++11 version and the boost version) take a const reference as parameter. So passing the smart pointer as value instead of reference is a misuse, especially because it can be passed around for many times before some function actually stores it for later use (or maybe it won't be stored at all).
                If you use const & instead of raw pointer is really the same, and it miss the point of shared_ptr. This is why I told that is miss the point of shared pointer. Also having to enable a feature with performance implications means, so you use just minimally, means that users have to get extra thought if they want to use a feature or not, and they may not use it. And in Java you may get the performance right, and having the feature, when in C++ you may not have it, either the feature or the performance.

                Originally posted by Ansla View Post
                That depends a lot on the malloc implementation wrapped around by C++ new. And also the average C#/Java program will do a lot more dynamic memory allocations then a C++ one because in C++ it's possible to place a temporary instance of a class on the stack, with C#/Java you can only store on the stack primitive types, any class has to be dynamically allocated.
                I'm talking about default implementation/featureset. And if you use the same parameter for Java about Escape Analysis, it will convert heap allocations as stack allocations (as long the JIT can prove them safe). C# have "struct" keyword that put data on a stack, so there is nothing to complain on C# too.


                Originally posted by Ansla View Post
                But an array in C#/Java can not be resized, and the main reason for using C++ std::vector is it's ability to resize at runtime, so they are not at all equivalent
                Yet, they are not equivalent for other reasons too: arrays are allocated always on heap on VM languages too, but are closer equivalents than the Generic collections (at least on Java, as you noticed it, but also in C#, as the iteration will do every time a virtual call, as collections have to implement IEnumerable<T>)


                Originally posted by Ansla View Post
                True, with C++ you only benefit from optimizations in the standard library without rebuilding the program, so it's a good reason for the big bad corporations that only release binary blobs, but you're talking to a Gentoo user here who is not scared of an `emerge -e world` after upgrading the toolchain
                I think about the most users, they update the runtime when they update the OS/distribution. It seem to me you're not a Gentoo emerge guy, but even you would be one, I can say to you that Java was many times on the top of fast code, before GCC would catch up.
                Originally posted by Ansla View Post
                I am not familiar with Jake2, so I can only speculate on the possible reasons for that, ranging from Jake2 taking advantage of some newer features that were not available 15 years ago when the original Quake2 was written (like multithreading or maybe even newer OpenGL features) to some incompatibilities of Quake2 with newer OS versions, for example Diablo 2 runs like crap on Windows Vista or newer and it's only 12 years old.
                Jake2 is not faster as of OpenGL rewrite, but it would make sense even it would happen for this reason, but also because Java code can be sometimes optimized more today that a lot of C pointers code may be.

                Originally posted by Ansla View Post
                So Kotlin tries to bring in features from C# and C++ while maintaining compatibility with JVM?
                It brings (maybe) some features of C#, but most likely the source was Scala and other JVM languages, but I did not see any C++, the single reference in their FAQ page is:
                Consider, for instance, the chaos that existed in C++ with the wide variety of different 'custom' types created to hold booleans before the language designers finally added a standard 'bool' type to the language in an attempt to control the chaos.

                Comment


                • #58
                  Originally posted by Ansla View Post
                  The misuse is not using smart pointers in the first place, but not passing them as const reference on the function call. Because if the function called is only using the pointer for the duration of its life time, not taking ownership by storing a copy of the pointer at some global level why increment the usage counter? Lets say your function actually does store it for later reference, then the code would look like this:
                  Code:
                  void ProcessItem(const std::shared_ptr<Item> &item) {
                      someOtherSmartPointer = item;
                  }
                  This code will work as the assignment operator for shared_ptr (both the C++11 version and the boost version) take a const reference as parameter. So passing the smart pointer as value instead of reference is a misuse, especially because it can be passed around for many times before some function actually stores it for later use (or maybe it won't be stored at all).
                  Source
                  :
                  Code:
                  std::shared_ptr<std::string> previous_message;
                  
                  void send_message(const std::shared_ptr<std::string> &msg)
                  {
                      previous_message = 0;
                      std::cout << *msg << std::endl;
                      previous_message = msg;
                  }
                  (...)
                  send_message(std::shared_ptr<std::string>(new std::string("Hi")));
                  send_message(previous_message);
                  This would crash! I'm not saying that in places where you "obviously know" that the shared pointer cannot be null, to not use the const& construct, but you are basically on your own when you work with const references! So be aware, and use the principle: "the root of all evil is premature optimization".

                  Comment


                  • #59
                    Originally posted by ciplogic View Post
                    If you use const & instead of raw pointer is really the same, and it miss the point of shared_ptr.
                    Not at all, the const reference to a shared_ptr is all you need in order to increment the usage count of the existing shared_ptr. While having only a raw pointer you could only create a shared_ptr with a distinct counter and the original shared_ptr would free the pointer making your band new shared_ptr hold a dangling pointer.

                    Code:
                    #include <memory>
                    #include <iostream>
                    
                    std::shared_ptr<int> x;
                    std::shared_ptr<int> y;
                    
                    void updatex(const std::shared_ptr<int> &newX) {
                            x = newX;
                    }
                    
                    void updatey(int *newY) {
                            y = std::shared_ptr<int>(newY);
                    }
                    
                    int main() {
                            {
                                    std::shared_ptr<int> tmpx(new int(1));
                                    std::shared_ptr<int> tmpy(new int(2));
                                    updatex(tmpx);
                                    updatey(tmpy.get());
                                    std::cout << "tmpx=" << *tmpx << std::endl;
                                    std::cout << "tmpy=" << *tmpy << std::endl;
                            }
                            std::cout << "x=" << *x << std::endl;
                            std::cout << "y=" << *y << std::endl;
                    
                            return 0;
                    }
                    I was hoping for a crash, but I wasn't so lucky But running it with valgrind I got:
                    Code:
                    tmp=1
                    tmp2=2
                    x=1
                    ==32677== Invalid read of size 4
                    ==32677==    at 0x401215: main (in /home/andrei/Projects/smart_pointers/a.out)
                    ==32677==  Address 0x59790f0 is 0 bytes inside a block of size 4 free'd
                    ==32677==    at 0x4C28A5E: operator delete(void*) (vg_replace_malloc.c:387)
                    ==32677==    by 0x401330: main (in /home/andrei/Projects/smart_pointers/a.out)
                    ==32677== 
                    y=2
                    ==32677== Invalid free() / delete / delete[]
                    ==32677==    at 0x4C28A5E: operator delete(void*) (vg_replace_malloc.c:387)
                    ==32677==    by 0x401578: std::shared_ptr<int>::~shared_ptr() (in /home/andrei/Projects/smart_pointers/a.out)
                    ==32677==    by 0x560D870: exit (in /lib64/libc-2.13.so)
                    ==32677==    by 0x55F50A3: (below main) (in /lib64/libc-2.13.so)
                    ==32677==  Address 0x59790f0 is 0 bytes inside a block of size 4 free'd
                    ==32677==    at 0x4C28A5E: operator delete(void*) (vg_replace_malloc.c:387)
                    ==32677==    by 0x401330: main (in /home/andrei/Projects/smart_pointers/a.out)
                    So not only y holds a dangling pointer that might point to a random value, but it will also try to free the pointer a second time! While x correctly took over ownership from tmpx.

                    Originally posted by ciplogic View Post
                    I think about the most users, they update the runtime when they update the OS/distribution. It seem to me you're not a Gentoo emerge guy, but even you would be one, I can say to you that Java was many times on the top of fast code, before GCC would catch up.
                    I probably think in "proprietary world" (Windows/MacOS X) terms, where you have lots of 3rdParty apps installed that will not be updated together with the OS. But for a regular Linux distribution an OS update would also bring all the apps rebuilt with the new toolchain.

                    Originally posted by ciplogic View Post
                    Jake2 is not faster as of OpenGL rewrite, but it would make sense even it would happen for this reason, but also because Java code can be sometimes optimized more today that a lot of C pointers code may be.
                    Again, if your comparing a C binary from 15 years ago with a Java program running on a recent version of JRE, Java will have an advantage. As you said above, the Java program will take advantage of the new JVM while the C blob is forever stuck in 1997. And I'm sure the Java code being more recent also helps, I doubt if Jake2 was written in 1997 (using JDK 1.0 or 1.1 whatever was the current version at that time!!!), it would perform the same.

                    Originally posted by ciplogic View Post
                    It brings (maybe) some features of C#, but most likely the source was Scala and other JVM languages, but I did not see any C++, the single reference in their FAQ page is:
                    It might be a feature of Scala, I don't think i even heard of that language before, but it's also in C++... "Operator overloading" on this page http://confluence.jetbrains.net/disp...arison+to+Java

                    Comment


                    • #60
                      Originally posted by Ansla View Post
                      Not at all, the const reference to a shared_ptr is all you need in order to increment the usage count of the existing shared_ptr. While having only a raw pointer you could only create a shared_ptr with a distinct counter and the original shared_ptr would free the pointer making your band new shared_ptr hold a dangling pointer.

                      Code:
                      (...)
                      You misunderstood the problem,
                      The problem is when you have side effects, and try this:
                      Code:
                      #include <memory>
                      #include <iostream>
                      
                      std::shared_ptr<int> x;
                      void resetX() {
                        x = std::shared_ptr<int> (0);
                      }
                      
                      void updatex(const std::shared_ptr<int> &newX) {
                      	resetX(); //code have side effects that do set the 
                      //reference count of X to zero
                             //the referene to newX is wrong
                              std::cout << "x=" << newX << std::endl;
                      }
                      void updatex_safe_and_slow(std::shared_ptr<int> newX) {
                      	resetX(); //code have side effects that do set the 
                      //reference count of X to zero, but you have still a safe copy
                              std::cout << "x=" << newX << std::endl;
                      }
                      
                      
                      void main() {
                             {
                      x =std::shared_ptr<int> (new int(1));
                                      updatex_safe_and_slow(x);
                                      
                              }
                        
                             {
                      x =std::shared_ptr<int> (new int(1));
                                      updatex(x);
                                      
                              }
                      }
                      I cannot compile on Gcc now, may you try to reproduce if you have a crash? (I think that you should, and I'm not talking about dangling pointers, which is fun to have in your application )

                      Comment

                      Working...
                      X