Linux测试处理fps为30、1920*1080、一分钟的视频性能

打印 上一主题 下一主题

主题 820|帖子 820|积分 2460

前置条件

模拟fps为30、1920*1080、一分钟的视频
项目CMakeLists.txt
  1. cmake_minimum_required(VERSION 3.30)
  2. project(testOpenGl)
  3. set(CMAKE_CXX_STANDARD 11)
  4. add_executable(testOpenGl main.cpp
  5.         testOpenCl.cpp
  6.         testOpenCl.h
  7.         TestCpp.cpp
  8.         TestCpp.h
  9.         TestCppThread.cpp
  10.         TestCppThread.h
  11.         TestSIMD.cpp
  12.         TestSIMD.h)
  13. # 查找OpenCL
  14. find_package(OpenCL REQUIRED)
  15. # 链接OpenCl库
  16. target_include_directories(testOpenGl PRIVATE ${OpenCL_INCLUDE_DIRS})
  17. target_link_libraries(testOpenGl PRIVATE ${OpenCL_LIBRARIES})
  18. # 检测SIMD支持并添加编译选项
  19. include(CheckCXXCompilerFlag)
  20. check_cxx_compiler_flag("-mavx" COMPILER_SUPPORTS_AVX)
  21. check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2)
  22. if(COMPILER_SUPPORTS_AVX2)
  23.     target_compile_options(testOpenGl PRIVATE -mavx2)
  24. elseif (COMPILER_SUPPORTS_AVX)
  25.     target_compile_options(testOpenGl PRIVATE -mavx)
  26. else ()
  27.     message(FATAL_ERROR "AVX or AVX2 is not supported by compiler")
  28. endif ()
复制代码
C++代码

  1. //
  2. // Created by lai on 2025/1/17.
  3. //
  4. #include "TestCpp.h"
  5. #include <iostream>
  6. #include <vector>
  7. #include <random>
  8. #include <chrono>
  9. // 灰度转换函数
  10. void to_gray(const std::vector<unsigned char>& input, std::vector<unsigned char>& output, int width, int height) {
  11.     for (int i = 0; i < width * height; ++i) {
  12.         int offset = i * 3;  // RGB 分量
  13.         unsigned char r = input[offset];
  14.         unsigned char g = input[offset + 1];
  15.         unsigned char b = input[offset + 2];
  16.         // 灰度公式
  17.         output[i] = static_cast<unsigned char>(0.299f * r + 0.587f * g + 0.114f * b);
  18.     }
  19. }
  20. void TestCpp::runTest() {
  21.     const int width = 1920;         // 视频宽度
  22.     const int height = 1080;        // 视频高度
  23.     const int fps = 30;             // 帧率
  24.     const int duration = 60;        // 视频持续时间(秒)
  25.     const int frameCount = fps * duration; // 总帧数
  26.     // 模拟视频帧数据:随机生成每帧的 RGB 数据
  27.     std::vector<unsigned char> inputFrame(width * height * 3);
  28.     std::vector<unsigned char> outputFrame(width * height);
  29.     std::random_device rd;
  30.     std::mt19937 gen(rd());
  31.     std::uniform_int_distribution<> dis(0, 255);
  32.     // 开始处理
  33.     auto startTime = std::chrono::high_resolution_clock::now();
  34.     for (int frame = 0; frame < frameCount; ++frame) {
  35.         // 随机生成模拟的 RGB 数据
  36.         for (auto& pixel : inputFrame) {
  37.             pixel = dis(gen);
  38.         }
  39.         // 调用灰度转换函数
  40.         to_gray(inputFrame, outputFrame, width, height);
  41.         // 打印进度
  42.         if (frame % 30 == 0) {
  43.             std::cout << "Processed frame: " << frame + 1 << "/" << frameCount << std::endl;
  44.         }
  45.     }
  46.     auto endTime = std::chrono::high_resolution_clock::now();
  47.     double elapsedTime = std::chrono::duration<double>(endTime - startTime).count();
  48.     // 打印处理时间
  49.     std::cout << "Processed " << frameCount << " frames in " << elapsedTime << " seconds." << std::endl;
  50.     std::cout << "Average time per frame: " << (elapsedTime / frameCount) << " seconds." << std::endl;
  51. }
