Click here to Skip to main content
15,867,320 members
Articles / Programming Languages / C++17
Tip/Trick

C++17: Benchmark of Singular Min/Max and Iterator Versions

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
16 Jan 2020CPOL 5.4K   29   1   2
Benchmark of Singular Min/Max and Iterator Versions

Introduction

In this tip, we'll benchmark native </> operator with singular min()/max() and iterator versions like min_element()/max_element(). Lastly, we benchmark the combined operations with minmax_element().

This is the benchmark code:

C++
const size_t MAX_LOOP = (argc == 2) ? atoi(argv[1]) : 1000;

using int_type = uint64_t;
std::vector<int_type> vec(1000000);
std::iota(vec.begin(), vec.end(), 1);
std::random_device rd;
std::mt19937 g(rd());

std::shuffle(vec.begin(), vec.end(), g);
timer stopwatch;

stopwatch.start("manual min");
int_type min = vec[0];
for (size_t k = 0; k < MAX_LOOP; ++k)
{
    min = vec[0];
    for (auto n : vec)
    {
        if (n < min)
            min = n;
    }
}
stopwatch.stop(min);

stopwatch.start("std min");
min = vec[0];
for (size_t k = 0; k < MAX_LOOP; ++k)
{
    min = vec[0];
    for (auto n : vec)
        min = std::min(n, min);
}
stopwatch.stop(min);

stopwatch.start("std min_element");
min = vec[0];
for (size_t k = 0; k < MAX_LOOP; ++k)
{
    min = vec[0];
    min = * std::min_element(vec.cbegin(), vec.cend());
}
stopwatch.stop(min);

std::cout << std::endl;

stopwatch.start("manual max");
int_type max = vec[0];
for (size_t k = 0; k < MAX_LOOP; ++k)
{
    max = vec[0];
    for (auto n : vec)
    {
        if (n > max)
            max = n;
    }
}
stopwatch.stop(max);

stopwatch.start("std max");
max = vec[0];
for (size_t k = 0; k < MAX_LOOP; ++k)
{
    max = vec[0];
    for (auto n : vec)
        max = std::max(n, max);
}
stopwatch.stop(max);

stopwatch.start("std max_element");
max = vec[0];
for (size_t k = 0; k < MAX_LOOP; ++k)
{
    max = vec[0];
    max = *std::max_element(vec.cbegin(), vec.cend());
}
stopwatch.stop(max);

std::cout << std::endl;

stopwatch.start("manual min max");
for (size_t k = 0; k < MAX_LOOP; ++k)
{
    min = vec[0];
    max = vec[0];
    for (auto n : vec)
    {
        if (n < min)
            min = n;
        if (n > max)
            max = n;
    }
}
stopwatch.stop(min, max);

stopwatch.start("std min & max");
for (size_t k = 0; k < MAX_LOOP; ++k)
{
    min = vec[0];
    max = vec[0];
    for (auto n : vec)
    {
        min = std::min(n, min);
        max = std::max(n, max);
    }
}
stopwatch.stop(min, max);

stopwatch.start("std minmax_element");
std::pair<std::vector<int_type>::const_iterator, std::vector<int_type>::const_iterator> minmax;
for (size_t k = 0; k < MAX_LOOP; ++k)
{
    minmax = std::minmax_element(vec.cbegin(), vec.cend());
}
stopwatch.stop(*minmax.first, *minmax.second);

The benchmark is done on Intel i7-8700 CPU at 3.2GHz. Clang++ and G++ benchmark is built and run on Windows Subsystem for Linux(WSL)(Ubuntu 18.04 version) on Windows 10 update 19.10. The timing is based on 1 billion iterations.

VC++ update 16.4, /Ox

From the Visual C++ results, we can see the iterator versions are consistently slower than the native </> operators and min()/max(). In other words, iterator versions are not worth the trouble to use them.

        manual min:  592ms, result:1
           std min:  630ms, result:1
   std min_element: 1889ms, result:1

        manual max:  832ms, result:1000000
           std max:  585ms, result:1000000
   std max_element: 1891ms, result:1000000

    manual min max:  816ms, result:1,1000000
     std min & max:  762ms, result:1,1000000
std minmax_element: 2143ms, result:1,1000000

Clang++ 6.0.0, -O3

From the Clang++ results, the iterator version of min_element() and minmax_element() performs better than singular version.

        manual min:  521ms, result:1
           std min:  419ms, result:1
   std min_element:  386ms, result:1

        manual max:  416ms, result:1000000
           std max:  445ms, result:1000000
   std max_element:  428ms, result:1000000

    manual min max:  701ms, result:1,1000000
     std min & max:  969ms, result:1,1000000
std minmax_element:  514ms, result:1,1000000

G++ 7.4.0, -O3

For G++, we can just stick to </> operators for min/max since their results comes neck to neck. From the results, minmax_element() is to be avoided since it performs worse than the combined </> and min()/max().

        manual min:  801ms, result:1
           std min:  810ms, result:1
   std min_element:  808ms, result:1

        manual max:  566ms, result:1000000
           std max:  552ms, result:1000000
   std max_element:  555ms, result:1000000

    manual min max:  799ms, result:1,1000000
     std min & max:  796ms, result:1,1000000
std minmax_element: 2052ms, result:1,1000000

History

  • 16th January, 2020: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Singapore Singapore
Shao Voon is from Singapore. His interest lies primarily in computer graphics, software optimization, concurrency, security, and Agile methodologies.

In recent years, he shifted focus to software safety research. His hobby is writing a free C++ DirectX photo slideshow application which can be viewed here.

Comments and Discussions

 
QuestionSmall optimization Pin
Mircea Neacsu17-Jan-20 14:40
Mircea Neacsu17-Jan-20 14:40 
AnswerRe: Small optimization Pin
Shao Voon Wong17-Jan-20 21:18
mvaShao Voon Wong17-Jan-20 21:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.