SlideShare a Scribd company logo
1 of 59
Download to read offline
Small Lie in Big O
Mateusz Pusz
November 15, 2016
2code::dive 2016 Mateusz Pusz
‘sample’ is a simple class containing 8-bit unsigned integral member
and a few user defined methods. Integral member inside ‘sample’
class should be initialized during class construction.
Implement function ‘test’ that:
• takes 2 integral arguments ‘n’ and ‘k’
• creates a collection of ‘n’ ‘sample’ objects with random values
assigned
• sorts created collection
• inserts a new random value keeping the collection sorted
(repeat ‘k’ times)
• returns average value from all the samples in the collection
SIMPLE PROGRAMMING PROBLEM
3code::dive 2016 Mateusz Pusz
class sample {
std::uint8_t value_;
public:
// more interface...
};
‘sample’ is a simple class containing 8-bit unsigned integral member and a few user defined
methods
4code::dive 2016 Mateusz Pusz
class sample {
std::uint8_t value_;
public:
explicit constexpr sample(std::uint8_t value) noexcept : value_{value} {}
// more interface...
};
Integral member inside ‘sample’ class should be initialized during class construction
5code::dive 2016 Mateusz Pusz
class sample {
std::uint8_t value_;
public:
explicit constexpr sample(std::uint8_t value) noexcept : value_{value} {}
// more interface...
};
std::uint8_t test(int n, int k)
{
}
implement a function ‘test’ that takes 2 integral arguments ‘n’ and ‘k’
6code::dive 2016 Mateusz Pusz
class sample {
std::uint8_t value_;
public:
explicit constexpr sample(std::uint8_t value) noexcept : value_{value} {}
// more interface...
};
std::uint8_t test(int n, int k)
{
// create collection of 'n' random samples
// sort the collection
// k times insert a new random sample keeping the collection sorted
// return average value from samples in the collection
}
implement a function ‘test’ that …
7code::dive 2016 Mateusz Pusz
class sample {
std::uint8_t value_;
public:
explicit constexpr sample(std::uint8_t value) noexcept : value_{value} {}
// more interface...
// returns stored value
constexpr operator std::uint8_t() const noexcept { return value_; }
};
“sorting”, “comparing values”, … –> need to extend ‘sample’ interface
8code::dive 2016 Mateusz Pusz
using elem_type = sample*;
using collection = std::list<elem_type>;
“class”, not a fundamental type –> dynamic memory allocation
“inserting in the middle”, “sorting”, … –> std::list
9code::dive 2016 Mateusz Pusz
std::uint8_t generate()
{
... // probably not enough time today to describe the implementation
}
“random values” –> provide random numbers generator
… or use C++11 <random>
XKCD way …
10code::dive 2016 Mateusz Pusz
collection init_random(int n)
{
collection samples;
for(int i=0; i<num; ++i)
samples.emplace_back(new sample{generate()});
return samples;
}
std::uint8_t test(int n, int k)
{
// create collection of 'n' random samples
auto samples = init_random(n);
// ...
}
creates a collection of ‘n’ ‘sample’ objects with random values assigned
O(n)
11code::dive 2016 Mateusz Pusz
std::uint8_t test(int n, int k)
{
// create collection of 'n' random samples
auto samples = init_random(n);
// sort the collection
values.sort([](const auto& l, const auto& r) { return *l < *r; });
// ...
}
sorts created collection
O(nlogn)
12code::dive 2016 Mateusz Pusz
std::uint8_t test(int n, int k)
{
// ...
// k times insert a new random sample keeping the collection sorted
for(int i=0; i<k; ++i) {
const sample new_sample{generate()};
samples.emplace(
),
new sample{new_sample});
}
// ...
}
std::uint8_t test(int n, int k)
{
// ...
// k times insert a new random sample keeping the collection sorted
for(int i=0; i<k; ++i) {
const sample new_sample{generate()};
samples.emplace(find_if(begin(samples), end(samples),
),
new sample{new_sample});
}
// ...
}
std::uint8_t test(int n, int k)
{
// ...
// k times insert a new random sample keeping the collection sorted
for(int i=0; i<k; ++i) {
const sample new_sample{generate()};
samples.emplace(find_if(begin(samples), end(samples),
[&](const auto& s) { return new_sample < *s; }),
new sample{new_sample});
}
// ...
}
inserts a new random value keeping the collection sorted (repeat ‘k’ times)
O(k * (n+k))
13code::dive 2016 Mateusz Pusz
std::uint8_t test(int n, int k)
{
// ...
// return average value from samples in the collection
return std::accumulate(begin(samples), end(samples), std::uint64_t{},
[](const auto& sum, const auto& s){ return sum + *s; }) / samples.size();
}
returns average value from all the samples in the collection
O(n)
14code::dive 2016 Mateusz Pusz
std::uint8_t test(int n, int k)
{
// create collection of 'n' random samples
auto samples = init_random(n);
// sort the collection
samples.sort([](const auto& l, const auto& r) { return *l < *r; });
// k times insert a new random sample keeping the collection sorted
for(int i = 0; i < k; ++i) {
const sample new_sample{generate()};
samples.emplace(find_if(begin(samples), end(samples),
[&](const auto& s) { return new_sample < *s; }),
new sample{new_sample});
}
// return average value from samples in the collection
return std::accumulate(begin(samples), end(samples), std::uint64_t{},
[](const auto& sum, const auto& s){ return sum + *s; }) / samples.size();
}
Whole code
Do you see a problem?
15code::dive 2016 Mateusz Pusz
std::uint8_t test(int n, int k)
{
// create collection of 'n' random samples
auto samples = init_random(n);
// sort the collection
samples.sort([](const auto& l, const auto& r) { return *l < *r; });
// k times insert a new random sample keeping the collection sorted
for(int i = 0; i < k; ++i) {
const sample new_sample{generate()};
samples.emplace(find_if(begin(samples), end(samples),
[&](const auto& s) { return new_sample < *s; }),
new sample{new_sample});
}
// return average value from samples in the collection
return std::accumulate(begin(samples), end(samples), std::uint64_t{},
[](const auto& sum, const auto& s){ return sum + *s; }) / samples.size();
}
Whole code
Do you see a problem?
16code::dive 2016 Mateusz Pusz
We have a memory
leak here
17code::dive 2016 Mateusz Pusz
std::uint8_t test(int n, int k)
{
// ...
// cleanup the collection
for(auto& s : samples)
delete s;
}
Adding cleanup is simple, right?
18code::dive 2016 Mateusz Pusz
std::uint8_t test(int n, int k)
{
// create collection of 'n' random samples
auto samples = init_random(n);
// sort the collection
samples.sort([](const auto& l, const auto& r) { return *l < *r; });
// k times insert a new random sample keeping the collection sorted
for(int i = 0; i < k; ++i) {
const sample new_sample{generate()};
samples.emplace(find_if(begin(samples), end(samples),
[&](const auto& s) { return new_sample < *s; }),
new sample{new_sample});
}
// return average value from samples in the collection
auto avg = std::accumulate(begin(samples), end(samples), std::uint64_t{},
[](const auto& sum, const auto& s){ return sum + *s; }) / samples.size();
// cleanup the collection
for(auto& s : samples)
delete s;
return avg;
}
Whole code
Do you see a problem?
19code::dive 2016 Mateusz Pusz
std::uint8_t test(int n, int k)
{
// create collection of 'n' random samples
auto samples = init_random(n);
// sort the collection
samples.sort([](const auto& l, const auto& r) { return *l < *r; });
// k times insert a new random sample keeping the collection sorted
for(int i = 0; i < k; ++i) {
const sample new_sample{generate()};
samples.emplace(find_if(begin(samples), end(samples),
[&](const auto& s) { return new_sample < *s; }),
new sample{new_sample});
}
// return average value from samples in the collection
auto avg = std::accumulate(begin(samples), end(samples), std::uint64_t{},
[](const auto& sum, const auto& s){ return sum + *s; }) / samples.size();
// cleanup the collection
for(auto& s : samples)
delete s;
return avg;
}
Whole code
Do you see a problem?
20code::dive 2016 Mateusz Pusz
The code is not exception safe!!!
21code::dive 2016 Mateusz Pusz
class resource {
// resource handle
public:
resource(/* args */)
{ /* obtain ownership of a resource and store the handle */ }
~resource()
{ /* reclaim the resource */ }
};
If you dissect the words of the RAII acronym (Resource Acquisition Is
Initialization), you will think RAII is about acquiring resources during
initialization. However the power of RAII comes not from tying acquisition to
initialization, but from tying reclamation to destruction.
-- Bjarne Stroustrup
RESOURCE ACQUISITION IS INITIALIZATION (RAII)
22code::dive 2016 Mateusz Pusz
• Smart Pointers
– std::unique_ptr<T, Deleter = std::default_delete<T>>
– std::shared_ptr<T>
– std::weak_ptr<T>
– std::auto_ptr<T>
• Containers
– all STL containers manage ownership of their data
• File streams
• Mutex locks
– std::lock_guard<Mutex>
– std::unique_lock<Mutex>
• More…
RAII USAGE IN C++ STANDARD LIBRARY
23code::dive 2016 Mateusz Pusz
using elem_type = std::unique_ptr<sample>;
// ...
// replace all
new sample{...}
// with
std::make_unique<sample>(...)
std::uint8_t test(int n, int k)
{
// ...
// cleanup the collection
for(auto& s : samples)
delete s;
}
Let’s fix our code to be C++ exception safe
Writing exception safe code
is not that hard at all!!!
24code::dive 2016 Mateusz Pusz
Solution test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
Original 10,7s 104,5s 32,6s
Change 1 9,3s 57,1s 16,4s
Change 2 0,75s 1,7s 0,37s
Change 3 0,75s 0,98s 0,21s
Speedup 14x 106x 155x
Can we make our code faster?
TWEAKING ‘N’ IN ‘F(N)’
25code::dive 2016 Mateusz Pusz
Solution test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
Original 10,7s 104,5s 32,6s
Change #1 9,3s 57,1s 16,4s
Change #2 0,75s 1,7s 0,37s
Change #3 0,75s 0,98s 0,21s
Speedup 14x 106x 155x
Can we make our code faster?
Yes, A LOT faster
TWEAKING ‘N’ IN ‘F(N)’
26code::dive 2016 Mateusz Pusz
using elem_type = sample*;
using collection = std::list<elem_type>;
“class”, not a fundamental type –> dynamic memory allocation
“inserting in the middle”, “sorting”, … –> std::list
WRONG!!!
27code::dive 2016 Mateusz Pusz
• Heap usage should be avoided if possible
– allocation and deallocation of heap memory is slow
– obtaining data from non-cached memory is slow
– heap allocation can fail
– allocation of many small objects causes huge memory fragmentation
• C++ loves value semantics
– using pointers changes semantics of copy, assignment and equality
– pointer dereferencing takes time
– much easier to write thread-safe code
– reference/pointer semantics causes aliasing problems
• compiler optimizer cannot do its best -> slower code
– Copy Elision (RVO) and Move Semantics improve things a lot
C++ IS NOT C# OR JAVA
28code::dive 2016 Mateusz Pusz
Avoid pointers
using elem_type = sample;
// ...
std::uint8_t test(int n, int k)
{
// ...
samples.sort([](const auto& l, const auto& r) { return *l < *r; });
// ...
auto avg = std::accumulate(begin(samples), end(samples), std::uint64_t{},
[](const auto& sum, const auto& s){ return sum + *s; }) / samples.size();
// ...
}
1.15x-2x speedup
CHANGE #1
29code::dive 2016 Mateusz Pusz
Use std::vector<T> as a default container
using collection = std::vector<elem_type>;
collection init_random(int n, int k)
{
collection samples;
samples.reserve(n + k);
for(int i=0; i<n; ++i)
samples.emplace_back(generate());
return samples;
}
12x-44x speedup. Why?
std::uint8_t test(int n, int k)
{
// create collection of 'n' random samples
auto samples = init_random(n, k);
// ...
// sort the collection
sort(begin(samples), end(samples));
// ...
}
CHANGE #2
30code::dive 2016 Mateusz Pusz
Operation std::list<T> std::vector<T>
create container of 'n' random values O(n) O(n)
sort container O(nlogn) O(nlogn)
'k' times insert a new random value keeping
the container sorted
O(k * (n+k)) O(k * (n+k))
verify if sorted O(n+k) O(n+k)
Overall complexity O(k * (n+k)) O(k * (n+k))
12x-44x speedup. Why?
ALGORITHMIC POINT OF VIEW
31code::dive 2016 Mateusz Pusz
T
prev
next
T
prev
next
T
prev
next
std::list<T>
32code::dive 2016 Mateusz Pusz
• easy to insert new elements
• easy to erase existing elements
• easy to reorder elements
• bidirectional iteration
• memory ineffective
– for small T large memory overhead
– a lot of dynamic memory allocations and deallocations
– a lot of pointer dereferences during iteration
– not cache friendly
std::list<T>
T
prev
next
T
prev
nextT
prev
next
T
prev
next
33code::dive 2016 Mateusz Pusz
std::list<int> ITERATION
prev* next* int pad
M
E
M
O
R
Y
CPU cache
34code::dive 2016 Mateusz Pusz
{ reserved }
• inserting new elements
– end – easy (unless buffer reallocation is needed)
– begin, middle – hard
• erasing existing elements
– end – easy
– begin, middle – hard
• swapping values needed to reorder elements
• random access iteration
• memory effective
– small memory overhead (reserved space)
– nearly no dynamic memory allocations and deallocations
– no pointer dereferences during iteration
– cache friendly!!!
std::vector<T>
T T T T T T T T T T T T
35code::dive 2016 Mateusz Pusz
int
CPU cache
Writing cache
friendly code makes a
huge difference!
std::vector<int> ITERATION
M
E
M
O
R
Y
36code::dive 2016 Mateusz Pusz
Performance counter stats for './test_list':
83991,294231 task-clock (msec) # 0,999 CPUs utilized
213901565783 cycles # 2,547 GHz
27748493084 instructions # 0,13 insn per cycle
8472128537 branches # 100,869 M/sec
61763769 branch-misses # 0,73% of all branches
8822212776 L1-dcache-loads # 105,037 M/sec
4799991469 L1-dcache-load-misses # 54,41% of all L1-dcache hits
4177763046 LLC-loads # 49,740 M/sec
550506468 LLC-load-misses # 13,18% of all LL-cache hits
78237 page-faults # 0,931 K/sec
Performance counter stats for './test_vector':
2826,385943 task-clock (msec) # 0,999 CPUs utilized
7462656329 cycles # 2,640 GHz
27117855932 instructions # 3,63 insn per cycle
7396349132 branches # 2616,893 M/sec
39248559 branch-misses # 0,53% of all branches
6466518567 L1-dcache-loads # 2287,911 M/sec
77800147 L1-dcache-load-misses # 1,20% of all L1-dcache hits
89304 LLC-loads # 0,032 M/sec
36469 LLC-load-misses # 40,84% of all LL-cache hits
1050 page-faults # 0,371 K/sec
LISTVECTOR
37code::dive 2016 Mateusz Pusz
L1 cache reference 0.5 ns
Branch misprediction 5 ns
L2 cache reference 7 ns 14x L1 cache
Mutex lock/unlock 25 ns
Main memory reference 100 ns 20x L2 cache, 200x L1 cache
Compress 1K bytes with Zippy 3,000 ns
Send 1K bytes over 1 Gbps network 10,000 ns
Read 4K randomly from SSD 150,000 ns
Read 1 MB sequentially from memory 250,000 ns
Round trip within same datacenter 500,000 ns
Read 1 MB sequentially from SSD 1,000,000 ns 4X memory
Disk seek 10,000,000 ns 20x datacenter roundtrip
Read 1 MB sequentially from disk 20,000,000 ns 80x memory, 20X SSD
Send packet CA->Netherlands->CA 150,000,000 ns
Latency Numbers Every Programmer Should Know
-- Jeff Dean
38code::dive 2016 Mateusz Pusz
std::uint8_t test(int n, int k)
{
// create collection of 'n' random samples
// sort the collection
// k times insert a new random sample keeping the collection sorted
// return average value from samples in the collection
}
§25.4.3.1
template<class ForwardIterator, class T>
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value);
1 Requires: The elements e of [first,last) shall be partitioned with respect to the expression e < value
2 Returns: The furthermost iterator i in the range [first,last] such that for every iterator j in the range
[first,i) the following corresponding conditions hold: *j < value.
3 Complexity: At most log2(last − first) + O(1) comparisons.
A NEW POSSIBILITY FOR ALGORITHMIC OPTIMIZATION
39code::dive 2016 Mateusz Pusz
Know and use C++ algorithms
std::uint8_t test(int n, int k)
{
// ...
// k times insert a new random sample keeping the collection sorted
for(int i=0; i<k; ++i) {
const sample new_sample{generate()};
samples.emplace(lower_bound(begin(samples), end(samples), new_sample), new_sample);
}
// ...
}
1x-1.7x speedup
CHANGE #3
40code::dive 2016 Mateusz Pusz
collection init_random(int n, int k)
{
collection samples;
samples.reserve(n + k);
for(int i=0; i<n; ++i)
samples.emplace_back(generate());
return samples;
}
std::uint8_t test(int n, int k)
{
auto samples = init_random(n, k);
sort(begin(samples), end(samples));
// k times insert a new random sample keeping the collection sorted
for(int i=0; i<k; ++i) {
const sample new_sample{generate()};
samples.emplace(lower_bound(begin(samples), end(samples), new_sample), new_sample);
}
return std::accumulate(begin(samples), end(samples), std::uint64_t{}) / samples.size();
}
Isn’t it a great
example of efficient
programming?
Whole code
41code::dive 2016 Mateusz Pusz
QUOTES FROM THE C++ COMMUNITY
Using std::map is an exercise in slowing down code.
If you think link list is bad... maps are worse.
42code::dive 2016 Mateusz Pusz
Metric vector multiset vector multiset vector multiset
task-clock [msec] 765 9162
Instructions [insn/cycle] 1,33 0,31
L1-dcache-loads [M/sec] 645,8 189,6
L1-dcache-load-misses 0,39% 29,91%
LLC-loads [M/sec] 0,074 37,9
LLC-load-misses 37,55% 18,61%
page-faults [K/sec] 1 11
std::multiset<sample> usage
test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
43code::dive 2016 Mateusz Pusz
Metric vector multiset vector multiset vector multiset
task-clock [msec] 765 9162
Instructions [insn/cycle] 1,33 0,31 3,86 0,60
L1-dcache-loads [M/sec] 645,8 189,6 2557,5 326,3
L1-dcache-load-misses 0,39% 29,91% 1,03% 12,06%
LLC-loads [M/sec] 0,074 37,9 0,035 17,7
LLC-load-misses 37,55% 18,61% 22,45% 16,84%
page-faults [K/sec] 1 11 0,14 23
std::multiset<sample> usage
test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
44code::dive 2016 Mateusz Pusz
Metric vector multiset vector multiset vector multiset
task-clock [msec] 765 9162 978 46
Instructions [insn/cycle] 1,33 0,31 3,86 0,60
L1-dcache-loads [M/sec] 645,8 189,6 2557,5 326,3
L1-dcache-load-misses 0,39% 29,91% 1,03% 12,06%
LLC-loads [M/sec] 0,074 37,9 0,035 17,7
LLC-load-misses 37,55% 18,61% 22,45% 16,84%
page-faults [K/sec] 1 11 0,14 23
std::multiset<sample> usage
test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
45code::dive 2016 Mateusz Pusz
Metric vector multiset vector multiset vector multiset
task-clock [msec] 765 9162 978 46 212 61
Instructions [insn/cycle] 1,33 0,31 3,86 0,60 3,70 0,59
L1-dcache-loads [M/sec] 645,8 189,6 2557,5 326,3 2598,5 367,6
L1-dcache-load-misses 0,39% 29,91% 1,03% 12,06% 1,45% 19,20%
LLC-loads [M/sec] 0,074 37,9 0,035 17,7 0,084 16,9
LLC-load-misses 37,55% 18,61% 22,45% 16,84% 21,07% 8,38%
page-faults [K/sec] 1 11 0,14 23 0,67 23
std::multiset<sample> usage
test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
46code::dive 2016 Mateusz Pusz
Solution test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
Original 10,7s 104,5s 32,6s
Change #1 9,3s 57,1s 16,4s
Change #2 0,75s 1,7s 0,37s
Change #3 0,75s 0,98s 0,21s
Speedup 14x 106x 155x
Can we make our code faster?
TWEAKING ‘N’ IN ‘F(N)’
47code::dive 2016 Mateusz Pusz
Solution test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
Original 10,7s 104,5s 32,6s
Change #1 9,3s 57,1s 16,4s
Change #2 0,75s 1,7s 0,37s
Change #3 0,75s 0,98s 0,21s
Bonus #1 8,9s 0,04s 0,05s
Bonus #2 1,7s 0,04s 0,02s
Speedup ??? 2 612x 1 630x
Can we make our code faster?
TWEAKING ‘N’ IN ‘F(N)’
48code::dive 2016 Mateusz Pusz
std::multiset<sample> usage
using collection = std::multiset<elem_type>;
// ...
std::uint8_t test(int n, int k)
{
// ...
sort(begin(samples), end(samples));
// ...
samples.emplace(lower_bound(begin(samples), end(samples), new_sample), new_sample);
// ...
}
0.08x-24x speedup
Bonus #1
49code::dive 2016 Mateusz Pusz
std::multiset<sample> + std::vector<sample> usage
using collection1 = std::vector<elem_type>; using collection2 = std::multiset<elem_type>;
// ...
std::uint8_t test(int n, int k)
{
// create collection of 'n' random samples
collection1 samples1 = init_random(n, k);
// sort the collection
sort(begin(samples1), end(samples1));
collection2 samples2{begin(samples1), end(samples1)};
// ...
}
Bonus #2
50code::dive 2016 Mateusz Pusz
TAKE AWAYS
Learn C++ to be a more
efficient programmer
• containers,
• algorithms,
• new C++11/C++14/C++17
features
Use RAII design pattern as
your first resort tool for
management of all
resources
Use tools provided by the
C++ standard or C++
community
Do not reinvent the wheel!!!
Remember that memory
access is the bottleneck of
many today’s applications!
Limit pointers usage
Write cache friendly code
Photograph by Mauro Sartori
Always meassure your code
if you care for performance!
Do not do premature
optimizations based only on
your assumptions
(algorithms, CPU cache
friendliness or others)
56code::dive 2016 Mateusz Pusz
Questions?
58code::dive 2016 Mateusz Pusz
BONUS SLIDE
59code::dive 2016 Mateusz Pusz
template<typename T>
auto make_random_int_generator(T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max(),
std::mt19937::result_type seed = std::mt19937::default_seed)
{
static_assert(std::is_integral_v<T>);
std::mt19937 gen{seed};
std::uniform_int_distribution<T> distr{min, maxs};
return [=]() mutable { return distr(gen); };
}
std::uint8_t generate()
{
static auto generator = make_random_int_generator<std::uint8_t>();
return generator();
}
PSEUDO-RANDOM NUMBERS GENERATOR