复制代码
C++多线程

  1. //
  2. // Created by lai on 2025/1/17.
  3. //
  4. #include "TestCppThread.h"
  5. #include <iostream>
  6. #include <vector>
  7. #include <random>
  8. #include <chrono>
  9. #include <thread>
  10. // 灰度转换函数,每个线程处理一部分图像
  11. void to_gray_chunk(const std::vector<unsigned char>& input, std::vector<unsigned char>& output, int width, int height, int start, int end) {
  12.     for (int i = start; i < end; ++i) {
  13.         int offset = i * 3;  // RGB 分量
  14.         unsigned char r = input[offset];
  15.         unsigned char g = input[offset + 1];
  16.         unsigned char b = input[offset + 2];
  17.         // 灰度公式
  18.         output[i] = static_cast<unsigned char>(0.299f * r + 0.587f * g + 0.114f * b);
  19.     }
  20. }
  21. void TestCppThread::runTest() {
  22.     const int width = 1920;         // 视频宽度
  23.     const int height = 1080;        // 视频高度
  24.     const int fps = 30;             // 帧率
  25.     const int duration = 60;        // 视频持续时间(秒)
  26.     const int frameCount = fps * duration; // 总帧数
  27.     const int numThreads = std::thread::hardware_concurrency(); // 获取可用线程数
  28.     // 模拟视频帧数据:随机生成每帧的 RGB 数据
  29.     std::vector<unsigned char> inputFrame(width * height * 3);
  30.     std::vector<unsigned char> outputFrame(width * height);
  31.     std::random_device rd;
  32.     std::mt19937 gen(rd());
  33.     std::uniform_int_distribution<> dis(0, 255);
  34.     // 开始处理
  35.     auto startTime = std::chrono::high_resolution_clock::now();
  36.     for (int frame = 0; frame < frameCount; ++frame) {
  37.         // 随机生成模拟的 RGB 数据
  38.         for (auto& pixel : inputFrame) {
  39.             pixel = dis(gen);
  40.         }
  41.         // 启动多个线程来处理图像
  42.         std::vector<std::thread> threads;
  43.         int chunkSize = width * height / numThreads; // 每个线程处理的像素块大小
  44.         for (int t = 0; t < numThreads; ++t) {
  45.             int start = t * chunkSize;
  46.             int end = (t == numThreads - 1) ? (width * height) : (start + chunkSize); // 最后一个线程处理剩余的像素
  47.             threads.emplace_back(to_gray_chunk, std::cref(inputFrame), std::ref(outputFrame), width, height, start, end);
  48.         }
  49.         // 等待所有线程完成
  50.         for (auto& t : threads) {
  51.             t.join();
  52.         }
  53.         // 打印进度
  54.         if (frame % 30 == 0) {
  55.             std::cout << "Processed frame: " << frame + 1 << "/" << frameCount << std::endl;
  56.         }
  57.     }
  58.     auto endTime = std::chrono::high_resolution_clock::now();
  59.     double elapsedTime = std::chrono::duration<double>(endTime - startTime).count();
  60.     // 打印处理时间
  61.     std::cout << "Processed " << frameCount << " frames in " << elapsedTime << " seconds." << std::endl;
  62.     std::cout << "Average time per frame: " << (elapsedTime / frameCount) << " seconds." << std::endl;
  63. }
复制代码
CPU版本的Opencl

cmake中添加
  1. # 查找OpenCL
  2. find_package(OpenCL REQUIRED)
  3. # 链接OpenCl库
  4. target_include_directories(testOpenGl PRIVATE ${OpenCL_INCLUDE_DIRS})
  5. target_link_libraries(testOpenGl PRIVATE ${OpenCL_LIBRARIES})
