
[link]文章指出,Haskell代码的性能优于C ++代码。立刻引起了人们的兴趣 两者都可以由LLVM由编译器生成,这意味着Eskell可以为编译器提供更多提示,或者C ++实现有问题。接下来,我们将分析作者的行为中发生的一系列事故如何导致错误的结论,下表中对此进行了描述(下划线)。
前言
最近,另一篇文章来自0xd34df00dHaskell代码优化。在这种情况下,自然可以将其与不可否认的性能领先者-C / C ++进行比较。这时来了解析本文来自音阶关于哪种asm代码真正更好,以及在不同语言上的实现之间有什么区别(我建议阅读)。甚至更早(大约一个半月前),Haskell与C / C ++系列的前一篇文章也已发布,我进行了类似的分析,但是没有将其发布到Habr-,,我将其放在了后箱中。本周评论中的激烈讨论促使我回到上一个主题。今天我终于把那笔降价文件从抽屉里拿出来,除掉了灰尘,完了,并提供您的评论。
介绍
, [], :
/++, .. , , " , ". "", . , , , 10- .
-, , ++ , , , . , zero-cost, , , , - ++, . , clang 3 (!) , +, , .. lang llvm — .
, : gcc clang. , . ( ), gcc . , , , , , .
std::min({...})
, , std::min.
C++.
, std::min({delCost, insCost, substCost})
std::min(substCost, std::min(delCost, insCost))
,
clang — 0.840
, .
( — 0xd34df00d)
:
A.unsafeWrite v1 (j + 1) $ min (substCost + substCostBase) $ 1 + min delCost insCost
, min
! (, ). , , C++ , , llvm llvm. , . , , "skell " . , " ++; , PHP" , , . :
stdlib gcc - std::min
, ++. std::min_element
. , , , :
f(int, int, int):
cmp esi, edi
mov eax, edx
cmovg esi, edi
cmp esi, edx
cmovle eax, esi
ret
: cmov*
= conditional move (: g
— greater, le
— less equal, ..).
, , , , clang, gcc, - ( rsp ):
fptr(int*, int*, int*):
mov eax, dword ptr [rdi]
mov dword ptr [rsp - 12], eax
mov ecx, dword ptr [rsi]
mov dword ptr [rsp - 8], ecx
cmp ecx, eax
cmovle eax, ecx
mov ecx, dword ptr [rdx]
cmp ecx, eax
cmovle eax, ecx
ret
, clang . initializer_list
asm -O1
, (-O2
), asm . , std::min(std::initializer_list)
-, -, , .
s1[i]
, — , ++.
s1[i]
! ()
, , , - , , . , s1[i]
,
let s1char = s1 `BS.index` i
let go j | j == n = pure ()
++, , clang. .. + llvm - , -march=native
. , , std::min
, , ! , - , " " , .
C++ .
,
C main', .
( )
, , , - , :
size_t lev_dist(const std::string &s1, const std::string &s2) {
const auto m = s1.size();
const auto n = s2.size();
std::vector<int> v0;
v0.resize(n + 1);
std::iota(v0.begin(), v0.end(), 0);
auto v1 = v0;
for (size_t i = 0; i < m; ++i) {
v1[0] = i + 1;
char c1 = s1[i];
for (size_t j = 0; j < n; ++j) {
auto substCost = c1 == s2[j] ? v0[j] : (v0[j] + 1);
v1[j + 1] = std::min(substCost, std::min(v0[j + 1], v1[j]) + 1);
}
std::swap(v0, v1);
}
return v0[n];
}
32- int
— , ( ).
, GCC . j
, GCC. clang .
LLVM == LLVM
-, , ++ Haskell , clang-9. , Skylake C++ . , , , Haswell, .
, , , GCC LLVM.
, , llvm, ffi, .
GCC vs CLANG
-, , gcc . , clang- .
, , , , (#if !defined(__GNUC__) || defined(__llvm__)
), ++ , , ++ .
clang ( ) . ( )
, GCC LLVM. , asm. gcc - : , cmov* min ( , ). (3), , , ++ :
for (size_t j = 0; j < n; ++j) {
auto delCost = v0[j + 1] + 1;
auto insCost = v1[j] + 1;
auto substCost = c1 == s2[j] ? v0[j] : (v0[j] + 1);
v1[j + 1] = std::min(substCost, std::min(delCost, insCost));
}
, , :
.L42:
inc rcx // j++
mov rdi, QWORD PTR [r12+rcx*8] // v0[j+1]
xor edx, edx // %edx
cmp r10b, BYTE PTR [r11-1+rcx] // c1 == s2[j]
setne dl // %rdx
lea r9, [rdi+1] // v0[j+1] + 1
add rdx, QWORD PTR [r12-8+rcx*8] // v0[j]
lea rsi, [rax+1] // %rax v1[j]
cmp rdi, rax // v0[j+1] v1[j] += 1
mov rax, r9
cmovg rax, rsi // += 1
cmp rax, rdx // %rax, %rdx
cmovg rax, rdx
mov QWORD PTR [r8+rcx*8], rax // v1[j+1] = ...
cmp rbx, rcx // loop
jne .L42
, — v1[j]
%rax
.
LLVM, - , . , , :
.LBB1_40: # in Loop: Header=BB1_36 Depth=2
mov qword ptr [r14 + 8*rsi + 8], rax
mov rdx, qword ptr [rbx + 8*rsi + 16]
inc rdx
inc rax
xor ebp, ebp
cmp cl, byte ptr [r13 + rsi + 1]
setne bpl
add rbp, qword ptr [rbx + 8*rsi + 8]
cmp rax, rdx
jg .LBB1_41
lea rdi, [rsi + 2]
cmp rax, rbp
jle .LBB1_44
jmp .LBB1_43
: jmp, j*
= jump (: jg
— greater, jle
— less equal, ..).
v0[j+1]
, v0[j]
, cmp
s1[i]
, cmp + jump . , , ( , ) , , . — .
, GCC , LLVM 2 (!) , .
, . : (jump), — (cmov).
, — .
, , . , , PGO (, JIT ). , GCC PGO clang. — , . , , // , , , .
- , —
- , LLVM
- , GCC LLVM ,
- ffi. , .. , , ,
, , .
: , , "" , , . Rust (, ).
P.S.
— , -
( )
, — , .. , , , s1 s2. . -, O(n*m) ( for). , . , k. , . , .
LinearLeopard .
- :
-O3 -march=native -std=gnu++17
. - 处理器:Intel i5-8250U(是,笔记本电脑)
- 作业系统:Ubuntu 19.04 / Linux 5.0.0
- 首先运行以加速涡轮增压,然后至少连续行驶五次。偏差在1-2%以内。
- 在推出不同的1s实施方案之间,我们会降温(是的,笔记本电脑)
补充:懒惰脚本
您可以在硬件上运行相同的东西,并将结果告知公众:指向github的链接。
补充:没有-march = native的结果
根据评论中的请求,我决定检查此标志的影响。