More Related Content

What's hot

The Evolution of Async-Programming (SD 2.0, JavaScript)
The Evolution of Async-Programming (SD 2.0, JavaScript)The Evolution of Async-Programming (SD 2.0, JavaScript)
The Evolution of Async-Programming (SD 2.0, JavaScript)jeffz
 
Jscex: Write Sexy JavaScript
Jscex: Write Sexy JavaScriptJscex: Write Sexy JavaScript
Jscex: Write Sexy JavaScriptjeffz
 
Unleash your inner console cowboy
Unleash your inner console cowboyUnleash your inner console cowboy
Unleash your inner console cowboyKenneth Geisshirt
 
LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기Wanbok Choi
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6Fiyaz Hasan
 
Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)jeffz
 
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...GeeksLab Odessa
 
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Susan Potter
 
(3) cpp abstractions more_on_user_defined_types
(3) cpp abstractions more_on_user_defined_types(3) cpp abstractions more_on_user_defined_types
(3) cpp abstractions more_on_user_defined_typesNico Ludwig
 
PVS-Studio for Linux Went on a Tour Around Disney
PVS-Studio for Linux Went on a Tour Around DisneyPVS-Studio for Linux Went on a Tour Around Disney
PVS-Studio for Linux Went on a Tour Around DisneyPVS-Studio
 
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)jeffz
 
Source Code Clone Search (Iman keivanloo PhD seminar)
Source Code Clone Search (Iman keivanloo PhD seminar)Source Code Clone Search (Iman keivanloo PhD seminar)
Source Code Clone Search (Iman keivanloo PhD seminar)imanmahsa
 
Tips and tricks for building high performance android apps using native code
Tips and tricks for building high performance android apps using native codeTips and tricks for building high performance android apps using native code
Tips and tricks for building high performance android apps using native codeKenneth Geisshirt
 
The Ring programming language version 1.5.4 book - Part 10 of 185
The Ring programming language version 1.5.4 book - Part 10 of 185The Ring programming language version 1.5.4 book - Part 10 of 185
The Ring programming language version 1.5.4 book - Part 10 of 185Mahmoud Samir Fayed
 
A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)
A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)
A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)Sylvain Hallé
 
Javascript Uncommon Programming
Javascript Uncommon ProgrammingJavascript Uncommon Programming
Javascript Uncommon Programmingjeffz
 
Real World Generics In Swift
Real World Generics In SwiftReal World Generics In Swift
Real World Generics In SwiftVadym Markov
 
The Evolution of Async-Programming on .NET Platform (TUP, Full)
The Evolution of Async-Programming on .NET Platform (TUP, Full)The Evolution of Async-Programming on .NET Platform (TUP, Full)
The Evolution of Async-Programming on .NET Platform (TUP, Full)jeffz
 