复制代码
测试代码
  1. //
  2. // Created by lai on 2025/1/16.
  3. //
  4. #include "testOpenCl.h"
  5. #include <chrono>
  6. #include <CL/cl.h>
  7. #include <iostream>
  8. #include <vector>
  9. #include <random>
  10. // OpenCL 内核代码
  11. const char* kernelSource = R"(
  12. __kernel void to_gray(
  13.     __global unsigned char* input,
  14.     __global unsigned char* output,
  15.     const int width,
  16.     const int height)
  17. {
  18.     int id = get_global_id(0);  // 每个线程处理一个像素
  19.     if (id < width * height) {
  20.         int offset = id * 3;  // RGB 分量
  21.         unsigned char r = input[offset];
  22.         unsigned char g = input[offset + 1];
  23.         unsigned char b = input[offset + 2];
  24.         // 灰度公式
  25.         output[id] = (unsigned char)(0.299f * r + 0.587f * g + 0.114f * b);
  26.     }
  27. }
  28. )";
  29. void TestOpenCl::runTests() {
  30.     const int width = 1920;         // 视频宽度
  31.     const int height = 1080;        // 视频高度
  32.     const int fps = 30;             // 帧率
  33.     const int duration = 60;        // 视频持续时间(秒)
  34.     const int frameCount = fps * duration; // 总帧数
  35.     // 模拟视频帧数据:随机生成每帧的 RGB 数据
  36.     std::vector<unsigned char> inputFrame(width * height * 3);
  37.     std::vector<unsigned char> outputFrame(width * height);
  38.     std::random_device rd;
  39.     std::mt19937 gen(rd());
  40.     std::uniform_int_distribution<> dis(0, 255);
  41.     // 初始化 OpenCL
  42.     cl_int err;
  43.     cl_platform_id platform;
  44.     clGetPlatformIDs(1, &platform, nullptr);
  45.     cl_device_id device;
  46.     clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 1, &device, nullptr);
  47.     cl_context context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
  48.     cl_command_queue queue = clCreateCommandQueue(context, device, 0, &err);
  49.     cl_program program = clCreateProgramWithSource(context, 1, &kernelSource, nullptr, &err);
  50.     clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);
  51.     cl_kernel kernel = clCreateKernel(program, "to_gray", &err);
  52.     // 创建 OpenCL 缓冲区
  53.     cl_mem inputBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY, inputFrame.size(), nullptr, &err);
  54.     cl_mem outputBuffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY, outputFrame.size(), nullptr, &err);
  55.     // 开始处理
  56.     auto startTime = std::chrono::high_resolution_clock::now();
  57.     for (int frame = 0; frame < frameCount; ++frame) {
  58.         // 随机生成模拟的 RGB 数据
  59.         for (auto& pixel : inputFrame) {
  60.             pixel = dis(gen);
  61.         }
  62.         // 写入数据到 OpenCL 缓冲区
  63.         clEnqueueWriteBuffer(queue, inputBuffer, CL_TRUE, 0, inputFrame.size(), inputFrame.data(), 0, nullptr, nullptr);
  64.         // 设置内核参数
  65.         clSetKernelArg(kernel, 0, sizeof(cl_mem), &inputBuffer);
  66.         clSetKernelArg(kernel, 1, sizeof(cl_mem), &outputBuffer);
  67.         clSetKernelArg(kernel, 2, sizeof(int), &width);
  68.         clSetKernelArg(kernel, 3, sizeof(int), &height);
  69.         // 定义工作区大小
  70.         size_t globalSize = width * height;
  71.         // 执行内核
  72.         clEnqueueNDRangeKernel(queue, kernel, 1, nullptr, &globalSize, nullptr, 0, nullptr, nullptr);
  73.         // 读取处理后的灰度数据
  74.         clEnqueueReadBuffer(queue, outputBuffer, CL_TRUE, 0, outputFrame.size(), outputFrame.data(), 0, nullptr, nullptr);
  75.         // 打印进度
  76.         if (frame % 30 == 0) {
  77.             std::cout << "Processed frame: " << frame + 1 << "/" << frameCount << std::endl;
  78.         }
  79.     }
  80.     auto endTime = std::chrono::high_resolution_clock::now();
  81.     double elapsedTime = std::chrono::duration<double>(endTime - startTime).count();
  82.     // 打印处理时间
  83.     std::cout << "Processed " << frameCount << " frames in " << elapsedTime << " seconds." << std::endl;
  84.     std::cout << "Average time per frame: " << (elapsedTime / frameCount) << " seconds." << std::endl;
  85.     // 释放 OpenCL 资源
  86.     clReleaseMemObject(inputBuffer);
  87.     clReleaseMemObject(outputBuffer);
  88.     clReleaseKernel(kernel);
  89.     clReleaseProgram(program);
  90.     clReleaseCommandQueue(queue);
  91.     clReleaseContext(context);
  92. }
复制代码
内存对齐的SIMD指令集

cmake添加
  1. # 检测SIMD支持并添加编译选项
  2. include(CheckCXXCompilerFlag)
  3. check_cxx_compiler_flag("-mavx" COMPILER_SUPPORTS_AVX)
  4. check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2)
  5. if(COMPILER_SUPPORTS_AVX2)
  6.     target_compile_options(testOpenGl PRIVATE -mavx2)
  7. elseif (COMPILER_SUPPORTS_AVX)
  8.     target_compile_options(testOpenGl PRIVATE -mavx)
  9. else ()
  10.     message(FATAL_ERROR "AVX or AVX2 is not supported by compiler")
  11. endif ()
