https://meetingcpp.com/index.php/tv16/items/18.html
C++ low latency
coding
techniques:
● General considerations
C++11 Move semantics
Static assert
Data member layout, padding and alignment (盡量alignment access)
● False sharing
http://shuyufu.blogspot.tw/2013/01/false-sharing.html
● Cache locality
● Compile-time dispatch
std::sort(array, array + N, [](
int a, int b) { return b < a; });
71us, std deviation 1.5us
int comparer(
const void* a, const void* b) { return *(int*)a - *(int*)b; }
qsort(arr, N, sizeof(int), comparer);
223us, std deviation 7us
● Constexpr
C++14 feature
● Variadic templates
● Loop unrolling
Generally, don’t bother, the compiler will figure it out
● Expression short-circuiting
Rewrite:
if (expensiveCheck() && inexpensiveCheck()) {}
As:
if (inexpensiveCheck() && expensiveCheck()) {}
● Signed vs unsigned comparisons
用loop iteratort用signed就是了 (可看前篇
● Mixing float and doubles
Default type of a floating point literal in C++ is double, not float
Side note: If you are brave, consider -ffast-math
● Branch prediction/reduction
Compile-time branch prediction hints are a topic of much discussion (particularly within SG14)
○ I.e. gcc’s __builtin_expect
Avoid this:
if (checkForErrorA()) handleErrorA();
else if (checkForErrorB()) handleErrorB();
else if (checkForErrorC()) handleErrorC();
else executeHotpath();
Aim for this:
uint32_t errorFlags; ...
if (errorFlags) HandleError(errorFlags)
else { ... hotpath }
● Exceptions
不要用
● Slowpath removal
Code is data - keep it minimal, and keep the slowpath code away from the hotpath
● Avoiding allocations
使用萬惡的replace new
Tip: don’t use swap. Memory is cheap. Buy more!
● Fast containers
● Lambda functions
If only at runtime you know what the target is, you have no choice but to use
std::function
If you know at compile time which target is to be run, then prefer lambdas
template
void SendMessage(T&& target) {
// populate and send message
target(mBuffer);
send(mBuffer);
}
SendMessage([&](auto& message) {
message.field1 = x;
...
message.field3 = z;
});
Surprises
and side
notes:
Older versions of gcc’s implementation had copy on write semantics (新版比較快)
#include <string>
#include <iostream>
int main() {
std::string a(50, 'c');
std::string b = a;
*const_cast<char*>(a.c_str()) = 'A';
std::cout << "a: " << a << "\nb: " << b << std::endl;
}
GCC < 5:
$ g++ -std=c++11 main.cpp && ./a.out
a: Accccccccccccccccccccccccccccccccccccccccccccccccc
b: Accccccccccccccccccccccccccccccccccccccccccccccccc
Aha! Copy-on-write in action.
GCC >= 5:
$ g++-5 -std=c++11 main.cpp && ./a.out
a: Accccccccccccccccccccccccccccccccccccccccccccccccc
b: cccccccccccccccccccccccccccccccccccccccccccccccccc
clang:
$ clang++ -std=c++11 -stdlib=libc++ main.cpp && ./a.out
a: Accccccccccccccccccccccccccccccccccccccccccccccccc
b: cccccccccccccccccccccccccccccccccccccccccccccccccc
reference: http://shaharmike.com/cpp/std-string/