mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2026-10-28 18:07:12 +08:00
[libyuv] Pilot OpenMP support for row processing
Add SetMaxThreads() and GetMaxThreads() APIs (with LIBYUV_NUM_THREADS environment variable override, defaulting to half of logical cores capped at 8 when built with -fopenmp). Enable OpenMP parallel row processing for large frames (>= 1280x720) in I420ToARGBMatrix and CopyPlane (including reshaping coalesced contiguous planes across threads), and configure thread counts for ComputeHammingDistance, ComputeSumSquareError, and CalcFrameSsim. 1280x720 Benchmarks (ms): Benchmark Reps 1T 2T 4T 8T Speedup -------------------------------------------------------- I420ToARGB_Opt 1000 272 162 88 60 4.53x CopyPlane_Opt 1000 57 42 19 14 4.07x BenchmarkPsnr_Opt 1000 92 76 56 34 2.71x BenchmarkSsim_Opt 100 518 241 147 89 5.82x R=rrwinterton@gmail.com Bug: none Test: libyuv_unittest --gtest_filter=*TestSetMaxThreads*:*I420ToARGB_Opt*:*CopyPlane_Opt*:*Ssim* Change-Id: I5ca9a2b8c68eaac870da6353c51306930d015c3a CONV=a7f09b98-93ab-4652-a8eb-8d9551361f61 TAG=agy
This commit is contained in:
parent
700f153cb8
commit
f310cb6ce1
@ -66,3 +66,4 @@ You can also repeat the test a specified number of iterations, allowing benchmar
|
||||
set LIBYUV_REPEAT=999
|
||||
set LIBYUV_FLAGS=-1
|
||||
set LIBYUV_CPU_INFO=-1
|
||||
set LIBYUV_NUM_THREADS=4
|
||||
|
||||
@ -150,6 +150,16 @@ static __inline void SetCpuFlags(int cpu_flags) {
|
||||
LIBYUV_API
|
||||
void CpuId(int info_eax, int info_ecx, int* cpu_info);
|
||||
|
||||
// Set maximum number of threads for OpenMP.
|
||||
// 0 = auto (default: half of logical cores, capped at 8).
|
||||
// Returns the number of threads configured.
|
||||
LIBYUV_API
|
||||
int SetMaxThreads(int num_threads);
|
||||
|
||||
// Get maximum number of threads for OpenMP.
|
||||
LIBYUV_API
|
||||
int GetMaxThreads(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
} // namespace libyuv
|
||||
|
||||
@ -200,7 +200,7 @@ uint64_t ComputeHammingDistance(const uint8_t* src_a,
|
||||
remainder = count & (kBlockSize - 1) & ~(simd_size - 1);
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel for reduction(+ : diff)
|
||||
#pragma omp parallel for reduction(+ : diff) num_threads(GetMaxThreads())
|
||||
#endif
|
||||
for (i = 0; i < (count - (kBlockSize - 1)); i += kBlockSize) {
|
||||
diff += HammingDistance(src_a + i, src_b + i, kBlockSize);
|
||||
@ -275,7 +275,7 @@ uint64_t ComputeSumSquareError(const uint8_t* src_a,
|
||||
#endif
|
||||
remainder = count & (kBlockSize - 1) & ~(simd_size - 1);
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel for reduction(+ : sse)
|
||||
#pragma omp parallel for reduction(+ : sse) num_threads(GetMaxThreads())
|
||||
#endif
|
||||
for (i = 0; i < (count - (kBlockSize - 1)); i += kBlockSize) {
|
||||
sse += SumSquareError(src_a + i, src_b + i, kBlockSize);
|
||||
@ -532,7 +532,8 @@ double CalcFrameSsim(const uint8_t* src_a,
|
||||
const int rem_width = tile_width & (simd_size - 1);
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel reduction(+ : ssim_total, samples)
|
||||
#pragma omp parallel reduction(+ : ssim_total, samples) \
|
||||
num_threads(GetMaxThreads())
|
||||
#endif
|
||||
{
|
||||
align_buffer_64(row_buf, (size_t)tile_width * 2 * sizeof(uint32_t));
|
||||
|
||||
@ -13,6 +13,9 @@
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h> // For memcpy.
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "libyuv/convert_from_argb.h"
|
||||
#include "libyuv/cpu_id.h"
|
||||
@ -155,6 +158,23 @@ int I420ToARGBMatrix(const uint8_t* src_y,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_OPENMP)
|
||||
{
|
||||
int num_threads = GetMaxThreads();
|
||||
int use_omp = (num_threads > 1) &&
|
||||
((ptrdiff_t)width * height >= 1280 * 720) &&
|
||||
(height >= num_threads);
|
||||
#pragma omp parallel for schedule(static) num_threads(num_threads) if (use_omp)
|
||||
for (y = 0; y < height; ++y) {
|
||||
const uint8_t* row_src_y = src_y + (ptrdiff_t)y * src_stride_y;
|
||||
const uint8_t* row_src_u = src_u + (ptrdiff_t)(y >> 1) * src_stride_u;
|
||||
const uint8_t* row_src_v = src_v + (ptrdiff_t)(y >> 1) * src_stride_v;
|
||||
uint8_t* row_dst_argb = dst_argb + (ptrdiff_t)y * dst_stride_argb;
|
||||
I422ToARGBRow(row_src_y, row_src_u, row_src_v, row_dst_argb, yuvconstants,
|
||||
width);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (y = 0; y < height; ++y) {
|
||||
I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
|
||||
dst_argb += dst_stride_argb;
|
||||
@ -164,6 +184,7 @@ int I420ToARGBMatrix(const uint8_t* src_y,
|
||||
src_v += src_stride_v;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -20,8 +20,12 @@
|
||||
#endif
|
||||
|
||||
// For ArmCpuCaps() but unittested on all platforms
|
||||
#include <stdio.h> // For fopen()
|
||||
#include <stdio.h> // For fopen()
|
||||
#include <stdlib.h> // For getenv(), atoi()
|
||||
#include <string.h>
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && (defined(__aarch64__) || defined(__loongarch__))
|
||||
#include <sys/auxv.h> // For getauxval()
|
||||
@ -521,6 +525,54 @@ int InitCpuFlags(void) {
|
||||
return MaskCpuFlags(-1);
|
||||
}
|
||||
|
||||
#if defined(_OPENMP)
|
||||
static int max_threads_ = 0;
|
||||
#endif
|
||||
|
||||
LIBYUV_API
|
||||
int SetMaxThreads(int num_threads) {
|
||||
#if defined(_OPENMP)
|
||||
if (num_threads <= 0) {
|
||||
int procs = omp_get_num_procs();
|
||||
if (procs <= 2) {
|
||||
num_threads = 1;
|
||||
} else if (procs <= 4) {
|
||||
num_threads = 2;
|
||||
} else {
|
||||
num_threads = procs / 2; // Avoid hyperthreads and avoid consuming host
|
||||
if (num_threads > 8) {
|
||||
num_threads = 8; // Prevent memory channel saturation
|
||||
}
|
||||
}
|
||||
}
|
||||
max_threads_ = num_threads;
|
||||
omp_set_num_threads(num_threads);
|
||||
return num_threads;
|
||||
#else
|
||||
(void)num_threads;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBYUV_API
|
||||
int GetMaxThreads(void) {
|
||||
#if defined(_OPENMP)
|
||||
if (max_threads_ <= 0) {
|
||||
const char* env_threads = getenv("LIBYUV_NUM_THREADS");
|
||||
if (env_threads) {
|
||||
int t = atoi(env_threads);
|
||||
if (t > 0) {
|
||||
return SetMaxThreads(t);
|
||||
}
|
||||
}
|
||||
return SetMaxThreads(0);
|
||||
}
|
||||
return max_threads_;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
} // namespace libyuv
|
||||
|
||||
@ -13,6 +13,9 @@
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h> // for memset()
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "libyuv/convert_from_argb.h" // For ArgbConstants
|
||||
#include "libyuv/cpu_id.h"
|
||||
@ -24,6 +27,28 @@ namespace libyuv {
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_OPENMP)
|
||||
// Reshape coalesced 1D buffer into a 2D rectangle for parallel row processing.
|
||||
static void ComputeParallelShape(int total_bytes,
|
||||
int num_threads,
|
||||
int* out_width,
|
||||
int* out_height) {
|
||||
const int kAlign = 64;
|
||||
if (num_threads > 1 && total_bytes >= 1280 * 720) {
|
||||
int total_blocks = total_bytes / kAlign;
|
||||
int blocks_per_thread = total_blocks / num_threads;
|
||||
if (blocks_per_thread > 0 &&
|
||||
blocks_per_thread * num_threads == total_blocks) {
|
||||
*out_width = blocks_per_thread * kAlign;
|
||||
*out_height = num_threads;
|
||||
return;
|
||||
}
|
||||
}
|
||||
*out_width = total_bytes;
|
||||
*out_height = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy a plane of data
|
||||
LIBYUV_API
|
||||
void CopyPlane(const uint8_t* src_y,
|
||||
@ -46,9 +71,15 @@ void CopyPlane(const uint8_t* src_y,
|
||||
// Coalesce rows.
|
||||
if (src_stride_y == width && dst_stride_y == width &&
|
||||
(ptrdiff_t)width * height <= INT_MAX) {
|
||||
#if defined(_OPENMP)
|
||||
int num_threads = GetMaxThreads();
|
||||
ComputeParallelShape(width * height, num_threads, &width, &height);
|
||||
src_stride_y = dst_stride_y = (height > 1) ? width : 0;
|
||||
#else
|
||||
width *= height;
|
||||
height = 1;
|
||||
src_stride_y = dst_stride_y = 0;
|
||||
#endif
|
||||
}
|
||||
// Nothing to do.
|
||||
if (src_y == dst_y && src_stride_y == dst_stride_y) {
|
||||
@ -112,11 +143,25 @@ void CopyPlane(const uint8_t* src_y,
|
||||
#endif
|
||||
|
||||
// Copy plane
|
||||
#if defined(_OPENMP)
|
||||
{
|
||||
int num_threads = GetMaxThreads();
|
||||
int use_omp = (num_threads > 1) &&
|
||||
((ptrdiff_t)width * height >= 1280 * 720) &&
|
||||
(height >= num_threads);
|
||||
#pragma omp parallel for schedule(static) num_threads(num_threads) if (use_omp)
|
||||
for (y = 0; y < height; ++y) {
|
||||
CopyRow(src_y + (ptrdiff_t)y * src_stride_y,
|
||||
dst_y + (ptrdiff_t)y * dst_stride_y, width);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (y = 0; y < height; ++y) {
|
||||
CopyRow(src_y, dst_y, width);
|
||||
src_y += src_stride_y;
|
||||
dst_y += dst_stride_y;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBYUV_API
|
||||
|
||||
@ -463,4 +463,22 @@ TEST_F(LibYUVBaseTest, MAYBE_TestSetCpuFlags) {
|
||||
MaskCpuFlags(benchmark_cpu_info_);
|
||||
}
|
||||
|
||||
TEST_F(LibYUVBaseTest, TestSetMaxThreads) {
|
||||
#ifdef _OPENMP
|
||||
printf("_OPENMP %d\n", _OPENMP);
|
||||
#endif
|
||||
int default_threads = GetMaxThreads();
|
||||
printf("Max Threads %d\n", default_threads);
|
||||
EXPECT_GE(default_threads, 1);
|
||||
|
||||
int threads_1 = SetMaxThreads(1);
|
||||
EXPECT_EQ(1, threads_1);
|
||||
EXPECT_EQ(1, GetMaxThreads());
|
||||
|
||||
int restored_threads = SetMaxThreads(0);
|
||||
EXPECT_GE(restored_threads, 1);
|
||||
EXPECT_LE(restored_threads, 8);
|
||||
EXPECT_EQ(restored_threads, GetMaxThreads());
|
||||
}
|
||||
|
||||
} // namespace libyuv
|
||||
|
||||
@ -61,6 +61,7 @@ int main(int argc, const char* argv[]) {
|
||||
printf("Kernel Version %d.%d\n", kernelversion[0], kernelversion[1]);
|
||||
}
|
||||
#endif // defined(__linux__)
|
||||
printf("Max Threads %d\n", GetMaxThreads());
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
int has_arm = TestCpuFlag(kCpuHasARM);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user