复制代码
  1. //
  2. // Created by lai on 2025/1/17.
  3. //
  4. #include "TestSIMD.h"
  5. #include <iostream>
  6. #include <vector>
  7. #include <random>
  8. #include <chrono>
  9. #include <immintrin.h> // SIMD 指令集
  10. #include <cstdlib>  // 用于posix_memalign
  11. void to_gray_simd(const unsigned char* input, unsigned char* output, int width, int height) {
  12.     const int pixelCount = width * height;
  13.     const __m256 scale_r = _mm256_set1_ps(0.299f); // 红色通道的权重
  14.     const __m256 scale_g = _mm256_set1_ps(0.587f); // 绿色通道的权重
  15.     const __m256 scale_b = _mm256_set1_ps(0.114f); // 蓝色通道的权重
  16.     int i = 0;
  17.     for (; i <= pixelCount - 8; i += 8) {
  18.         // 加载 8 组 RGB 像素
  19.         __m256i pixel_r = _mm256_loadu_si256((__m256i*)&input[i * 3]);  // 确保内存对齐
  20.         __m256i pixel_g = _mm256_loadu_si256((__m256i*)&input[i * 3 + 1]);
  21.         __m256i pixel_b = _mm256_loadu_si256((__m256i*)&input[i * 3 + 2]);
  22.         // 转换为浮点数以便计算
  23.         __m256 r_f = _mm256_cvtepi32_ps(pixel_r);
  24.         __m256 g_f = _mm256_cvtepi32_ps(pixel_g);
  25.         __m256 b_f = _mm256_cvtepi32_ps(pixel_b);
  26.         // 灰度转换公式
  27.         __m256 gray_f = _mm256_add_ps(
  28.             _mm256_add_ps(_mm256_mul_ps(r_f, scale_r), _mm256_mul_ps(g_f, scale_g)),
  29.             _mm256_mul_ps(b_f, scale_b));
  30.         // 转回整数
  31.         __m256i gray_i = _mm256_cvtps_epi32(gray_f);
  32.         // 存储结果
  33.         _mm256_storeu_si256((__m256i*)&output[i], gray_i);
  34.     }
  35.     // 处理剩余像素(非对齐部分)
  36.     for (; i < pixelCount; ++i) {
  37.         int offset = i * 3;
  38.         unsigned char r = input[offset];
  39.         unsigned char g = input[offset + 1];
  40.         unsigned char b = input[offset + 2];
  41.         output[i] = static_cast<unsigned char>(0.299f * r + 0.587f * g + 0.114f * b);
  42.     }
  43. }
  44. void TestSIMD::runTest() {
  45.     const int width = 1920;         // 视频宽度
  46.     const int height = 1080;        // 视频高度
  47.     const int fps = 30;             // 帧率
  48.     const int duration = 60;        // 视频持续时间(秒)
  49.     const int frameCount = fps * duration; // 总帧数
  50.     size_t size = width * height * 3 * sizeof(unsigned char);
  51.     // 模拟视频帧数据:随机生成每帧的 RGB 数据
  52.     // 使用posix_memalign分配对齐内存
  53.     unsigned char* inputFrame;
  54.     unsigned char* outputFrame;
  55.     int alignment = 32; // 使用32字节对齐
  56.     int resultInput = posix_memalign((void**)&inputFrame, alignment, size);
  57.     int resultOutput = posix_memalign((void**)&outputFrame, alignment, size);
  58.     if (resultInput != 0 || resultOutput != 0) {
  59.         std::cerr << "memory allocation failed" << std::endl;
  60.         return;
  61.     }
  62.     std::random_device rd;
  63.     std::mt19937 gen(rd());
  64.     std::uniform_int_distribution<> dis(0, 255);
  65.     // 开始处理
  66.     auto startTime = std::chrono::high_resolution_clock::now();
  67.     for (int frame = 0; frame < frameCount; ++frame) {
  68.         // 随机生成模拟的 RGB 数据
  69.         for (int i = 0; i < width * height * 3; ++i) {
  70.             inputFrame[i] = dis(gen);
  71.         }
  72.         // 使用 SIMD 转换灰度
  73.         to_gray_simd(inputFrame, outputFrame, width, height);
  74.         // 打印进度
  75.         if (frame % 30 == 0) {
  76.             std::cout << "Processed frame: " << frame + 1 << "/" << frameCount << std::endl;
  77.         }
  78.     }
  79.     auto endTime = std::chrono::high_resolution_clock::now();
  80.     double elapsedTime = std::chrono::duration<double>(endTime - startTime).count();
  81.     // 打印处理时间
  82.     std::cout << "Processed " << frameCount << " frames in " << elapsedTime << " seconds." << std::endl;
  83.     std::cout << "Average time per frame: " << (elapsedTime / frameCount) << " seconds." << std::endl;
  84. }
复制代码
结论

  1. C++
  2. Processed 1800 frames in 251.789 seconds.
  3. Average time per frame: 0.139883 seconds.
  4. C++ thread
  5. Processed 1800 frames in 229.571 seconds.
  6. Average time per frame: 0.12754 seconds.
  7. CPU版本POCL的OPENCL
  8. Processed 1800 frames in 233.25 seconds.
  9. Average time per frame: 0.129583 seconds.
  10. SIMD 内存对齐以后
  11. Processed 1800 frames in 191.015 seconds.
  12. Average time per frame: 0.106119 seconds.
复制代码
SIMD的性能明显由于其他几项,但是还需要测试GPU版本的OPencl和多线程指令集优化对性能的提拔

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

美丽的神话

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表