Skip to content

Use std::chrono::steady_clock in getTickCount#22217

Merged
asmorkalov merged 2 commits intoopencv:3.4from
CSharperMantle:CSharperMantle-patch-steady-clock
Aug 3, 2022
Merged

Use std::chrono::steady_clock in getTickCount#22217
asmorkalov merged 2 commits intoopencv:3.4from
CSharperMantle:CSharperMantle-patch-steady-clock

Conversation

@CSharperMantle
Copy link
Copy Markdown
Contributor

@CSharperMantle CSharperMantle commented Jul 8, 2022

This PR enables the use of std::chrono::steady_clock on supported compilers as a source to retrieve the current tick count and clock frequency in a cross-platform way.

Resolves #6902.

Pull Request Readiness Checklist

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • There is a reference to the original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

@CSharperMantle CSharperMantle changed the title Use std::chrono::steady_clock in getTickCount() Use std::chrono::steady_clock in getTickCount() Jul 8, 2022
@CSharperMantle CSharperMantle changed the title Use std::chrono::steady_clock in getTickCount() Use std::chrono::steady_clock in getTickCount Jul 8, 2022
Add conditional compilation directives to enable uses of std::chrono on supported compilers. Use std::chrono::steady_clock as a source to retrieve current tick count and clock frequency.

Fixes opencv#6902.
@CSharperMantle CSharperMantle force-pushed the CSharperMantle-patch-steady-clock branch from c334f4c to db70676 Compare July 9, 2022 02:43
@CSharperMantle
Copy link
Copy Markdown
Contributor Author

I am particularly concerned about possible name clashes with macros.

In the patch, I store the result of __cplusplus >= 201103L in a macro named HAVE_CXX11, but it is a common name among libraries. Are there any better ways to detect C++11? Any suggestions will be appreciated.

@CSharperMantle CSharperMantle force-pushed the CSharperMantle-patch-steady-clock branch from 11de6af to fa613e3 Compare July 10, 2022 11:22
@asmorkalov asmorkalov requested a review from alalek July 29, 2022 06:50
@CSharperMantle
Copy link
Copy Markdown
Contributor Author

CSharperMantle commented Jul 29, 2022

One job failed due to a non-existent repository, CSharperMantle/opencv_contrib, but I suppose that it is not necessary for me to fork such repository. Are there any actions I should take, or it indicates a bug in the workflow?

@alalek
Copy link
Copy Markdown
Member

alalek commented Jul 29, 2022

To merge this patch we need to ensure that there is no unwanted performance regression against the existed code.
So we need microbenchmark results on major systems: Linux, Windows, MacOSX.

@CSharperMantle
Copy link
Copy Markdown
Contributor Author

@alalek, unfortunately I don't an macOS X system, and my Linux system is quite atypical. May I ask whether the benchmarks should be carried out myself, or by your build farm?

@CSharperMantle
Copy link
Copy Markdown
Contributor Author

CSharperMantle commented Jul 31, 2022

Benchmark 1: Windows

Code

The following benchmark code utilizes macros to switch among different implementations of getTickCount.

#include <chrono>
#include <cstdint>
#include <iostream>

#if defined(BENCH_IS_WINDOWS)
#include <windows.h>
#elif defined(BENCH_IS_MACH)    
#include <mach/mach_time.h>
#elif defined(BENCH_IS_UNIX)
#include <time.h>
#else
#include <sys/time.h>
#endif

#define RUN_COUNT 10000000

