First taste of google/benchmark

Today, I tried google/benchmark. The build process is idiomatic:

# git clone https://github.com/google/benchmark.git
# git clone https://github.com/google/googletest.git benchmark/googletest
# cd benchmark/
# mkdir build
# cd build/
# cmake ..
# make

But the “make test” generates an error (please refer this issue). Write a simple test.cc:

# cat test.cc
#include <benchmark/benchmark.h>

static void BM_StringCreation(benchmark::State& state) {
  for (auto _ : state)
    std::string empty_string;
}
// Register the function as a benchmark
BENCHMARK(BM_StringCreation);

// Define another benchmark
static void BM_StringCopy(benchmark::State& state) {
  std::string x = "hello";
  for (auto _ : state)
    std::string copy(x);
}
BENCHMARK(BM_StringCopy);

BENCHMARK_MAIN();

Build and run it:

# g++ -pthread test.cc -o test -lbenchmark
# ./test
2018-04-30 18:14:59
Running ./test
Run on (2 X 2394 MHz CPU s)
CPU Caches:
  L1 Data 32K (x2)
  L1 Instruction 32K (x2)
  L2 Unified 4096K (x1)
***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead.
***WARNING*** Library was built as DEBUG. Timings may be affected.
---------------------------------------------------------
Benchmark                  Time           CPU Iterations
---------------------------------------------------------
BM_StringCreation         10 ns         10 ns   71084124
BM_StringCopy             52 ns         52 ns   10000000

Maybe I will take a plunge in this project further.

Small examples show copy elision in C++

“return value optimization” is a common technique of copy elision whose target is eliminating unnecessary copying of objects. Check the following example:

#include <iostream>
using namespace std;

class Foo {
public:
    Foo() {cout<<"default constructor is called"<<endl;}
    Foo(const Foo& other) {cout<<"copy constructor is called"<<endl;}
    Foo(Foo&& other) {cout<<"move constructor is called"<<endl;}
};

Foo func()
{
    Foo f;
    return f;
}

int main()
{
    Foo a = func();
    return 0;
}

The compiler is clang 5.0.1:

# c++ --version
OpenBSD clang version 5.0.1 (tags/RELEASE_501/final) (based on LLVM 5.0.1)
Target: amd64-unknown-openbsd6.3
Thread model: posix
InstalledDir: /usr/bin

Build an execute it:

# c++ -std=c++11 test.cpp
# ./a.out
default constructor is called

You may expect Foo‘ copy constructor is called at least once:

Foo a = func();

However, the reality is that compiler may be clever enough to know the content in local variable f of func() will be finally copied to a, so it creates a first, and pass a into func(), like this:

Foo a;
func(&a);

Let’s modify the program:

#include <iostream>
using namespace std;

class Foo {
public:
    Foo() {cout<<"default constructor is called"<<endl;}
    Foo(const Foo& other) {cout<<"copy constructor is called"<<endl;}
    Foo(Foo&& other) {cout<<"move constructor is called"<<endl;}
};

Foo func(Foo f)
{
    return f;
}

int main()
{
    Foo a;
    Foo b = func(a);
    return 0;
}

This time, the temp variable f of func() is a parameter. Build and run it:

# c++ -std=c++11 test.cpp
# ./a.out
default constructor is called
copy constructor is called
move constructor is called

the temp variable fof func() is constructed by copy constructor:

Foo b = func(a);

In above statement, the func(a) returns a temporary variable, which is a rvalue, so the Foo‘s move constructor is used to construct b. If Foo doesn’t define move constructor:

Foo(Foo&& other) {cout<<"move constructor is called"<<endl;}

Then “Foo b = func(a);” will trigger copy constructor to initialize b.

A performance issue about copy constructor

These two day, I debugged a performance issue which is related to copy constructor: the class A has a member b which is NTL::ZZX type:

class A
{
    enum class type {zzx_t, ...} t;
    NTL::ZZX b;
    ......
}

When member t‘s value is zzx_t, b is valid. Otherwise b‘s content should be outdated.

There are 2 methods of implementing A‘s copy constructor:
(1)

A(const A& other) : t(other.t), b(other.b)
{
    ......
}

In this method, NTL::ZZX‘s copy constructor is called in spite of anything.

(2)

A(const A& other) : t(other.t)
{
    ......
    if (t == zzx_t)
    {
        b = other.b;
    }
    .....
}

In this case, NTL::ZZX‘s default constructor is called first. NTL::ZZX‘s copy assignment operator is invoked only if “t == zzx_t” condition is met.

NTL::ZZX‘s default constructor nearly does nothing, and copy constructor does approximate work as copy assignment operator. But in our scenario, t‘s value is not zzx_t at 80 percent of the time. So the second implementation of copy constructor gets a big performance boost compared to first one.

Install vtop on OpenBSD

vtop is a tool which gives you an intuition of CPU/memory usage during a period. This post introduces how to install it on OpenBSD (assuming working asroot account):

(1) Install node.js (refer here):

# pkg_add node

(2) Install vtop:

# npm install -g vtop

(3) Since vtop uses Unicode braille characters to CPU and Memory charts, I need to change OpenBSD to use UTF-8 encoding (refer here and here):

export LC_CTYPE="en_US.UTF-8"

Now, vtop works well on my Cygwin terminal:

Capture

The work flow of using github

This post is a reference about how to contribute to others’ github projects:

(1) Fork the project into your account:

1(2) Clone your project, and enter the directory:

$ git clone https://github.com/<username>/project.git
$ cd project

Set the upstream:

$ git remote add upstream https://github.com/<upstream>/project.git
$ git remote set-url --push upstream no-pushing

(3) Synchronize the upstream and origin branch timely:

$ git pull upstream master

(4) If you want to submit “Pull Request”, create a new branch based on master and develop in this branch:

$ git checkout master
$ git checkout -b patch-1
$ vi README.md
$ git commit -a -m "Edited README"
$ git push origin patch-1

(5) Then you can send “Pull Request” to upstream:

2

Reference:
swarm/CONTRIBUTING.md.