JavaScript Web Development
JavaScript Web DevelopmentJavaScript Web Development
JavaScript Web Developmentvito jeng
 

What's hot (20)

The Evolution of Async-Programming (SD 2.0, JavaScript)
The Evolution of Async-Programming (SD 2.0, JavaScript)The Evolution of Async-Programming (SD 2.0, JavaScript)
The Evolution of Async-Programming (SD 2.0, JavaScript)
 
Jscex: Write Sexy JavaScript
Jscex: Write Sexy JavaScriptJscex: Write Sexy JavaScript
Jscex: Write Sexy JavaScript
 
Unleash your inner console cowboy
Unleash your inner console cowboyUnleash your inner console cowboy
Unleash your inner console cowboy
 
LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6
 
Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)
 
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
 
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
 
(3) cpp abstractions more_on_user_defined_types
(3) cpp abstractions more_on_user_defined_types(3) cpp abstractions more_on_user_defined_types
(3) cpp abstractions more_on_user_defined_types
 
PVS-Studio for Linux Went on a Tour Around Disney
PVS-Studio for Linux Went on a Tour Around DisneyPVS-Studio for Linux Went on a Tour Around Disney
PVS-Studio for Linux Went on a Tour Around Disney
 
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
 
Source Code Clone Search (Iman keivanloo PhD seminar)
Source Code Clone Search (Iman keivanloo PhD seminar)Source Code Clone Search (Iman keivanloo PhD seminar)
Source Code Clone Search (Iman keivanloo PhD seminar)
 
Tips and tricks for building high performance android apps using native code
Tips and tricks for building high performance android apps using native codeTips and tricks for building high performance android apps using native code
Tips and tricks for building high performance android apps using native code
 
The Ring programming language version 1.5.4 book - Part 10 of 185
The Ring programming language version 1.5.4 book - Part 10 of 185The Ring programming language version 1.5.4 book - Part 10 of 185
The Ring programming language version 1.5.4 book - Part 10 of 185
 
A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)
A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)
A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)
 
Javascript Uncommon Programming
Javascript Uncommon ProgrammingJavascript Uncommon Programming
Javascript Uncommon Programming
 
Java 7 new features
Java 7 new featuresJava 7 new features
Java 7 new features
 
Real World Generics In Swift
Real World Generics In SwiftReal World Generics In Swift
Real World Generics In Swift
 
The Evolution of Async-Programming on .NET Platform (TUP, Full)
The Evolution of Async-Programming on .NET Platform (TUP, Full)The Evolution of Async-Programming on .NET Platform (TUP, Full)
The Evolution of Async-Programming on .NET Platform (TUP, Full)
 
JavaScript Web Development
JavaScript Web DevelopmentJavaScript Web Development
JavaScript Web Development
 

Similar to Small Lie in Big O

Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?Andrey Karpov
 
