Hacker News new | past | comments | ask | show | jobs | submit login

Thank you. I ran both through lldb to see why luajit was faster and was confused how luajit was faster despite doing quite a bit more work:

    luajit loop:

    0x12a0effe0: movl   %eax, %ebp
    0x12a0effe2: movl   %ebp, %edi
    0x12a0effe4: callq  *%rbx
    0x12a0effe6: movsd  0x8(%rsp), %xmm0          ; xmm0 = mem[0],zero
    0x12a0effec: xorps  %xmm7, %xmm7
    0x12a0effef: cvtsi2sdl %eax, %xmm7
    0x12a0efff3: ucomisd %xmm7, %xmm0
    0x12a0efff7: ja     0x12a0effe0

    c_hello loop:

    0x100000ea0 <+80>:  movl   %ebx, %edi
    0x100000ea2 <+82>:  callq  0x100000ee6               ; symbol stub for: plusone
    0x100000ea7 <+87>:  movl   %eax, %ebx
    0x100000ea9 <+89>:  cmpl   %r14d, %ebx
    0x100000eac <+92>:  jl     0x100000ea0               ; <+80>
    
    
    0x100000ee6 <+0>: jmpq   *0x134(%rip)

I'm still a bit surprised that that extra jumpq is more expensive than all those extra instructions luajit is executing.

EDIT: For those curious, Lua handles all numbers as floating-point; there are no ints in Lua. That's what all the extra instructions are for. Interestingly it looks like LuaJIT is storing the loop variable x as int (in the eax register) and just converting it to floating-point for comparison against "count" each loop. Interesting bending of the rules there.




So, running under perf stat tells me the luajit version runs very much more instructions (5M vs. 3M with my patched C version), but they run in the same number of cycles (2.5M), with the luajit version using more instructions per cycle. The unpatched C version uses 3.5M instructions, and 3.5M cycles, which is half the number of instructions per cycle compared to the luajit version.


How did you patch it? Just compile with "-fno-plt" or something more?


  diff --git a/hello.c b/hello.c
  index 725d5ec..b7b1745 100644
  --- a/hello.c
  +++ b/hello.c
  @@ -1,3 +1,5 @@
  +#define _GNU_SOURCE
  +#include <dlfcn.h>
   #include <stdio.h>
   #include "newplus/plus.h"

  @@ -7,8 +9,9 @@ void run(int count)
       long long end;
       
       int x = 0;
  +    int (*_plusone)(int) = dlsym(RTLD_DEFAULT, "plusone");
       while (x < count)
  -        x = plusone(x);
  +        x = _plusone(x);
       
       printf("%lld\n", current_timestamp() - start);
   }
And you need to add -ldl to the link flags.

Edit: but yeah, -fno-plt works too.


> For those curious, Lua handles all numbers as floating-point; there are no ints in Lua.

Same as in JavaScript. I'm surprised by that. On the surface, having just floats and no ints sounds like a pretty dumb idea. What am I missing? Is there a reasonable rationale for such choice?


Well, doubles can represent all the numbers a 52 bit int can, so there's not a huge reason to not use doubles for whole numbers. It also means that new programmers don't get confused when they do 1/3 and get 1, and the language can be significantly simpler when there's only one number type. Also, when you try to store numbers bigger than 2^52, doubles degrade relatively gracefully, while ints wrap around.

There are definitely downsides too, but it's a trade-off, not an exclusively bad decision.


> It also means that new programmers don't get confused when they do 1/3 and get 1,

I'm not a new programmer (nearly 2 decades of professional programming experience), and I would be very confused if 1/3 using integer math returned 1.


Haha, that's what I get for writing comments late at night. I meant something like 4/3.


It was a perfect example of how integer math is not intuitive :-)


> Well, doubles can represent all the numbers a 52 bit int can, so there's not a huge reason to not use doubles for whole numbers.

Not exactly.

> It also means that new programmers don't get confused when they do 1/3 and get 1

Is this (actually, getting 0 from 1/3) really more surprising than doing 2+2 and getting 3.9999999999999?

Floats are mostly inexact and introduce errors with almost every operation. It's something you have to constantly keep in mind when doing any kind of math with meaningful comsequences. I for one think that exact types are both more useful for many practical cases, as well as significantly simpler in use.


> > Well, doubles can represent all the numbers a 52 bit int can, so there's not a huge reason to not use doubles for whole numbers.

> Not exactly.

Yes, exactly [0]. The 52 bit significand gives LuaJIT and other NaN-tagged languages exact integer representations within that range.

[0]: https://en.wikipedia.org/wiki/Floating-point_arithmetic#Inte...


> Is this (actually, getting 0 from 1/3) really more surprising than doing 2+2 and getting 3.9999999999999?

No, so it's a good thing doubles never do anything remotely like that


All floating point integer operations with values smaller than 252 are exact. Most floating point operations with small values with few significant figures are precise.

Fraction, and there are fractions like 1/10 that cannot be represented precisely in base two, much like 1/3 cannot be represented precisely in base 10.

Beyond that, there's the usual issue of pushing out the least significant bits, but that's insurmountable while working in finite precision.


I think you meant 2^52, not 252.


correct. thanks.


There are ints in Lua 5.3, and ffi ints in luajit.

But generally, its simpler, why should people care about representations. Lua also let you compike as int only I think.


> why should people care about representations

Because ints are exact, while floats introduce errors with nearly every operation.

Representations are important in programming - different ones have different consequences.


Javascript is likely to get 64 bit integers soon. It's busy making its way through TC39, anyways.


Lua 5.3 introduced actual 64 bit integers but those probably will never get in LuaJIT because its deeply married to the NaN tagging trick, which limits unboxed values to aprox 48 bits.


You're thinking of the 47 bit address space limitation.

LuaJIT represents the full range of valid 64 bit floats faithfully, giving a 52 bit signed int.


Either way, it cant represent 64 bit integers unless they are boxed (which is very slow)




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: