LCOV - code coverage report
Current view: top level - perftests - testperf_gdal_minmax_element.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 388 390 99.5 %
Date: 2026-03-05 10:33:42 Functions: 71 71 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Project:  GDAL Core
       3             :  * Purpose:  Test performance of gdal_minmax_element.hpp
       4             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : 
      12             : #include "gdal_minmax_element.hpp"
      13             : 
      14             : #include <chrono>
      15             : #include <random>
      16             : 
      17          14 : template <class T> void randomFill(T *v, size_t size, bool withNaN = true)
      18             : {
      19          28 :     std::random_device rd;
      20          14 :     std::mt19937 gen{rd()};
      21          14 :     std::normal_distribution<> dist{
      22             :         cpl::NumericLimits<T>::is_signed ? -63 : 127, 30};
      23   140000000 :     for (size_t i = 0; i < size; i++)
      24             :     {
      25   140000000 :         v[i] = static_cast<T>(dist(gen));
      26             :         if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double> ||
      27             :                       std::is_same_v<T, GFloat16>)
      28             :         {
      29    60000000 :             if (withNaN && (i == 0 || (i > 10 && ((i + 1) % 1024) <= 4)))
      30      146478 :                 v[i] = cpl::NumericLimits<T>::quiet_NaN();
      31             :         }
      32             :     }
      33          14 : }
      34             : 
      35             : constexpr size_t SIZE = 10 * 1000 * 1000 + 1;
      36             : constexpr int N_ITERS = 1;
      37             : 
      38          56 : template <class T> inline void ASSERT_EQ(T v_optim, T v_ref)
      39             : {
      40          56 :     if (v_optim != v_ref)
      41             :     {
      42           0 :         fprintf(stderr, "Optim value != ref value\n");
      43           0 :         exit(1);
      44             :     }
      45          56 : }
      46             : 
      47             : template <class T>
      48             : #if defined(__GNUC__)
      49             : __attribute__((noinline))
      50             : #endif
      51           8 : static void benchIntegers(GDALDataType eDT, T noData)
      52             : {
      53          16 :     std::vector<T> x;
      54           8 :     x.resize(SIZE);
      55           8 :     randomFill(x.data(), x.size());
      56             :     T v_optim, v_ref;
      57             :     {
      58           8 :         auto start = std::chrono::steady_clock::now();
      59           8 :         int idx = 0;
      60          16 :         for (int i = 0; i < N_ITERS; ++i)
      61             :         {
      62           8 :             idx += static_cast<int>(
      63           8 :                 gdal::min_element(x.data(), x.size(), eDT, false, 0));
      64             :         }
      65           8 :         idx /= N_ITERS;
      66           8 :         printf("min at idx %d (optimized), val=%s\n", idx,
      67           8 :                std::to_string(x[idx]).c_str());
      68           8 :         auto end = std::chrono::steady_clock::now();
      69           8 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
      70           8 :         v_optim = x[idx];
      71             :     }
      72             :     {
      73           8 :         auto start = std::chrono::steady_clock::now();
      74           8 :         int idx = 0;
      75          16 :         for (int i = 0; i < N_ITERS; ++i)
      76             :         {
      77           8 :             idx += static_cast<int>(
      78           8 :                 std::distance(x.begin(), std::min_element(x.begin(), x.end())));
      79             :         }
      80           8 :         idx /= N_ITERS;
      81           8 :         printf("min at idx %d (using std::min_element), val=%s\n", idx,
      82           8 :                std::to_string(x[idx]).c_str());
      83           8 :         auto end = std::chrono::steady_clock::now();
      84           8 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
      85           8 :         v_ref = x[idx];
      86             :     }
      87           8 :     ASSERT_EQ(v_optim, v_ref);
      88             : 
      89             :     {
      90           8 :         auto start = std::chrono::steady_clock::now();
      91           8 :         int idx = 0;
      92          16 :         for (int i = 0; i < N_ITERS; ++i)
      93             :         {
      94           8 :             idx += static_cast<int>(
      95           8 :                 gdal::min_element(x.data(), x.size(), eDT, true, noData));
      96             :         }
      97           8 :         idx /= N_ITERS;
      98           8 :         printf("min at idx %d (nodata case, optimized), val=%s\n", idx,
      99           8 :                std::to_string(x[idx]).c_str());
     100           8 :         auto end = std::chrono::steady_clock::now();
     101           8 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     102           8 :         v_optim = x[idx];
     103             :     }
     104             :     {
     105           8 :         auto start = std::chrono::steady_clock::now();
     106           8 :         int idx = 0;
     107          16 :         for (int i = 0; i < N_ITERS; ++i)
     108             :         {
     109           8 :             idx += static_cast<int>(std::distance(
     110             :                 x.begin(), std::min_element(x.begin(), x.end(),
     111   160000000 :                                             [noData](T a, T b)
     112             :                                             {
     113   159882000 :                                                 return b == noData   ? true
     114    79882200 :                                                        : a == noData ? false
     115    80000000 :                                                                      : a < b;
     116             :                                             })));
     117             :         }
     118           8 :         idx /= N_ITERS;
     119           8 :         printf("min at idx %d (nodata case, using std::min_element with "
     120             :                "nodata aware comparison), val=%s\n",
     121           8 :                idx, std::to_string(x[idx]).c_str());
     122           8 :         auto end = std::chrono::steady_clock::now();
     123           8 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     124           8 :         v_ref = x[idx];
     125             :     }
     126           8 :     ASSERT_EQ(v_optim, v_ref);
     127             : 
     128             :     {
     129           8 :         auto start = std::chrono::steady_clock::now();
     130           8 :         int idx = 0;
     131          16 :         for (int i = 0; i < N_ITERS; ++i)
     132             :         {
     133           8 :             idx += static_cast<int>(
     134           8 :                 gdal::max_element(x.data(), x.size(), eDT, false, 0));
     135             :         }
     136           8 :         idx /= N_ITERS;
     137           8 :         printf("max at idx %d (optimized), val=%s\n", idx,
     138           8 :                std::to_string(x[idx]).c_str());
     139           8 :         auto end = std::chrono::steady_clock::now();
     140           8 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     141           8 :         v_optim = x[idx];
     142             :     }
     143             :     {
     144           8 :         auto start = std::chrono::steady_clock::now();
     145           8 :         int idx = 0;
     146          16 :         for (int i = 0; i < N_ITERS; ++i)
     147             :         {
     148           8 :             idx += static_cast<int>(
     149           8 :                 std::distance(x.begin(), std::max_element(x.begin(), x.end())));
     150             :         }
     151           8 :         idx /= N_ITERS;
     152           8 :         printf("max at idx %d (using std::max_element), val=%s\n", idx,
     153           8 :                std::to_string(x[idx]).c_str());
     154           8 :         auto end = std::chrono::steady_clock::now();
     155           8 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     156           8 :         v_ref = x[idx];
     157             :     }
     158           8 :     ASSERT_EQ(v_optim, v_ref);
     159             : 
     160             :     {
     161           8 :         auto start = std::chrono::steady_clock::now();
     162           8 :         int idx = 0;
     163          16 :         for (int i = 0; i < N_ITERS; ++i)
     164             :         {
     165           8 :             idx += static_cast<int>(
     166           8 :                 gdal::max_element(x.data(), x.size(), eDT, true, noData));
     167             :         }
     168           8 :         idx /= N_ITERS;
     169           8 :         printf("max at idx %d (nodata case, optimized), val=%s\n", idx,
     170           8 :                std::to_string(x[idx]).c_str());
     171           8 :         auto end = std::chrono::steady_clock::now();
     172           8 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     173           8 :         v_optim = x[idx];
     174             :     }
     175             :     {
     176           8 :         auto start = std::chrono::steady_clock::now();
     177           8 :         int idx = 0;
     178          16 :         for (int i = 0; i < N_ITERS; ++i)
     179             :         {
     180           8 :             idx += static_cast<int>(std::distance(
     181             :                 x.begin(), std::max_element(x.begin(), x.end(),
     182   160000000 :                                             [noData](T a, T b)
     183             :                                             {
     184   159882000 :                                                 return a == noData   ? true
     185    79882200 :                                                        : b == noData ? false
     186    80000000 :                                                                      : a < b;
     187             :                                             })));
     188             :         }
     189           8 :         idx /= N_ITERS;
     190           8 :         printf("max at idx %d (nodata case, using std::max_element with "
     191             :                "nodata aware comparison), val=%s\n",
     192           8 :                idx, std::to_string(x[idx]).c_str());
     193           8 :         auto end = std::chrono::steady_clock::now();
     194           8 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     195           8 :         v_ref = x[idx];
     196             :     }
     197           8 :     ASSERT_EQ(v_optim, v_ref);
     198           8 : }
     199             : 
     200             : template <class T>
     201             : #if defined(__GNUC__)
     202             : __attribute__((noinline))
     203             : #endif
     204           3 : static void benchFloatingPointsWithNaN(GDALDataType eDT, T noData)
     205             : {
     206           6 :     std::vector<T> x;
     207           3 :     x.resize(SIZE);
     208           3 :     randomFill(x.data(), x.size());
     209             :     T v_optim, v_ref;
     210             : 
     211             :     {
     212           3 :         auto start = std::chrono::steady_clock::now();
     213           3 :         int idx = 0;
     214           6 :         for (int i = 0; i < N_ITERS; ++i)
     215             :         {
     216           3 :             idx += static_cast<int>(
     217           3 :                 gdal::min_element(x.data(), x.size(), eDT, false, 0));
     218             :         }
     219           3 :         idx /= N_ITERS;
     220           3 :         printf("min at idx %d (optimized), val = %g\n", idx,
     221           3 :                static_cast<double>(x[idx]));
     222           3 :         auto end = std::chrono::steady_clock::now();
     223           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     224           3 :         v_optim = x[idx];
     225             :     }
     226             :     {
     227           3 :         auto start = std::chrono::steady_clock::now();
     228           3 :         int idx = 0;
     229           6 :         for (int i = 0; i < N_ITERS; ++i)
     230             :         {
     231           3 :             idx += static_cast<int>(std::distance(
     232             :                 x.begin(), std::min_element(x.begin(), x.end(),
     233    30000000 :                                             [](T a, T b)
     234             :                                             {
     235    79902300 :                                                 return CPLIsNan(b)   ? true
     236    49902300 :                                                        : CPLIsNan(a) ? false
     237    39951200 :                                                                      : a < b;
     238             :                                             })));
     239             :         }
     240           3 :         idx /= N_ITERS;
     241           3 :         printf("min at idx %d (using std::min_element with NaN aware "
     242             :                "comparison), val = %g\n",
     243           3 :                idx, static_cast<double>(x[idx]));
     244           3 :         auto end = std::chrono::steady_clock::now();
     245           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     246           3 :         v_ref = x[idx];
     247             :     }
     248           3 :     ASSERT_EQ(v_optim, v_ref);
     249             : 
     250             :     {
     251           3 :         auto start = std::chrono::steady_clock::now();
     252           3 :         int idx = 0;
     253           6 :         for (int i = 0; i < N_ITERS; ++i)
     254             :         {
     255           3 :             idx += static_cast<int>(
     256           3 :                 gdal::min_element(x.data(), x.size(), eDT, true, noData));
     257             :         }
     258           3 :         idx /= N_ITERS;
     259           3 :         printf("min at idx %d (nodata case, optimized), val = %g\n", idx,
     260           3 :                static_cast<double>(x[idx]));
     261           3 :         auto end = std::chrono::steady_clock::now();
     262           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     263           3 :         v_optim = x[idx];
     264             :     }
     265             :     {
     266           3 :         auto start = std::chrono::steady_clock::now();
     267           3 :         int idx = 0;
     268           6 :         for (int i = 0; i < N_ITERS; ++i)
     269             :         {
     270           3 :             idx += static_cast<int>(std::distance(
     271             :                 x.begin(), std::min_element(x.begin(), x.end(),
     272    69804600 :                                             [noData](T a, T b)
     273             :                                             {
     274    79902300 :                                                 return CPLIsNan(b)   ? true
     275    59853500 :                                                        : CPLIsNan(a) ? false
     276    39804700 :                                                        : b == noData ? true
     277    29853500 :                                                        : a == noData ? false
     278    39951200 :                                                                      : a < b;
     279             :                                             })));
     280             :         }
     281           3 :         idx /= N_ITERS;
     282           3 :         printf("min at idx %d (nodata case, using std::min_element with "
     283             :                "nodata aware and NaN aware comparison), val = %g\n",
     284           3 :                idx, static_cast<double>(x[idx]));
     285           3 :         auto end = std::chrono::steady_clock::now();
     286           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     287           3 :         v_ref = x[idx];
     288             :     }
     289           3 :     ASSERT_EQ(v_optim, v_ref);
     290             : 
     291             :     {
     292           3 :         auto start = std::chrono::steady_clock::now();
     293           3 :         int idx = 0;
     294           6 :         for (int i = 0; i < N_ITERS; ++i)
     295             :         {
     296           3 :             idx += static_cast<int>(
     297           3 :                 gdal::max_element(x.data(), x.size(), eDT, false, 0));
     298             :         }
     299           3 :         idx /= N_ITERS;
     300           3 :         printf("max at idx %d (optimized), val = %g\n", idx,
     301           3 :                static_cast<double>(x[idx]));
     302           3 :         auto end = std::chrono::steady_clock::now();
     303           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     304           3 :         v_optim = x[idx];
     305             :     }
     306             :     {
     307           3 :         auto start = std::chrono::steady_clock::now();
     308           3 :         int idx = 0;
     309           6 :         for (int i = 0; i < N_ITERS; ++i)
     310             :         {
     311           3 :             idx += static_cast<int>(std::distance(
     312             :                 x.begin(), std::max_element(x.begin(), x.end(),
     313    30000000 :                                             [](T a, T b)
     314             :                                             {
     315    79902300 :                                                 return CPLIsNan(a)   ? true
     316    49902300 :                                                        : CPLIsNan(b) ? false
     317    39951200 :                                                                      : a < b;
     318             :                                             })));
     319             :         }
     320           3 :         idx /= N_ITERS;
     321           3 :         printf("max at idx %d (using std::max_element with NaN aware "
     322             :                "comparison), val = %g\n",
     323           3 :                idx, static_cast<double>(x[idx]));
     324           3 :         auto end = std::chrono::steady_clock::now();
     325           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     326           3 :         v_ref = x[idx];
     327             :     }
     328           3 :     ASSERT_EQ(v_optim, v_ref);
     329             : 
     330             :     {
     331           3 :         auto start = std::chrono::steady_clock::now();
     332           3 :         int idx = 0;
     333           6 :         for (int i = 0; i < N_ITERS; ++i)
     334             :         {
     335           3 :             idx += static_cast<int>(
     336           3 :                 gdal::max_element(x.data(), x.size(), eDT, true, noData));
     337             :         }
     338           3 :         idx /= N_ITERS;
     339           3 :         printf("max at idx %d (nodata case, optimized), val = %g\n", idx,
     340           3 :                static_cast<double>(x[idx]));
     341           3 :         auto end = std::chrono::steady_clock::now();
     342           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     343           3 :         v_optim = x[idx];
     344             :     }
     345             :     {
     346           3 :         auto start = std::chrono::steady_clock::now();
     347           3 :         int idx = 0;
     348           6 :         for (int i = 0; i < N_ITERS; ++i)
     349             :         {
     350           3 :             idx += static_cast<int>(std::distance(
     351             :                 x.begin(), std::max_element(x.begin(), x.end(),
     352    69804600 :                                             [noData](T a, T b)
     353             :                                             {
     354    79902300 :                                                 return CPLIsNan(a)   ? true
     355    59853500 :                                                        : CPLIsNan(b) ? false
     356    39804700 :                                                        : a == noData ? true
     357    29853500 :                                                        : b == noData ? false
     358    39951200 :                                                                      : a < b;
     359             :                                             })));
     360             :         }
     361           3 :         idx /= N_ITERS;
     362           3 :         printf("max at idx %d (nodata case, using std::max_element with "
     363             :                "nodata aware and NaN aware comparison), val = %g\n",
     364           3 :                idx, static_cast<double>(x[idx]));
     365           3 :         auto end = std::chrono::steady_clock::now();
     366           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     367           3 :         v_ref = x[idx];
     368             :     }
     369           3 :     ASSERT_EQ(v_optim, v_ref);
     370           3 : }
     371             : 
     372             : template <class T>
     373             : #if defined(__GNUC__)
     374             : __attribute__((noinline))
     375             : #endif
     376           3 : static void benchFloatingPointsWithoutNaN(GDALDataType eDT, T noData)
     377             : {
     378           6 :     std::vector<T> x;
     379           3 :     x.resize(SIZE);
     380           3 :     randomFill(x.data(), x.size(), false);
     381             :     T v_optim, v_ref;
     382             : 
     383             :     {
     384           3 :         auto start = std::chrono::steady_clock::now();
     385           3 :         int idx = 0;
     386           6 :         for (int i = 0; i < N_ITERS; ++i)
     387             :         {
     388           3 :             idx += static_cast<int>(
     389           3 :                 gdal::min_element(x.data(), x.size(), eDT, false, 0));
     390             :         }
     391           3 :         idx /= N_ITERS;
     392           3 :         printf("min at idx %d (optimized), val = %g\n", idx,
     393           3 :                static_cast<double>(x[idx]));
     394           3 :         auto end = std::chrono::steady_clock::now();
     395           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     396           3 :         v_optim = x[idx];
     397             :     }
     398             :     {
     399           3 :         auto start = std::chrono::steady_clock::now();
     400           3 :         int idx = 0;
     401           6 :         for (int i = 0; i < N_ITERS; ++i)
     402             :         {
     403           3 :             idx += static_cast<int>(
     404           3 :                 std::distance(x.begin(), std::min_element(x.begin(), x.end())));
     405             :         }
     406           3 :         idx /= N_ITERS;
     407           3 :         printf("min at idx %d (using std::min_element), val = %g\n", idx,
     408           3 :                static_cast<double>(x[idx]));
     409           3 :         auto end = std::chrono::steady_clock::now();
     410           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     411           3 :         v_ref = x[idx];
     412             :     }
     413           3 :     ASSERT_EQ(v_optim, v_ref);
     414             : 
     415             :     {
     416           3 :         auto start = std::chrono::steady_clock::now();
     417           3 :         int idx = 0;
     418           6 :         for (int i = 0; i < N_ITERS; ++i)
     419             :         {
     420           3 :             idx += static_cast<int>(
     421           3 :                 gdal::min_element(x.data(), x.size(), eDT, true, noData));
     422             :         }
     423           3 :         idx /= N_ITERS;
     424           3 :         printf("min at idx %d (nodata case, optimized), val = %g\n", idx,
     425           3 :                static_cast<double>(x[idx]));
     426           3 :         auto end = std::chrono::steady_clock::now();
     427           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     428           3 :         v_optim = x[idx];
     429             :     }
     430             :     {
     431           3 :         auto start = std::chrono::steady_clock::now();
     432           3 :         int idx = 0;
     433           6 :         for (int i = 0; i < N_ITERS; ++i)
     434             :         {
     435           3 :             idx += static_cast<int>(std::distance(
     436             :                 x.begin(), std::min_element(x.begin(), x.end(),
     437    50000000 :                                             [noData](T a, T b)
     438             :                                             {
     439    60000000 :                                                 return b == noData   ? true
     440    30000000 :                                                        : a == noData ? false
     441    40000000 :                                                                      : a < b;
     442             :                                             })));
     443             :         }
     444           3 :         idx /= N_ITERS;
     445           3 :         printf("min at idx %d (nodata case, using std::min_element with "
     446             :                "nodata aware comparison), val = %g\n",
     447           3 :                idx, static_cast<double>(x[idx]));
     448           3 :         auto end = std::chrono::steady_clock::now();
     449           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     450           3 :         v_ref = x[idx];
     451             :     }
     452           3 :     ASSERT_EQ(v_optim, v_ref);
     453             : 
     454             :     {
     455           3 :         auto start = std::chrono::steady_clock::now();
     456           3 :         int idx = 0;
     457           6 :         for (int i = 0; i < N_ITERS; ++i)
     458             :         {
     459           3 :             idx += static_cast<int>(
     460           3 :                 gdal::max_element(x.data(), x.size(), eDT, false, 0));
     461             :         }
     462           3 :         idx /= N_ITERS;
     463           3 :         printf("max at idx %d (optimized), val = %g\n", idx,
     464           3 :                static_cast<double>(x[idx]));
     465           3 :         auto end = std::chrono::steady_clock::now();
     466           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     467           3 :         v_optim = x[idx];
     468             :     }
     469             :     {
     470           3 :         auto start = std::chrono::steady_clock::now();
     471           3 :         int idx = 0;
     472           6 :         for (int i = 0; i < N_ITERS; ++i)
     473             :         {
     474           3 :             idx += static_cast<int>(
     475           3 :                 std::distance(x.begin(), std::max_element(x.begin(), x.end())));
     476             :         }
     477           3 :         idx /= N_ITERS;
     478           3 :         printf("max at idx %d (using std::max_element), val = %g\n", idx,
     479           3 :                static_cast<double>(x[idx]));
     480           3 :         auto end = std::chrono::steady_clock::now();
     481           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     482           3 :         v_ref = x[idx];
     483             :     }
     484           3 :     ASSERT_EQ(v_optim, v_ref);
     485             : 
     486             :     {
     487           3 :         auto start = std::chrono::steady_clock::now();
     488           3 :         int idx = 0;
     489           6 :         for (int i = 0; i < N_ITERS; ++i)
     490             :         {
     491           3 :             idx += static_cast<int>(
     492           3 :                 gdal::max_element(x.data(), x.size(), eDT, true, noData));
     493             :         }
     494           3 :         idx /= N_ITERS;
     495           3 :         printf("max at idx %d (nodata case, optimized), val = %g\n", idx,
     496           3 :                static_cast<double>(x[idx]));
     497           3 :         auto end = std::chrono::steady_clock::now();
     498           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     499           3 :         v_optim = x[idx];
     500             :     }
     501             :     {
     502           3 :         auto start = std::chrono::steady_clock::now();
     503           3 :         int idx = 0;
     504           6 :         for (int i = 0; i < N_ITERS; ++i)
     505             :         {
     506           3 :             idx += static_cast<int>(std::distance(
     507             :                 x.begin(), std::max_element(x.begin(), x.end(),
     508    50000000 :                                             [noData](T a, T b)
     509             :                                             {
     510    60000000 :                                                 return a == noData   ? true
     511    30000000 :                                                        : b == noData ? false
     512    40000000 :                                                                      : a < b;
     513             :                                             })));
     514             :         }
     515           3 :         idx /= N_ITERS;
     516           3 :         printf("max at idx %d (nodata case, using std::max_element with "
     517             :                "nodata aware comparison), val = %g\n",
     518           3 :                idx, static_cast<double>(x[idx]));
     519           3 :         auto end = std::chrono::steady_clock::now();
     520           3 :         printf("-> elapsed=%d\n", static_cast<int>((end - start).count()));
     521           3 :         v_ref = x[idx];
     522             :     }
     523           3 :     ASSERT_EQ(v_optim, v_ref);
     524           3 : }
     525             : 
     526           1 : int main(int /* argc */, char * /* argv */[])
     527             : {
     528             :     {
     529             :         using T = uint8_t;
     530           1 :         constexpr GDALDataType eDT = GDT_Byte;
     531           1 :         printf("uint8:\n");
     532           1 :         benchIntegers<T>(eDT, 0);
     533             :     }
     534           1 :     printf("--------------------\n");
     535             :     {
     536             :         using T = int8_t;
     537           1 :         constexpr GDALDataType eDT = GDT_Int8;
     538           1 :         printf("int8:\n");
     539           1 :         benchIntegers<T>(eDT, 0);
     540             :     }
     541           1 :     printf("--------------------\n");
     542             :     {
     543             :         using T = uint16_t;
     544           1 :         constexpr GDALDataType eDT = GDT_UInt16;
     545           1 :         printf("uint16:\n");
     546           1 :         benchIntegers<T>(eDT, 0);
     547             :     }
     548           1 :     printf("--------------------\n");
     549             :     {
     550             :         using T = int16_t;
     551           1 :         constexpr GDALDataType eDT = GDT_Int16;
     552           1 :         printf("int16:\n");
     553           1 :         benchIntegers<T>(eDT, 0);
     554             :     }
     555           1 :     printf("--------------------\n");
     556             :     {
     557             :         using T = uint32_t;
     558           1 :         constexpr GDALDataType eDT = GDT_UInt32;
     559           1 :         printf("uint32:\n");
     560           1 :         benchIntegers<T>(eDT, 0);
     561             :     }
     562           1 :     printf("--------------------\n");
     563             :     {
     564             :         using T = int32_t;
     565           1 :         constexpr GDALDataType eDT = GDT_Int32;
     566           1 :         printf("int32:\n");
     567           1 :         benchIntegers<T>(eDT, 0);
     568             :     }
     569           1 :     printf("--------------------\n");
     570             :     {
     571             :         using T = uint64_t;
     572           1 :         constexpr GDALDataType eDT = GDT_UInt64;
     573           1 :         printf("uint64:\n");
     574           1 :         benchIntegers<T>(eDT, 0);
     575             :     }
     576           1 :     printf("--------------------\n");
     577             :     {
     578             :         using T = int64_t;
     579           1 :         constexpr GDALDataType eDT = GDT_Int64;
     580           1 :         printf("int64:\n");
     581           1 :         benchIntegers<T>(eDT, 0);
     582             :     }
     583           1 :     printf("--------------------\n");
     584             :     {
     585             :         using T = GFloat16;
     586           1 :         constexpr GDALDataType eDT = GDT_Float16;
     587           1 :         printf("float16 (*with* NaN):\n");
     588           1 :         benchFloatingPointsWithNaN<T>(eDT, 0);
     589             :     }
     590           1 :     printf("--------------------\n");
     591             :     {
     592             :         using T = GFloat16;
     593           1 :         constexpr GDALDataType eDT = GDT_Float16;
     594           1 :         printf("float16 (without NaN):\n");
     595           1 :         benchFloatingPointsWithoutNaN<T>(eDT, 0);
     596             :     }
     597           1 :     printf("--------------------\n");
     598             :     {
     599             :         using T = float;
     600           1 :         constexpr GDALDataType eDT = GDT_Float32;
     601           1 :         printf("float (*with* NaN):\n");
     602           1 :         benchFloatingPointsWithNaN<T>(eDT, 0);
     603             :     }
     604           1 :     printf("--------------------\n");
     605             :     {
     606             :         using T = float;
     607           1 :         constexpr GDALDataType eDT = GDT_Float32;
     608           1 :         printf("float (without NaN):\n");
     609           1 :         benchFloatingPointsWithoutNaN<T>(eDT, 0);
     610             :     }
     611           1 :     printf("--------------------\n");
     612             :     {
     613             :         using T = double;
     614           1 :         constexpr GDALDataType eDT = GDT_Float64;
     615           1 :         printf("double (*with* NaN):\n");
     616           1 :         benchFloatingPointsWithNaN<T>(eDT, 0);
     617             :     }
     618           1 :     printf("--------------------\n");
     619             :     {
     620             :         using T = double;
     621           1 :         constexpr GDALDataType eDT = GDT_Float64;
     622           1 :         printf("double (without NaN):\n");
     623           1 :         benchFloatingPointsWithoutNaN<T>(eDT, 0);
     624             :     }
     625           1 :     return 0;
     626             : }

Generated by: LCOV version 1.14