6 ms·
Well, I have not taken a look at the implementation yet, but java is certainly known for delivering a decent performance even if the programmer is a little care
by JepZ 9y ago
Well, I have not taken a look at the implementation yet, but java is certainly known for delivering a decent performance even if the programmer is a little careless regarding perfromance.
In Go on the other hand, doing simple 'mistakes' like declaring a variable inside a loop can bring you to performance hell:
Declaration in a loop:
var sum int
for i := 0; i < n; i++ {
x := i + i
sum = x - i
}
Declaration outside the loop:
var sum int
var x int
for i := 0; i < n; i++ {
x = i + i
sum = x - i
}
Benchmark results:
BenchmarkInLoop-8 2000000000 0.40 ns/op
BenchmarkOutLoop-8 2000000000 0.47 ns/op
And the same is certainly true for C/C++.
Src: https://nopaste.xyz/?68c6800acd9200d6#mDstI36uBPBU4Td8k//GNC+P7mmbB1ldMw3DGMuxeQo= https://nopaste.xyz/?68c6800acd9200d6#mDstI36uBPBU4Td8k//GNC...
- Retric 9y agoThis is a common compiler optimization. It says little about a language, just the compiler in use.
- yoklov 9y agoDeclaring a primitive variable inside vs outside a loop in c or c++ will have no effect when compiled with optimizations on by any major compiler. For non-primitive types it will depend on a number of factors, and the better choice for perf could go either way.
- DannyBee 9y agoYes, because if the loop is not always-executing, it may be cheaper to not initialize the complex object, even if it is safe to so.
- yoklov 9y agoI've also (recently) had poor performance on MSVC when "outside the loop" meant "a function argument", for a type that was essentially a struct wrapping a single primitive. It ended up being ABI weirdness that was confusing MSVC (and forceinline ended up fixing it).
- anon946 9y agoAny decent C/C++ compiler will give the same code. For example, this: int f1(int n) { int sum = 0; for (int i = 0; i < n; i++) { int x = i + i; sum = x - i; } return sum; } int f2(int n) { int sum = 0; int x; for (int i = 0; i < n; i++) { x = i + i; sum = x - i; } return sum; } when compiled with 'gcc -O -S' gives: .file "loop.c" .text .globl f1 .type f1, @function f1: .LFB0: .cfi_startproc testl %edi, %edi jle .L4 movl $0, %eax .L3: addl $1, %eax cmpl %eax, %edi jne .L3 subl $1, %eax ret .L4: movl $0, %eax ret .cfi_endproc .LFE0: .size f1, .-f1 .globl f2 .type f2, @function f2: .LFB1: .cfi_startproc testl %edi, %edi jle .L9 movl $0, %eax .L8: addl $1, %eax cmpl %eax, %edi jne .L8 subl $1, %eax ret .L9: movl $0, %eax ret .cfi_endproc .LFE1: .size f2, .-f2 .ident "GCC: (GNU) 7.2.0" .section .note.GNU-stack,"",@progbits Even when compiled without optimization, the generated assembly was the same, though it was messier so I don't show it.
- helper 9y agoWhat go compiler are you using? On my machine those run in exactly the same amount of time (go version go1.9 linux/amd64 ). $ ./tmp.test -test.bench . goos: linux goarch: amd64 BenchmarkInLoop-4 2000000000 0.46 ns/op BenchmarkOutLoop-4 2000000000 0.46 ns/op PASS (pprof) disasm fast Total: 1.95s ROUTINE ======================== _/tmp.fast 970ms 970ms (flat, cum) 49.74% of Total . . 4ed7c0: MOVQ 0x8(SP), AX ;main_test.go:23 . . 4ed7c5: XORL CX, CX . . 4ed7c7: MOVQ CX, DX . . 4ed7ca: JMP 0x4ed7d6 ;main_test.go:26 660ms 660ms 4ed7cc: LEAQ 0x1(CX), BX ;_/tmp.fast main_test.go:26 110ms 110ms 4ed7d0: MOVQ CX, DX 170ms 170ms 4ed7d3: MOVQ BX, CX 30ms 30ms 4ed7d6: CMPQ AX, CX . . 4ed7d9: JL 0x4ed7cc ;main_test.go:26 . . 4ed7db: MOVQ DX, 0x10(SP) ;main_test.go:30 (pprof) disasm slow Total: 1.95s ROUTINE ======================== _/tmp.slow 960ms 960ms (flat, cum) 49.23% of Total . . 4ed790: MOVQ 0x8(SP), AX ;main_test.go:14 . . 4ed795: XORL CX, CX . . 4ed797: MOVQ CX, DX . . 4ed79a: JMP 0x4ed7a6 ;main_test.go:16 690ms 690ms 4ed79c: LEAQ 0x1(CX), BX ;_/tmp.slow main_test.go:16 100ms 100ms 4ed7a0: MOVQ CX, DX 100ms 100ms 4ed7a3: MOVQ BX, CX 70ms 70ms 4ed7a6: CMPQ AX, CX . . 4ed7a9: JL 0x4ed79c ;main_test.go:16 . . 4ed7ab: MOVQ DX, 0x10(SP) ;main_test.go:20
- JepZ 9y ago$ go version go version go1.9.1 linux/amd64
- JepZ 9y agoWell, the assembler looks the same to me too, but I can confirm different runtimes on two different machines (fast is always faster here). $ ./main.test -test.bench . -test.cpuprofile=test.profile goos: linux goarch: amd64 BenchmarkInLoop-8 2000000000 0.42 ns/op BenchmarkOutLoop-8 2000000000 0.47 ns/op PASS (pprof) disasm fast Total: 1.86s ROUTINE ======================== command-line-arguments.fast 990ms 990ms (flat, cum) 53.23% of Total . . 4ed7b0: MOVQ 0x8(SP), AX ;mem_test.go:16 . . 4ed7b5: XORL CX, CX . . 4ed7b7: MOVQ CX, DX . . 4ed7ba: JMP 0x4ed7c6 ;mem_test.go:19 650ms 650ms 4ed7bc: LEAQ 0x1(CX), BX ;command-line-arguments.fast mem_test.go:19 . . 4ed7c0: MOVQ CX, DX ;mem_test.go:19 10ms 10ms 4ed7c3: MOVQ BX, CX ;command-line-arguments.fast mem_test.go:19 330ms 330ms 4ed7c6: CMPQ AX, CX . . 4ed7c9: JL 0x4ed7bc ;mem_test.go:19 . . 4ed7cb: MOVQ DX, 0x10(SP) ;mem_test.go:23 (pprof) disasm slow Total: 1.86s ROUTINE ======================== command-line-arguments.slow 870ms 870ms (flat, cum) 46.77% of Total . . 4ed780: MOVQ 0x8(SP), AX ;mem_test.go:7 . . 4ed785: XORL CX, CX . . 4ed787: MOVQ CX, DX . . 4ed78a: JMP 0x4ed796 ;mem_test.go:9 560ms 560ms 4ed78c: LEAQ 0x1(CX), BX ;command-line-arguments.slow mem_test.go:9 . . 4ed790: MOVQ CX, DX ;mem_test.go:9 20ms 20ms 4ed793: MOVQ BX, CX ;command-line-arguments.slow mem_test.go:9 290ms 290ms 4ed796: CMPQ AX, CX . . 4ed799: JL 0x4ed78c ;mem_test.go:9 . . 4ed79b: MOVQ DX, 0x10(SP) ;mem_test.go:13