Coffeehouse Thread

24 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

"Near C Performance" w/ TraceMonkey JavaScript Engine

Back to Forum: Coffeehouse
  • User profile image
    dcuccia

    Just saw this article on the TraceMonkey complier for FF 3.1, which allows Javascript language features to "achieve a speedup of 22x."

    Knee-jerk reactions:

    1. "Hey, no fair!"
    2. JSC and Volta just got more relevant for cross-platform RIAs
    Any thoughts?

  • User profile image
    Bass

    Webkit has also greatly improved their JavaScript performance lately with a new virtual machine. What would be interesting is if Microsoft made a way to "compile" .NET into JavaScript I think, that Volta sounds really cool. Or if there was a standard virtual machine bytecode language that JavaScript compiled down to, and the web site could send directly to the browser for execution. It'll happen probably.

  • User profile image
    Ion Todirel

    Bass said:
    Webkit has also greatly improved their JavaScript performance lately with a new virtual machine. What would be interesting is if Microsoft made a way to "compile" .NET into JavaScript I think, that Volta sounds really cool. Or if there was a standard virtual machine bytecode language that JavaScript compiled down to, and the web site could send directly to the browser for execution. It'll happen probably.
     "near native performance" I don't think it's that near as it sounds Smiley

  • User profile image
    evildictait​or

    "Near C performance" on carefully selected algorithms. This fails to take into account:

    a) The general cost of cleanup of variables (Garbage collection)
    b) The time cost of compilation (Just in time means that large javascript libraries will take seconds, not milliseconds out of your performance)
    c) The fact that javascript is both untyped and dynamic, meaning that large amounts of indirections nessisarilly occur which will prevent C-speed performance from ever being achievable with javascript
    d) In C, if you write to an array past memory, your program crashes or exposes horrific bugs in your app. Because javascript should never allow arbitrary pointer-based code to run on your system, it must nessisarilly include checks that C does not, and will therefore nessisarilly experience slow down on all array accesses for bounds checking - optimising some of these away is possible, but slows down the JIT.
    e) The fact that javascript generally outputs by modifying a HTML DOM tree, which is large, unwieldy and needs to be re-rendered and balanced after every mutation, which is expensive compared to C which typically only modifies in-memory objects for algorithms.

    So I'm going to cry FUD on the whole "nearly as fast as C" statement here.

  • User profile image
    littleguru

    evildictaitor said:
    "Near C performance" on carefully selected algorithms. This fails to take into account:

    a) The general cost of cleanup of variables (Garbage collection)
    b) The time cost of compilation (Just in time means that large javascript libraries will take seconds, not milliseconds out of your performance)
    c) The fact that javascript is both untyped and dynamic, meaning that large amounts of indirections nessisarilly occur which will prevent C-speed performance from ever being achievable with javascript
    d) In C, if you write to an array past memory, your program crashes or exposes horrific bugs in your app. Because javascript should never allow arbitrary pointer-based code to run on your system, it must nessisarilly include checks that C does not, and will therefore nessisarilly experience slow down on all array accesses for bounds checking - optimising some of these away is possible, but slows down the JIT.
    e) The fact that javascript generally outputs by modifying a HTML DOM tree, which is large, unwieldy and needs to be re-rendered and balanced after every mutation, which is expensive compared to C which typically only modifies in-memory objects for algorithms.

    So I'm going to cry FUD on the whole "nearly as fast as C" statement here.
    I'm also suspicious about this claim. It sounds good but they probably checked it only on selected algorithms. C# is also having near C performance if you carefully craft the algorithms. It might also be faster than C.

    Interesting to point out is that they say "unoptimized C" code, which might be reaaaaaaaaally slow.

    But cool to see that JavaScript gets more performance.

  • User profile image
    evildictait​or

    littleguru said:
    evildictaitor said:
    *snip*
    I'm also suspicious about this claim. It sounds good but they probably checked it only on selected algorithms. C# is also having near C performance if you carefully craft the algorithms. It might also be faster than C.

    Interesting to point out is that they say "unoptimized C" code, which might be reaaaaaaaaally slow.

    But cool to see that JavaScript gets more performance.
    "Faster than C?" I think you'll find that these are just compiler optimisations, not that the code is actually faster.

    For example, from (pseudo) Spec#:


    ensures result > 0
    ensures (p == q) implies result = 0
    public int Distance(Point! p, Point! q){
      return (int)Math.Sqrt( (p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y) );
    }

    requires p > 0
    ensures p == 0
    public int factorial(int p){
      if(p == 0) return 1;
      return p * factorial(p - 1);
    }


    public static void main(){
      int i = 7;

      // Spec# should be able to avoid the if( !(p > 0) ) throw new ArgumentException("p > 0 assertion failed"); step here
      // because it knows the parameter here. In C this would typically happen inside the function.
      Console.WriteLine( factorial( i ) );

      // Spec# can probably optimise away this entire function, since distance contains no side-effects and the first ensures
      // defines the result of the function.
      Console.WriteLine( distance(new Point(i, i), new Point(i, i) ));
    }

    Note that while this is "better than C performance", it's not better than an ideal C representation of the program:

    int factorial(int f){
      if(f == 0) return 1;
      return factorial(f - 1) * f;
    }
    void main(){
      printf("%d\n0", factorial(i));
    }

    But is better than a non-ideal version of the program:

    int factorial(int f){
      assert(f < 0);
      if(f == 0) return 1;
      return f * factorial(f - 1);
    }

    int distance(struct Point* p, struct Point* q){
      assert(p != NULL);
      assert(q != NULL);
      return (int)sqrt( (p->x - q->x) * (p->x - q->x) + (p->y - q->y) * (p->y - q->y) );
    }


    void main(){
      int i = 7;
      struct Point* a, b;

      printf("%d\n", factorial(i));

      a = malloc(sizeof(Point));
      b = malloc(sizeof(Point));

      a->x = i;
      a->y = i;
      b->x = i;
      b->y = i;

      printf("%d\n", distance(a, b));

      free(a);
      free(b);
    }




    Because C is so close to assembly language, it's fairly simple to deconstruct assembly language into C. Consequently any high-level language that runs "faster than C" is usually lying, because the high level language can be decomposed to assembler and recomposed to C, which by-defintion runs in the same speed. High level languages have lots of benefits, but when there are additional constraints such as garbage collection, C will nearly always win in a straight battle of which has the higher theoretical speed for an algorithm.

  • User profile image
    littleguru

    evildictaitor said:
    littleguru said:
    *snip*
    "Faster than C?" I think you'll find that these are just compiler optimisations, not that the code is actually faster.

    For example, from (pseudo) Spec#:


    ensures result > 0
    ensures (p == q) implies result = 0
    public int Distance(Point! p, Point! q){
      return (int)Math.Sqrt( (p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y) );
    }

    requires p > 0
    ensures p == 0
    public int factorial(int p){
      if(p == 0) return 1;
      return p * factorial(p - 1);
    }


    public static void main(){
      int i = 7;

      // Spec# should be able to avoid the if( !(p > 0) ) throw new ArgumentException("p > 0 assertion failed"); step here
      // because it knows the parameter here. In C this would typically happen inside the function.
      Console.WriteLine( factorial( i ) );

      // Spec# can probably optimise away this entire function, since distance contains no side-effects and the first ensures
      // defines the result of the function.
      Console.WriteLine( distance(new Point(i, i), new Point(i, i) ));
    }

    Note that while this is "better than C performance", it's not better than an ideal C representation of the program:

    int factorial(int f){
      if(f == 0) return 1;
      return factorial(f - 1) * f;
    }
    void main(){
      printf("%d\n0", factorial(i));
    }

    But is better than a non-ideal version of the program:

    int factorial(int f){
      assert(f < 0);
      if(f == 0) return 1;
      return f * factorial(f - 1);
    }

    int distance(struct Point* p, struct Point* q){
      assert(p != NULL);
      assert(q != NULL);
      return (int)sqrt( (p->x - q->x) * (p->x - q->x) + (p->y - q->y) * (p->y - q->y) );
    }


    void main(){
      int i = 7;
      struct Point* a, b;

      printf("%d\n", factorial(i));

      a = malloc(sizeof(Point));
      b = malloc(sizeof(Point));

      a->x = i;
      a->y = i;
      b->x = i;
      b->y = i;

      printf("%d\n", distance(a, b));

      free(a);
      free(b);
    }




    Because C is so close to assembly language, it's fairly simple to deconstruct assembly language into C. Consequently any high-level language that runs "faster than C" is usually lying, because the high level language can be decomposed to assembler and recomposed to C, which by-defintion runs in the same speed. High level languages have lots of benefits, but when there are additional constraints such as garbage collection, C will nearly always win in a straight battle of which has the higher theoretical speed for an algorithm.
    Isn't object construction faster in C# than in C++ (or I could construct something like this). I could write a sample that only does that in both languages and compare... hehe.

    If you want to proof something you can always find a sample where the one or the other platform|language wins and in the end, in real-life, it doesn't hold at all.

  • User profile image
    Sven Groot

    evildictaitor said:
    littleguru said:
    *snip*
    "Faster than C?" I think you'll find that these are just compiler optimisations, not that the code is actually faster.

    For example, from (pseudo) Spec#:


    ensures result > 0
    ensures (p == q) implies result = 0
    public int Distance(Point! p, Point! q){
      return (int)Math.Sqrt( (p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y) );
    }

    requires p > 0
    ensures p == 0
    public int factorial(int p){
      if(p == 0) return 1;
      return p * factorial(p - 1);
    }


    public static void main(){
      int i = 7;

      // Spec# should be able to avoid the if( !(p > 0) ) throw new ArgumentException("p > 0 assertion failed"); step here
      // because it knows the parameter here. In C this would typically happen inside the function.
      Console.WriteLine( factorial( i ) );

      // Spec# can probably optimise away this entire function, since distance contains no side-effects and the first ensures
      // defines the result of the function.
      Console.WriteLine( distance(new Point(i, i), new Point(i, i) ));
    }

    Note that while this is "better than C performance", it's not better than an ideal C representation of the program:

    int factorial(int f){
      if(f == 0) return 1;
      return factorial(f - 1) * f;
    }
    void main(){
      printf("%d\n0", factorial(i));
    }

    But is better than a non-ideal version of the program:

    int factorial(int f){
      assert(f < 0);
      if(f == 0) return 1;
      return f * factorial(f - 1);
    }

    int distance(struct Point* p, struct Point* q){
      assert(p != NULL);
      assert(q != NULL);
      return (int)sqrt( (p->x - q->x) * (p->x - q->x) + (p->y - q->y) * (p->y - q->y) );
    }


    void main(){
      int i = 7;
      struct Point* a, b;

      printf("%d\n", factorial(i));

      a = malloc(sizeof(Point));
      b = malloc(sizeof(Point));

      a->x = i;
      a->y = i;
      b->x = i;
      b->y = i;

      printf("%d\n", distance(a, b));

      free(a);
      free(b);
    }




    Because C is so close to assembly language, it's fairly simple to deconstruct assembly language into C. Consequently any high-level language that runs "faster than C" is usually lying, because the high level language can be decomposed to assembler and recomposed to C, which by-defintion runs in the same speed. High level languages have lots of benefits, but when there are additional constraints such as garbage collection, C will nearly always win in a straight battle of which has the higher theoretical speed for an algorithm.
    Faster than C?" I think you'll find that these are just compiler optimisations, not that the code is actually faster.

    If the C# compiler (or JIT compiler) produces faster assembly code than the C compiler for the same algorithm, then in my opinion that means C# is faster than C for that scenario. That you could write a better algorithm in C with a lot of effort is irrelevant in the real world.

  • User profile image
    evildictait​or

    littleguru said:
    evildictaitor said:
    *snip*
    Isn't object construction faster in C# than in C++ (or I could construct something like this). I could write a sample that only does that in both languages and compare... hehe.

    If you want to proof something you can always find a sample where the one or the other platform|language wins and in the end, in real-life, it doesn't hold at all.
    With the 'new" keyword, almost certainly. With RAII stack initialization, probably not

    // C++
    void main(){
      Point* p = new Point(4,4);
      delete p;
    }

    pseudo-turns into:
      1. get me 8 bytes of data on the heap (a bit expensive, but not hugely)
      2. call the constructor for point  (relatively cheap)
      3. call the destructor of point (relatively cheap)
      3. free the data (almost no cost)

    Total cost: some.

    // C++
    void main(){
      Point p = Point(4,4);
    }

    pseudo-turns into:
      1. add 8 to ESP (almost free)
      2. call the constructor for point (relatively cheap)
      3. call the destructor for point (relatively cheap)

    Total cost: very little.

    // C#:

    void main(){
      // let's pretend Point is a class not a struct-type for comparison
      Point p = new Point(4,4);
    }

    pseudo-turns into:
      1. call GC::allocate(8);  (relatively cheap)
      2. expand the heap if necessary (expensive - requires a full generational collection)
      3. register the object in the GC (relatively cheap)
      4. call the constructor for point (relatively cheap)
      5. Fall off the end of the program. Call destructors for everything (relatively cheap)

    Total cost: a bit.

  • User profile image
    littleguru

    evildictaitor said:
    littleguru said:
    *snip*
    With the 'new" keyword, almost certainly. With RAII stack initialization, probably not

    // C++
    void main(){
      Point* p = new Point(4,4);
      delete p;
    }

    pseudo-turns into:
      1. get me 8 bytes of data on the heap (a bit expensive, but not hugely)
      2. call the constructor for point  (relatively cheap)
      3. call the destructor of point (relatively cheap)
      3. free the data (almost no cost)

    Total cost: some.

    // C++
    void main(){
      Point p = Point(4,4);
    }

    pseudo-turns into:
      1. add 8 to ESP (almost free)
      2. call the constructor for point (relatively cheap)
      3. call the destructor for point (relatively cheap)

    Total cost: very little.

    // C#:

    void main(){
      // let's pretend Point is a class not a struct-type for comparison
      Point p = new Point(4,4);
    }

    pseudo-turns into:
      1. call GC::allocate(8);  (relatively cheap)
      2. expand the heap if necessary (expensive - requires a full generational collection)
      3. register the object in the GC (relatively cheap)
      4. call the constructor for point (relatively cheap)
      5. Fall off the end of the program. Call destructors for everything (relatively cheap)

    Total cost: a bit.
    Which proofs my point that saying "something is faster than something else" doesn't really have a point. You had now 3 samples where I could pick a pair to say C# is faster or pick another pair where I would say C++ is faster.

  • User profile image
    evildictait​or

    Sven Groot said:
    evildictaitor said:
    *snip*

    If the C# compiler (or JIT compiler) produces faster assembly code than the C compiler for the same algorithm, then in my opinion that means C# is faster than C for that scenario. That you could write a better algorithm in C with a lot of effort is irrelevant in the real world.
    That definition of speed relies too heavilly on the competence of the programmer.

    It's like saying that my new hypothetical language is much better than C because it uses quicksort, whereas some hypothetical C programmer uses bubblesort. Since my implementation is better, my language is faster at sorting an array.

  • User profile image
    Cannot​Resolve​Symbol

    littleguru said:
    evildictaitor said:
    *snip*
    Isn't object construction faster in C# than in C++ (or I could construct something like this). I could write a sample that only does that in both languages and compare... hehe.

    If you want to proof something you can always find a sample where the one or the other platform|language wins and in the end, in real-life, it doesn't hold at all.
    C++ != C.

    C has no concept of object construction, therefore object construction cannot be faster in C# than in C.  The closest equivalent to object construction in C is malloc(int size); which is the operating system's memory allocation routine:  C# has to call it in the process of allocating memory for an object on the heap.

  • User profile image
    littleguru

    CannotResolveSymbol said:
    littleguru said:
    *snip*
    C++ != C.

    C has no concept of object construction, therefore object construction cannot be faster in C# than in C.  The closest equivalent to object construction in C is malloc(int size); which is the operating system's memory allocation routine:  C# has to call it in the process of allocating memory for an object on the heap.

    That's why I said C++... AFAIK the new keyword in C++ invokes only a method that finds and allocates space (runs the constructor) and returns a pointer to that to me. But you are right: C++ adds stuff to C and that's why I compared C++ with C#.

  • User profile image
    Sven Groot

    evildictaitor said:
    Sven Groot said:
    *snip*
    That definition of speed relies too heavilly on the competence of the programmer.

    It's like saying that my new hypothetical language is much better than C because it uses quicksort, whereas some hypothetical C programmer uses bubblesort. Since my implementation is better, my language is faster at sorting an array.
    No, you've got it the wrong way around. Your definition of speed relies on the competence of the programmer.

    What I'm saying is, you write the same algorithm in both languages. So you use pretty much the same code both in C and in C#. If you write Bubblesort in C# and C and the C# version is faster, then I say C# is faster for Bubblesort, even though you could write a better sorting algorithm in C.

    In many cases, in order to beat the optimizer of some other language, you would have to write extremely complex C code. That requires a level of skill that most real-world C programmers simply don't have.

    And sometimes it can't be done at all. The Intel Fortran compiler is very aggressive in its use of vectorization and parallelization of loop constructs. In C it's nearly impossible (not completely impossible though) for the compiler to do the same thing because of all the invariants that become hard to prove in the presence of C-style pointers. In the Intel C compiler, you would need a lot of compiler directives to get it to produce the same assembly code as the Fortran compiler. With a compiler like MS Visual C++, it nearly never uses vector instructions and the only way to get it on par with the Intel Fortran compiler is using inline assembly and writing the vector instructions yourself.

  • User profile image
    evildictait​or

    CannotResolveSymbol said:
    littleguru said:
    *snip*
    C++ != C.

    C has no concept of object construction, therefore object construction cannot be faster in C# than in C.  The closest equivalent to object construction in C is malloc(int size); which is the operating system's memory allocation routine:  C# has to call it in the process of allocating memory for an object on the heap.
    I don't want to a pedant, but malloc is a library function (sbrk is the OS version and is limited to whole pages).

    For double-pedantry, C# doesn't use malloc because the GC uses it's own heap, roughly of the sort:

    class GCHeap {
    public:
      unsigned char* base, current;
      size_t capacity;

      void* allocate(size_t s){
        if(current - base > capacity) { fullCollect(); expandHeap(); }
        void* next = current;
        current += size;
        return next;
      }
    }

    Which is rather cheap to perform (amortized O(1) time). The rationale here is to avoid memory fragmentation.

  • User profile image
    evildictait​or

    Sven Groot said:
    evildictaitor said:
    *snip*
    No, you've got it the wrong way around. Your definition of speed relies on the competence of the programmer.

    What I'm saying is, you write the same algorithm in both languages. So you use pretty much the same code both in C and in C#. If you write Bubblesort in C# and C and the C# version is faster, then I say C# is faster for Bubblesort, even though you could write a better sorting algorithm in C.

    In many cases, in order to beat the optimizer of some other language, you would have to write extremely complex C code. That requires a level of skill that most real-world C programmers simply don't have.

    And sometimes it can't be done at all. The Intel Fortran compiler is very aggressive in its use of vectorization and parallelization of loop constructs. In C it's nearly impossible (not completely impossible though) for the compiler to do the same thing because of all the invariants that become hard to prove in the presence of C-style pointers. In the Intel C compiler, you would need a lot of compiler directives to get it to produce the same assembly code as the Fortran compiler. With a compiler like MS Visual C++, it nearly never uses vector instructions and the only way to get it on par with the Intel Fortran compiler is using inline assembly and writing the vector instructions yourself.
    I'm happy to concede that a fortran program could achieve better than C performance. I'm going to be uneasy with C# getting better than C performance without using clever optimisations such as those found in Spec# (where I'll concede that this may be possible for normal programs). If a paper concluded this I would look rather carefully at the graphs and code to make sure they weren't cherry-picking examples . But for javascript? No. You've got to be having a laugh. Javascript is interpreted at runtime, dynamic, operates on a DOM which is graphically rendered, is not pointer based and is fully garbage collected. There is no hope in hell that it will ever be in the same league as C for speed.

  • User profile image
    littleguru

    evildictaitor said:
    Sven Groot said:
    *snip*
    I'm happy to concede that a fortran program could achieve better than C performance. I'm going to be uneasy with C# getting better than C performance without using clever optimisations such as those found in Spec# (where I'll concede that this may be possible for normal programs). If a paper concluded this I would look rather carefully at the graphs and code to make sure they weren't cherry-picking examples . But for javascript? No. You've got to be having a laugh. Javascript is interpreted at runtime, dynamic, operates on a DOM which is graphically rendered, is not pointer based and is fully garbage collected. There is no hope in hell that it will ever be in the same league as C for speed.

    The Firefox addition here compiles the JavaScript and stores it for later use. That's why they get the speed improvements. It's like ASP.NET's compiliation and storing for future requests - but on the client side.

    I'm also rather suspicious when I get these kind of bold statements. Even a lot of the scientific papers say something that is tailored to their set of test data and doesn't expand to the real world... and if I read something like this on a website my suspicious alarm bell rings like crazy.

  • User profile image
    Cannot​Resolve​Symbol

    littleguru said:
    evildictaitor said:
    *snip*

    The Firefox addition here compiles the JavaScript and stores it for later use. That's why they get the speed improvements. It's like ASP.NET's compiliation and storing for future requests - but on the client side.

    I'm also rather suspicious when I get these kind of bold statements. Even a lot of the scientific papers say something that is tailored to their set of test data and doesn't expand to the real world... and if I read something like this on a website my suspicious alarm bell rings like crazy.

    In the real world, you will see a performance boost.  Maybe not as dramatic as the 40x increase in certain benchmarks, but once a couple of performance regressions are worked out, Tracemonkey will be as fast or faster for any given script than the non-JIT Javascript interpreter.  And it should provide real-world performance gains, just like the .Net JIT compiler or the Java JIT compiler do:  it's more or less exactly the same concept.

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.