Write the code above and the ones below in netbeans IDE 8.13. (Eli.pdf
Write the code above and the ones below in netbeans IDE 8.13. (Eli.pdfWrite the code above and the ones below in netbeans IDE 8.13. (Eli.pdf
Write the code above and the ones below in netbeans IDE 8.13. (Eli.pdfarihantmum
 
maxbox starter60 machine learning
maxbox starter60 machine learningmaxbox starter60 machine learning
maxbox starter60 machine learningMax Kleiner
 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4Abed Bukhari
 
05. Java Loops Methods and Classes
05. Java Loops Methods and Classes05. Java Loops Methods and Classes
05. Java Loops Methods and ClassesIntro C# Book
 
rrxv6 Build a Riscv xv6 Kernel in Rust.pdf
rrxv6 Build a Riscv xv6 Kernel in Rust.pdfrrxv6 Build a Riscv xv6 Kernel in Rust.pdf
rrxv6 Build a Riscv xv6 Kernel in Rust.pdfYodalee
 
Standard Template Library (STL) in Object Oriented Programming
Standard Template Library (STL) in Object Oriented ProgrammingStandard Template Library (STL) in Object Oriented Programming
Standard Template Library (STL) in Object Oriented ProgrammingMandeep Singh
 
CountPositiveNumbersInArray.javapackage org.students;import java.pdf
CountPositiveNumbersInArray.javapackage org.students;import java.pdfCountPositiveNumbersInArray.javapackage org.students;import java.pdf
CountPositiveNumbersInArray.javapackage org.students;import java.pdfaparnatiwari291
 
Arrry structure Stacks in data structure
Arrry structure Stacks  in data structureArrry structure Stacks  in data structure
Arrry structure Stacks in data structurelodhran-hayat
 
SumNumbers.java import java.util.Scanner;public class SumNumbe.pdf
SumNumbers.java import java.util.Scanner;public class SumNumbe.pdfSumNumbers.java import java.util.Scanner;public class SumNumbe.pdf
SumNumbers.java import java.util.Scanner;public class SumNumbe.pdfankkitextailes
 
Design patterns in java script, jquery, angularjs
Design patterns in java script, jquery, angularjsDesign patterns in java script, jquery, angularjs
Design patterns in java script, jquery, angularjsRavi Bhadauria
 
Constructors and Destructors
Constructors and DestructorsConstructors and Destructors
Constructors and DestructorsKeyur Vadodariya
 
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source CodeA Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source CodePVS-Studio
 

Similar to Small Lie in Big O (20)

Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?
 
Write the code above and the ones below in netbeans IDE 8.13. (Eli.pdf
Write the code above and the ones below in netbeans IDE 8.13. (Eli.pdfWrite the code above and the ones below in netbeans IDE 8.13. (Eli.pdf
Write the code above and the ones below in netbeans IDE 8.13. (Eli.pdf
 
maxbox starter60 machine learning
maxbox starter60 machine learningmaxbox starter60 machine learning
maxbox starter60 machine learning
 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4
 
C++11 - STL Additions
C++11 - STL AdditionsC++11 - STL Additions
C++11 - STL Additions
 
05. Java Loops Methods and Classes
05. Java Loops Methods and Classes05. Java Loops Methods and Classes
05. Java Loops Methods and Classes
 
rrxv6 Build a Riscv xv6 Kernel in Rust.pdf
rrxv6 Build a Riscv xv6 Kernel in Rust.pdfrrxv6 Build a Riscv xv6 Kernel in Rust.pdf
rrxv6 Build a Riscv xv6 Kernel in Rust.pdf
 
Thread
ThreadThread
Thread
 
Lezione03
Lezione03Lezione03
Lezione03
 
Lezione03
Lezione03Lezione03
Lezione03
 
Standard Template Library (STL) in Object Oriented Programming
Standard Template Library (STL) in Object Oriented ProgrammingStandard Template Library (STL) in Object Oriented Programming
Standard Template Library (STL) in Object Oriented Programming
 
CountPositiveNumbersInArray.javapackage org.students;import java.pdf
CountPositiveNumbersInArray.javapackage org.students;import java.pdfCountPositiveNumbersInArray.javapackage org.students;import java.pdf
CountPositiveNumbersInArray.javapackage org.students;import java.pdf
 
Arrry structure Stacks in data structure
Arrry structure Stacks  in data structureArrry structure Stacks  in data structure
Arrry structure Stacks in data structure
 
3.Lesson Plan - Input.pdf.pdf
3.Lesson Plan - Input.pdf.pdf3.Lesson Plan - Input.pdf.pdf
3.Lesson Plan - Input.pdf.pdf
 
05-stack_queue.ppt
05-stack_queue.ppt05-stack_queue.ppt
05-stack_queue.ppt
 
SumNumbers.java import java.util.Scanner;public class SumNumbe.pdf
SumNumbers.java import java.util.Scanner;public class SumNumbe.pdfSumNumbers.java import java.util.Scanner;public class SumNumbe.pdf
SumNumbers.java import java.util.Scanner;public class SumNumbe.pdf
 
201801 CSE240 Lecture 13
201801 CSE240 Lecture 13201801 CSE240 Lecture 13
201801 CSE240 Lecture 13
 
Design patterns in java script, jquery, angularjs
Design patterns in java script, jquery, angularjsDesign patterns in java script, jquery, angularjs
Design patterns in java script, jquery, angularjs
 
Constructors and Destructors
Constructors and DestructorsConstructors and Destructors
Constructors and Destructors
 
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source CodeA Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
 

More from Mateusz Pusz

Free Lunch is Over: Why is C++ so Important in the Modern World?
Free Lunch is Over: Why is C++ so Important in the Modern World?Free Lunch is Over: Why is C++ so Important in the Modern World?
Free Lunch is Over: Why is C++ so Important in the Modern World?Mateusz Pusz
 
A Physical Units Library for the Next C++
A Physical Units Library for the Next C++A Physical Units Library for the Next C++
A Physical Units Library for the Next C++Mateusz Pusz
 
Striving for ultimate Low Latency
Striving for ultimate Low LatencyStriving for ultimate Low Latency
Striving for ultimate Low LatencyMateusz Pusz
 
Rethinking the Way We do Templates in C++
Rethinking the Way We do Templates in C++Rethinking the Way We do Templates in C++
Rethinking the Way We do Templates in C++Mateusz Pusz
 
C++11 Was Only the Beginning
C++11 Was Only the BeginningC++11 Was Only the Beginning
C++11 Was Only the BeginningMateusz Pusz
 
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++Mateusz Pusz
 
Effective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variantEffective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variantMateusz Pusz
 
Implementing Physical Units Library for C++
Implementing Physical Units Library for C++Implementing Physical Units Library for C++
Implementing Physical Units Library for C++Mateusz Pusz
 
C++ Concepts and Ranges - How to use them?
C++ Concepts and Ranges - How to use them?C++ Concepts and Ranges - How to use them?
C++ Concepts and Ranges - How to use them?Mateusz Pusz
 
Effective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variantEffective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variantMateusz Pusz
 
Git, CMake, Conan - How to ship and reuse our C++ projects?
Git, CMake, Conan - How to ship and reuse our C++ projects?Git, CMake, Conan - How to ship and reuse our C++ projects?
Git, CMake, Conan - How to ship and reuse our C++ projects?Mateusz Pusz
 
Pointless Pointers - How to make our interfaces efficient?
Pointless Pointers - How to make our interfaces efficient?Pointless Pointers - How to make our interfaces efficient?
Pointless Pointers - How to make our interfaces efficient?Mateusz Pusz
 
Striving for ultimate Low Latency
Striving for ultimate Low LatencyStriving for ultimate Low Latency
Striving for ultimate Low LatencyMateusz Pusz
 
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
std::shared_ptr<T> - (not so) Smart hammer for every pointy nailstd::shared_ptr<T> - (not so) Smart hammer for every pointy nail
std::shared_ptr<T> - (not so) Smart hammer for every pointy nailMateusz Pusz
 

More from Mateusz Pusz (15)

Free Lunch is Over: Why is C++ so Important in the Modern World?
Free Lunch is Over: Why is C++ so Important in the Modern World?Free Lunch is Over: Why is C++ so Important in the Modern World?
Free Lunch is Over: Why is C++ so Important in the Modern World?
 
A Physical Units Library for the Next C++
A Physical Units Library for the Next C++A Physical Units Library for the Next C++
A Physical Units Library for the Next C++
 
Striving for ultimate Low Latency
Striving for ultimate Low LatencyStriving for ultimate Low Latency
Striving for ultimate Low Latency
 
Rethinking the Way We do Templates in C++
Rethinking the Way We do Templates in C++Rethinking the Way We do Templates in C++
Rethinking the Way We do Templates in C++
 
C++11 Was Only the Beginning
C++11 Was Only the BeginningC++11 Was Only the Beginning
C++11 Was Only the Beginning
 
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
 
Effective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variantEffective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variant
 
Implementing Physical Units Library for C++
Implementing Physical Units Library for C++Implementing Physical Units Library for C++
Implementing Physical Units Library for C++
 
C++ Concepts and Ranges - How to use them?
C++ Concepts and Ranges - How to use them?C++ Concepts and Ranges - How to use them?
C++ Concepts and Ranges - How to use them?
 
Effective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variantEffective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variant
 
Git, CMake, Conan - How to ship and reuse our C++ projects?
Git, CMake, Conan - How to ship and reuse our C++ projects?Git, CMake, Conan - How to ship and reuse our C++ projects?
Git, CMake, Conan - How to ship and reuse our C++ projects?
 
Beyond C++17
Beyond C++17Beyond C++17
Beyond C++17
 
Pointless Pointers - How to make our interfaces efficient?
Pointless Pointers - How to make our interfaces efficient?Pointless Pointers - How to make our interfaces efficient?
Pointless Pointers - How to make our interfaces efficient?
 
Striving for ultimate Low Latency
Striving for ultimate Low LatencyStriving for ultimate Low Latency
Striving for ultimate Low Latency
 
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
std::shared_ptr<T> - (not so) Smart hammer for every pointy nailstd::shared_ptr<T> - (not so) Smart hammer for every pointy nail
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
 

Recently uploaded

DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)Samir Dash
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMKumar Satyam
 
Less Is More: Utilizing Ballerina to Architect a Cloud Data Platform
Less Is More: Utilizing Ballerina to Architect a Cloud Data PlatformLess Is More: Utilizing Ballerina to Architect a Cloud Data Platform
Less Is More: Utilizing Ballerina to Architect a Cloud Data PlatformWSO2
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamUiPathCommunity
 
Quantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation ComputingQuantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation ComputingWSO2
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Choreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringChoreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringWSO2
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Bhuvaneswari Subramani
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
Decarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational PerformanceDecarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational PerformanceIES VE
 

Recently uploaded (20)

DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDM
 
Less Is More: Utilizing Ballerina to Architect a Cloud Data Platform
Less Is More: Utilizing Ballerina to Architect a Cloud Data PlatformLess Is More: Utilizing Ballerina to Architect a Cloud Data Platform
Less Is More: Utilizing Ballerina to Architect a Cloud Data Platform
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Quantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation ComputingQuantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation Computing
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Choreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringChoreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software Engineering
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Decarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational PerformanceDecarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational Performance
 

Small Lie in Big O

  • 1. Small Lie in Big O Mateusz Pusz November 15, 2016
  • 2. 2code::dive 2016 Mateusz Pusz ‘sample’ is a simple class containing 8-bit unsigned integral member and a few user defined methods. Integral member inside ‘sample’ class should be initialized during class construction. Implement function ‘test’ that: • takes 2 integral arguments ‘n’ and ‘k’ • creates a collection of ‘n’ ‘sample’ objects with random values assigned • sorts created collection • inserts a new random value keeping the collection sorted (repeat ‘k’ times) • returns average value from all the samples in the collection SIMPLE PROGRAMMING PROBLEM
  • 3. 3code::dive 2016 Mateusz Pusz class sample { std::uint8_t value_; public: // more interface... }; ‘sample’ is a simple class containing 8-bit unsigned integral member and a few user defined methods
  • 4. 4code::dive 2016 Mateusz Pusz class sample { std::uint8_t value_; public: explicit constexpr sample(std::uint8_t value) noexcept : value_{value} {} // more interface... }; Integral member inside ‘sample’ class should be initialized during class construction
  • 5. 5code::dive 2016 Mateusz Pusz class sample { std::uint8_t value_; public: explicit constexpr sample(std::uint8_t value) noexcept : value_{value} {} // more interface... }; std::uint8_t test(int n, int k) { } implement a function ‘test’ that takes 2 integral arguments ‘n’ and ‘k’
  • 6. 6code::dive 2016 Mateusz Pusz class sample { std::uint8_t value_; public: explicit constexpr sample(std::uint8_t value) noexcept : value_{value} {} // more interface... }; std::uint8_t test(int n, int k) { // create collection of 'n' random samples // sort the collection // k times insert a new random sample keeping the collection sorted // return average value from samples in the collection } implement a function ‘test’ that …
  • 7. 7code::dive 2016 Mateusz Pusz class sample { std::uint8_t value_; public: explicit constexpr sample(std::uint8_t value) noexcept : value_{value} {} // more interface... // returns stored value constexpr operator std::uint8_t() const noexcept { return value_; } }; “sorting”, “comparing values”, … –> need to extend ‘sample’ interface
  • 8. 8code::dive 2016 Mateusz Pusz using elem_type = sample*; using collection = std::list<elem_type>; “class”, not a fundamental type –> dynamic memory allocation “inserting in the middle”, “sorting”, … –> std::list
  • 9. 9code::dive 2016 Mateusz Pusz std::uint8_t generate() { ... // probably not enough time today to describe the implementation } “random values” –> provide random numbers generator … or use C++11 <random> XKCD way …
  • 10. 10code::dive 2016 Mateusz Pusz collection init_random(int n) { collection samples; for(int i=0; i<num; ++i) samples.emplace_back(new sample{generate()}); return samples; } std::uint8_t test(int n, int k) { // create collection of 'n' random samples auto samples = init_random(n); // ... } creates a collection of ‘n’ ‘sample’ objects with random values assigned O(n)
  • 11. 11code::dive 2016 Mateusz Pusz std::uint8_t test(int n, int k) { // create collection of 'n' random samples auto samples = init_random(n); // sort the collection values.sort([](const auto& l, const auto& r) { return *l < *r; }); // ... } sorts created collection O(nlogn)
  • 12. 12code::dive 2016 Mateusz Pusz std::uint8_t test(int n, int k) { // ... // k times insert a new random sample keeping the collection sorted for(int i=0; i<k; ++i) { const sample new_sample{generate()}; samples.emplace( ), new sample{new_sample}); } // ... } std::uint8_t test(int n, int k) { // ... // k times insert a new random sample keeping the collection sorted for(int i=0; i<k; ++i) { const sample new_sample{generate()}; samples.emplace(find_if(begin(samples), end(samples), ), new sample{new_sample}); } // ... } std::uint8_t test(int n, int k) { // ... // k times insert a new random sample keeping the collection sorted for(int i=0; i<k; ++i) { const sample new_sample{generate()}; samples.emplace(find_if(begin(samples), end(samples), [&](const auto& s) { return new_sample < *s; }), new sample{new_sample}); } // ... } inserts a new random value keeping the collection sorted (repeat ‘k’ times) O(k * (n+k))
  • 13. 13code::dive 2016 Mateusz Pusz std::uint8_t test(int n, int k) { // ... // return average value from samples in the collection return std::accumulate(begin(samples), end(samples), std::uint64_t{}, [](const auto& sum, const auto& s){ return sum + *s; }) / samples.size(); } returns average value from all the samples in the collection O(n)
  • 14. 14code::dive 2016 Mateusz Pusz std::uint8_t test(int n, int k) { // create collection of 'n' random samples auto samples = init_random(n); // sort the collection samples.sort([](const auto& l, const auto& r) { return *l < *r; }); // k times insert a new random sample keeping the collection sorted for(int i = 0; i < k; ++i) { const sample new_sample{generate()}; samples.emplace(find_if(begin(samples), end(samples), [&](const auto& s) { return new_sample < *s; }), new sample{new_sample}); } // return average value from samples in the collection return std::accumulate(begin(samples), end(samples), std::uint64_t{}, [](const auto& sum, const auto& s){ return sum + *s; }) / samples.size(); } Whole code Do you see a problem?
  • 15. 15code::dive 2016 Mateusz Pusz std::uint8_t test(int n, int k) { // create collection of 'n' random samples auto samples = init_random(n); // sort the collection samples.sort([](const auto& l, const auto& r) { return *l < *r; }); // k times insert a new random sample keeping the collection sorted for(int i = 0; i < k; ++i) { const sample new_sample{generate()}; samples.emplace(find_if(begin(samples), end(samples), [&](const auto& s) { return new_sample < *s; }), new sample{new_sample}); } // return average value from samples in the collection return std::accumulate(begin(samples), end(samples), std::uint64_t{}, [](const auto& sum, const auto& s){ return sum + *s; }) / samples.size(); } Whole code Do you see a problem?
  • 16. 16code::dive 2016 Mateusz Pusz We have a memory leak here
  • 17. 17code::dive 2016 Mateusz Pusz std::uint8_t test(int n, int k) { // ... // cleanup the collection for(auto& s : samples) delete s; } Adding cleanup is simple, right?
  • 18. 18code::dive 2016 Mateusz Pusz std::uint8_t test(int n, int k) { // create collection of 'n' random samples auto samples = init_random(n); // sort the collection samples.sort([](const auto& l, const auto& r) { return *l < *r; }); // k times insert a new random sample keeping the collection sorted for(int i = 0; i < k; ++i) { const sample new_sample{generate()}; samples.emplace(find_if(begin(samples), end(samples), [&](const auto& s) { return new_sample < *s; }), new sample{new_sample}); } // return average value from samples in the collection auto avg = std::accumulate(begin(samples), end(samples), std::uint64_t{}, [](const auto& sum, const auto& s){ return sum + *s; }) / samples.size(); // cleanup the collection for(auto& s : samples) delete s; return avg; } Whole code Do you see a problem?
  • 19. 19code::dive 2016 Mateusz Pusz std::uint8_t test(int n, int k) { // create collection of 'n' random samples auto samples = init_random(n); // sort the collection samples.sort([](const auto& l, const auto& r) { return *l < *r; }); // k times insert a new random sample keeping the collection sorted for(int i = 0; i < k; ++i) { const sample new_sample{generate()}; samples.emplace(find_if(begin(samples), end(samples), [&](const auto& s) { return new_sample < *s; }), new sample{new_sample}); } // return average value from samples in the collection auto avg = std::accumulate(begin(samples), end(samples), std::uint64_t{}, [](const auto& sum, const auto& s){ return sum + *s; }) / samples.size(); // cleanup the collection for(auto& s : samples) delete s; return avg; } Whole code Do you see a problem?
  • 20. 20code::dive 2016 Mateusz Pusz The code is not exception safe!!!
  • 21. 21code::dive 2016 Mateusz Pusz class resource { // resource handle public: resource(/* args */) { /* obtain ownership of a resource and store the handle */ } ~resource() { /* reclaim the resource */ } }; If you dissect the words of the RAII acronym (Resource Acquisition Is Initialization), you will think RAII is about acquiring resources during initialization. However the power of RAII comes not from tying acquisition to initialization, but from tying reclamation to destruction. -- Bjarne Stroustrup RESOURCE ACQUISITION IS INITIALIZATION (RAII)
  • 22. 22code::dive 2016 Mateusz Pusz • Smart Pointers – std::unique_ptr<T, Deleter = std::default_delete<T>> – std::shared_ptr<T> – std::weak_ptr<T> – std::auto_ptr<T> • Containers – all STL containers manage ownership of their data • File streams • Mutex locks – std::lock_guard<Mutex> – std::unique_lock<Mutex> • More… RAII USAGE IN C++ STANDARD LIBRARY
  • 23. 23code::dive 2016 Mateusz Pusz using elem_type = std::unique_ptr<sample>; // ... // replace all new sample{...} // with std::make_unique<sample>(...) std::uint8_t test(int n, int k) { // ... // cleanup the collection for(auto& s : samples) delete s; } Let’s fix our code to be C++ exception safe Writing exception safe code is not that hard at all!!!
  • 24. 24code::dive 2016 Mateusz Pusz Solution test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000) Original 10,7s 104,5s 32,6s Change 1 9,3s 57,1s 16,4s Change 2 0,75s 1,7s 0,37s Change 3 0,75s 0,98s 0,21s Speedup 14x 106x 155x Can we make our code faster? TWEAKING ‘N’ IN ‘F(N)’
  • 25. 25code::dive 2016 Mateusz Pusz Solution test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000) Original 10,7s 104,5s 32,6s Change #1 9,3s 57,1s 16,4s Change #2 0,75s 1,7s 0,37s Change #3 0,75s 0,98s 0,21s Speedup 14x 106x 155x Can we make our code faster? Yes, A LOT faster TWEAKING ‘N’ IN ‘F(N)’
  • 26. 26code::dive 2016 Mateusz Pusz using elem_type = sample*; using collection = std::list<elem_type>; “class”, not a fundamental type –> dynamic memory allocation “inserting in the middle”, “sorting”, … –> std::list WRONG!!!
  • 27. 27code::dive 2016 Mateusz Pusz • Heap usage should be avoided if possible – allocation and deallocation of heap memory is slow – obtaining data from non-cached memory is slow – heap allocation can fail – allocation of many small objects causes huge memory fragmentation • C++ loves value semantics – using pointers changes semantics of copy, assignment and equality – pointer dereferencing takes time – much easier to write thread-safe code – reference/pointer semantics causes aliasing problems • compiler optimizer cannot do its best -> slower code – Copy Elision (RVO) and Move Semantics improve things a lot C++ IS NOT C# OR JAVA
  • 28. 28code::dive 2016 Mateusz Pusz Avoid pointers using elem_type = sample; // ... std::uint8_t test(int n, int k) { // ... samples.sort([](const auto& l, const auto& r) { return *l < *r; }); // ... auto avg = std::accumulate(begin(samples), end(samples), std::uint64_t{}, [](const auto& sum, const auto& s){ return sum + *s; }) / samples.size(); // ... } 1.15x-2x speedup CHANGE #1
  • 29. 29code::dive 2016 Mateusz Pusz Use std::vector<T> as a default container using collection = std::vector<elem_type>; collection init_random(int n, int k) { collection samples; samples.reserve(n + k); for(int i=0; i<n; ++i) samples.emplace_back(generate()); return samples; } 12x-44x speedup. Why? std::uint8_t test(int n, int k) { // create collection of 'n' random samples auto samples = init_random(n, k); // ... // sort the collection sort(begin(samples), end(samples)); // ... } CHANGE #2
  • 30. 30code::dive 2016 Mateusz Pusz Operation std::list<T> std::vector<T> create container of 'n' random values O(n) O(n) sort container O(nlogn) O(nlogn) 'k' times insert a new random value keeping the container sorted O(k * (n+k)) O(k * (n+k)) verify if sorted O(n+k) O(n+k) Overall complexity O(k * (n+k)) O(k * (n+k)) 12x-44x speedup. Why? ALGORITHMIC POINT OF VIEW
  • 31. 31code::dive 2016 Mateusz Pusz T prev next T prev next T prev next std::list<T>
  • 32. 32code::dive 2016 Mateusz Pusz • easy to insert new elements • easy to erase existing elements • easy to reorder elements • bidirectional iteration • memory ineffective – for small T large memory overhead – a lot of dynamic memory allocations and deallocations – a lot of pointer dereferences during iteration – not cache friendly std::list<T> T prev next T prev nextT prev next T prev next
  • 33. 33code::dive 2016 Mateusz Pusz std::list<int> ITERATION prev* next* int pad M E M O R Y CPU cache
  • 34. 34code::dive 2016 Mateusz Pusz { reserved } • inserting new elements – end – easy (unless buffer reallocation is needed) – begin, middle – hard • erasing existing elements – end – easy – begin, middle – hard • swapping values needed to reorder elements • random access iteration • memory effective – small memory overhead (reserved space) – nearly no dynamic memory allocations and deallocations – no pointer dereferences during iteration – cache friendly!!! std::vector<T> T T T T T T T T T T T T
  • 35. 35code::dive 2016 Mateusz Pusz int CPU cache Writing cache friendly code makes a huge difference! std::vector<int> ITERATION M E M O R Y
  • 36. 36code::dive 2016 Mateusz Pusz Performance counter stats for './test_list': 83991,294231 task-clock (msec) # 0,999 CPUs utilized 213901565783 cycles # 2,547 GHz 27748493084 instructions # 0,13 insn per cycle 8472128537 branches # 100,869 M/sec 61763769 branch-misses # 0,73% of all branches 8822212776 L1-dcache-loads # 105,037 M/sec 4799991469 L1-dcache-load-misses # 54,41% of all L1-dcache hits 4177763046 LLC-loads # 49,740 M/sec 550506468 LLC-load-misses # 13,18% of all LL-cache hits 78237 page-faults # 0,931 K/sec Performance counter stats for './test_vector': 2826,385943 task-clock (msec) # 0,999 CPUs utilized 7462656329 cycles # 2,640 GHz 27117855932 instructions # 3,63 insn per cycle 7396349132 branches # 2616,893 M/sec 39248559 branch-misses # 0,53% of all branches 6466518567 L1-dcache-loads # 2287,911 M/sec 77800147 L1-dcache-load-misses # 1,20% of all L1-dcache hits 89304 LLC-loads # 0,032 M/sec 36469 LLC-load-misses # 40,84% of all LL-cache hits 1050 page-faults # 0,371 K/sec LISTVECTOR
  • 37. 37code::dive 2016 Mateusz Pusz L1 cache reference 0.5 ns Branch misprediction 5 ns L2 cache reference 7 ns 14x L1 cache Mutex lock/unlock 25 ns Main memory reference 100 ns 20x L2 cache, 200x L1 cache Compress 1K bytes with Zippy 3,000 ns Send 1K bytes over 1 Gbps network 10,000 ns Read 4K randomly from SSD 150,000 ns Read 1 MB sequentially from memory 250,000 ns Round trip within same datacenter 500,000 ns Read 1 MB sequentially from SSD 1,000,000 ns 4X memory Disk seek 10,000,000 ns 20x datacenter roundtrip Read 1 MB sequentially from disk 20,000,000 ns 80x memory, 20X SSD Send packet CA->Netherlands->CA 150,000,000 ns Latency Numbers Every Programmer Should Know -- Jeff Dean
  • 38. 38code::dive 2016 Mateusz Pusz std::uint8_t test(int n, int k) { // create collection of 'n' random samples // sort the collection // k times insert a new random sample keeping the collection sorted // return average value from samples in the collection } §25.4.3.1 template<class ForwardIterator, class T> ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value); 1 Requires: The elements e of [first,last) shall be partitioned with respect to the expression e < value 2 Returns: The furthermost iterator i in the range [first,last] such that for every iterator j in the range [first,i) the following corresponding conditions hold: *j < value. 3 Complexity: At most log2(last − first) + O(1) comparisons. A NEW POSSIBILITY FOR ALGORITHMIC OPTIMIZATION
  • 39. 39code::dive 2016 Mateusz Pusz Know and use C++ algorithms std::uint8_t test(int n, int k) { // ... // k times insert a new random sample keeping the collection sorted for(int i=0; i<k; ++i) { const sample new_sample{generate()}; samples.emplace(lower_bound(begin(samples), end(samples), new_sample), new_sample); } // ... } 1x-1.7x speedup CHANGE #3
  • 40. 40code::dive 2016 Mateusz Pusz collection init_random(int n, int k) { collection samples; samples.reserve(n + k); for(int i=0; i<n; ++i) samples.emplace_back(generate()); return samples; } std::uint8_t test(int n, int k) { auto samples = init_random(n, k); sort(begin(samples), end(samples)); // k times insert a new random sample keeping the collection sorted for(int i=0; i<k; ++i) { const sample new_sample{generate()}; samples.emplace(lower_bound(begin(samples), end(samples), new_sample), new_sample); } return std::accumulate(begin(samples), end(samples), std::uint64_t{}) / samples.size(); } Isn’t it a great example of efficient programming? Whole code
  • 41. 41code::dive 2016 Mateusz Pusz QUOTES FROM THE C++ COMMUNITY Using std::map is an exercise in slowing down code. If you think link list is bad... maps are worse.
  • 42. 42code::dive 2016 Mateusz Pusz Metric vector multiset vector multiset vector multiset task-clock [msec] 765 9162 Instructions [insn/cycle] 1,33 0,31 L1-dcache-loads [M/sec] 645,8 189,6 L1-dcache-load-misses 0,39% 29,91% LLC-loads [M/sec] 0,074 37,9 LLC-load-misses 37,55% 18,61% page-faults [K/sec] 1 11 std::multiset<sample> usage test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
  • 43. 43code::dive 2016 Mateusz Pusz Metric vector multiset vector multiset vector multiset task-clock [msec] 765 9162 Instructions [insn/cycle] 1,33 0,31 3,86 0,60 L1-dcache-loads [M/sec] 645,8 189,6 2557,5 326,3 L1-dcache-load-misses 0,39% 29,91% 1,03% 12,06% LLC-loads [M/sec] 0,074 37,9 0,035 17,7 LLC-load-misses 37,55% 18,61% 22,45% 16,84% page-faults [K/sec] 1 11 0,14 23 std::multiset<sample> usage test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
  • 44. 44code::dive 2016 Mateusz Pusz Metric vector multiset vector multiset vector multiset task-clock [msec] 765 9162 978 46 Instructions [insn/cycle] 1,33 0,31 3,86 0,60 L1-dcache-loads [M/sec] 645,8 189,6 2557,5 326,3 L1-dcache-load-misses 0,39% 29,91% 1,03% 12,06% LLC-loads [M/sec] 0,074 37,9 0,035 17,7 LLC-load-misses 37,55% 18,61% 22,45% 16,84% page-faults [K/sec] 1 11 0,14 23 std::multiset<sample> usage test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
  • 45. 45code::dive 2016 Mateusz Pusz Metric vector multiset vector multiset vector multiset task-clock [msec] 765 9162 978 46 212 61 Instructions [insn/cycle] 1,33 0,31 3,86 0,60 3,70 0,59 L1-dcache-loads [M/sec] 645,8 189,6 2557,5 326,3 2598,5 367,6 L1-dcache-load-misses 0,39% 29,91% 1,03% 12,06% 1,45% 19,20% LLC-loads [M/sec] 0,074 37,9 0,035 17,7 0,084 16,9 LLC-load-misses 37,55% 18,61% 22,45% 16,84% 21,07% 8,38% page-faults [K/sec] 1 11 0,14 23 0,67 23 std::multiset<sample> usage test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000)
  • 46. 46code::dive 2016 Mateusz Pusz Solution test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000) Original 10,7s 104,5s 32,6s Change #1 9,3s 57,1s 16,4s Change #2 0,75s 1,7s 0,37s Change #3 0,75s 0,98s 0,21s Speedup 14x 106x 155x Can we make our code faster? TWEAKING ‘N’ IN ‘F(N)’
  • 47. 47code::dive 2016 Mateusz Pusz Solution test(10 000 000, 0) test(0, 100 000) test(100 000, 10 000) Original 10,7s 104,5s 32,6s Change #1 9,3s 57,1s 16,4s Change #2 0,75s 1,7s 0,37s Change #3 0,75s 0,98s 0,21s Bonus #1 8,9s 0,04s 0,05s Bonus #2 1,7s 0,04s 0,02s Speedup ??? 2 612x 1 630x Can we make our code faster? TWEAKING ‘N’ IN ‘F(N)’
  • 48. 48code::dive 2016 Mateusz Pusz std::multiset<sample> usage using collection = std::multiset<elem_type>; // ... std::uint8_t test(int n, int k) { // ... sort(begin(samples), end(samples)); // ... samples.emplace(lower_bound(begin(samples), end(samples), new_sample), new_sample); // ... } 0.08x-24x speedup Bonus #1
  • 49. 49code::dive 2016 Mateusz Pusz std::multiset<sample> + std::vector<sample> usage using collection1 = std::vector<elem_type>; using collection2 = std::multiset<elem_type>; // ... std::uint8_t test(int n, int k) { // create collection of 'n' random samples collection1 samples1 = init_random(n, k); // sort the collection sort(begin(samples1), end(samples1)); collection2 samples2{begin(samples1), end(samples1)}; // ... } Bonus #2
  • 50. 50code::dive 2016 Mateusz Pusz TAKE AWAYS
  • 51. Learn C++ to be a more efficient programmer • containers, • algorithms, • new C++11/C++14/C++17 features
  • 52. Use RAII design pattern as your first resort tool for management of all resources
  • 53. Use tools provided by the C++ standard or C++ community Do not reinvent the wheel!!!
  • 54. Remember that memory access is the bottleneck of many today’s applications! Limit pointers usage Write cache friendly code Photograph by Mauro Sartori
  • 55. Always meassure your code if you care for performance! Do not do premature optimizations based only on your assumptions (algorithms, CPU cache friendliness or others)
  • 56. 56code::dive 2016 Mateusz Pusz Questions?
  • 57.
  • 58. 58code::dive 2016 Mateusz Pusz BONUS SLIDE
  • 59. 59code::dive 2016 Mateusz Pusz template<typename T> auto make_random_int_generator(T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max(), std::mt19937::result_type seed = std::mt19937::default_seed) { static_assert(std::is_integral_v<T>); std::mt19937 gen{seed}; std::uniform_int_distribution<T> distr{min, maxs}; return [=]() mutable { return distr(gen); }; } std::uint8_t generate() { static auto generator = make_random_int_generator<std::uint8_t>(); return generator(); } PSEUDO-RANDOM NUMBERS GENERATOR