Fix slower CV_PAUSE on SkyLake and above.
authorVincent Rabaud <vrabaud@google.com>
Thu, 15 Dec 2022 11:28:30 +0000 (12:28 +0100)
committerVincent Rabaud <vrabaud@google.com>
Thu, 15 Dec 2022 13:18:57 +0000 (14:18 +0100)
This is fixing https://github.com/opencv/opencv/issues/22852

modules/core/src/parallel_impl.cpp

index 1d9690b04c1f1b0353969ce5bbfec82db7f3353a..087b41233badc1616b6aeb0101e5ab8be617ac8e 100644 (file)
@@ -52,11 +52,14 @@ DECLARE_CV_PAUSE
 #endif
 #ifndef CV_PAUSE
 # if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
+#   include <x86intrin.h> /* for __rdtsc */
 #   if !defined(__SSE2__)
       static inline void cv_non_sse_mm_pause() { __asm__ __volatile__ ("rep; nop"); }
 #     define _mm_pause cv_non_sse_mm_pause
 #   endif
-#   define CV_PAUSE(v) do { for (int __delay = (v); __delay > 0; --__delay) { _mm_pause(); } } while (0)
+// 5 * v is meants for backward compatibility: with pre-Skylake CPUs, _mm_pause took 4 or 5 cycles.
+// With post-Skylake CPUs, _mm_pause takes 140 cycles.
+#   define CV_PAUSE(v) do { const uint64_t __delay = 5 * v; uint64_t __init = __rdtsc(); do { _mm_pause(); } while ((__rdtsc() - __init) < __delay); } while (0)
 # elif defined __GNUC__ && defined __aarch64__
 #   define CV_PAUSE(v) do { for (int __delay = (v); __delay > 0; --__delay) { asm volatile("yield" ::: "memory"); } } while (0)
 # elif defined __GNUC__ && defined __arm__