std::int64_t getTickCount()
{
#if defined(BENCH_IS_CXX11)
    std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
    return (std::int64_t)now.time_since_epoch().count();
#elif defined(BENCH_IS_WINDOWS)
    LARGE_INTEGER counter;
    QueryPerformanceCounter(&counter);
    return (std::int64_t)counter.QuadPart;
#elif defined(BENCH_IS_MACH)
    return (std::int64_t)mach_absolute_time();
#elif defined(BENCH_IS_UNIX)
    struct timespec tp;
    clock_gettime(CLOCK_MONOTONIC, &tp);
    return (std::int64_t)tp.tv_sec * 1000000000 + tp.tv_nsec;
#else
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (std::int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
#endif
}

int main(int, char **)
{
    volatile std::int64_t tmp = 0;

    std::cout << "Defined macros: ";
#if defined(BENCH_IS_CXX11)
    std::cout << "BENCH_IS_CXX11 ";
#elif defined(BENCH_IS_WINDOWS)
    std::cout << "BENCH_IS_WINDOWS ";
#elif defined(BENCH_IS_MACH)
    std::cout << "BENCH_IS_MACH ";
#elif defined(BENCH_IS_UNIX)
    std::cout << "BENCH_IS_UNIX ";
#else
    std::cout << "<none> ";
#endif
    std::cout << '\n';

    auto before = std::chrono::steady_clock::now();
    for (size_t i = 0; i < RUN_COUNT; i++)
    {
        tmp = getTickCount();
    }
    auto after = std::chrono::steady_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(after - before);

    std::cout << "Total time (ns): " << duration.count()
              << ", Avg time (ns): " << duration.count() / RUN_COUNT
              << '\n';

    return 0;
}

Environment

  • OS: Windows 10.0.10586
  • CPU: Intel Core i3-4010U @ 1.70GHz, 1700 Mhz, 2C4T
  • Compiler: g++.exe (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0

Compiling commands:

g++ -std=c++11 -DBENCH_IS_UNIX -O0 -o bench_unix.exe .\bench_getTickCount.cpp
g++ -std=c++11 -DBENCH_IS_CXX11 -O0 -o bench_cxx11.exe .\bench_getTickCount.cpp
g++ -std=c++11 -DBENCH_IS_WINDOWS -O0 -o bench_windows.exe .\bench_getTickCount.cpp
g++ -std=c++11 -O0 -o bench_default.exe .\bench_getTickCount.cpp

Result

BENCH_IS_CXX11 BENCH_IS_UNIX BENCH_IS_WINDOWS <none>
Total (ns) 6618392421 6523856314 5999175594 970594447
Avg (ns) 661 652 599 97

The italicized column is the default implementation originally used on such platform; bold column is the fastest.

Raw:

PS F:\Workspace\bench> .\bench_cxx11.exe
Defined macros: BENCH_IS_CXX11
Total time (ns): 6618392421, Avg time (ns): 661
PS F:\Workspace\bench> .\bench_unix.exe
Defined macros: BENCH_IS_UNIX
Total time (ns): 6523856314, Avg time (ns): 652
PS F:\Workspace\bench> .\bench_windows.exe
Defined macros: BENCH_IS_WINDOWS
Total time (ns): 5999175594, Avg time (ns): 599
PS F:\Workspace\bench> .\bench_default.exe
Defined macros: <none>
Total time (ns): 970594447, Avg time (ns): 97
PS F:\Workspace\bench>

Benchmark 2: (Embedded) Linux

Environment

  • OS: Linux galileo 3.8.7-yocto-standard # 1 Tue Jun 9 22:07:14 GMT 2015 i586 GNU/Linux
  • CPU: Intel Quark SoC X1000 @ 400MHz, 1C1T
  • Compiler: g++ (GCC) 4.9.1

Compilation commands:

g++ -std=c++11 -DBENCH_IS_UNIX -O0 -o bench_unix ./bench_getTickCount.cpp
g++ -std=c++11 -DBENCH_IS_CXX11 -O0 -o bench_cxx11 ./bench_getTickCount.cpp
g++ -std=c++11 -O0 -o bench_default ./bench_getTickCount.cpp
g++ -std=c++11 -DBENCH_IS_UNIX -O3 -o bench_unix_opt ./bench_getTickCount.cpp
g++ -std=c++11 -DBENCH_IS_CXX11 -O3 -o bench_cxx11_opt ./bench_getTickCount.cpp
g++ -std=c++11 -O3 -o bench_default_opt ./bench_getTickCount.cpp

Result

BENCH_IS_CXX11 BENCH_IS_UNIX <none>
O0 Tot (ns) 42904347510 38211202301 36838514197
O0 Avg (ns) 4290 3821 3683
O3 Tot (ns) 39006813398 34951421319 33929480957
O3 Avg (ns) 3900 3495 3392

Raw:

root@galileo:~/bench# ./bench_cxx11
Defined macros: BENCH_IS_CXX11
Total time (ns): 42904347510, Avg time (ns): 4290
root@galileo:~/bench# ./bench_cxx11_opt
Defined macros: BENCH_IS_CXX11
Total time (ns): 39006813398, Avg time (ns): 3900
root@galileo:~/bench# ./bench_unix
Defined macros: BENCH_IS_UNIX
Total time (ns): 38211202301, Avg time (ns): 3821
root@galileo:~/bench# ./bench_unix_opt
Defined macros: BENCH_IS_UNIX
Total time (ns): 34951421319, Avg time (ns): 3495
root@galileo:~/bench# ./bench_default
Defined macros: <none>
Total time (ns): 36838514197, Avg time (ns): 3683
root@galileo:~/bench# ./bench_default_opt
Defined macros: <none>
Total time (ns): 33929480957, Avg time (ns): 3392
root@galileo:~/bench#

@asmorkalov asmorkalov self-requested a review August 3, 2022 11:05
@asmorkalov asmorkalov merged commit 2ffa7ac into opencv:3.4 Aug 3, 2022
This was referenced Aug 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add use of std::chrono::steady_clock into cv::getTickCount implementation when C++11 is available

3 participants