【问题标题】:Dispatching SIMD instructions + SIMDPP + qmake调度 SIMD 指令 + SIMDPP + qmake
【发布时间】:2016-09-14 06:43:05
【问题描述】:

我正在开发一个使用 SIMD 指令集的 QT 小部件。我编译了 3 个版本:SSE3、AVX 和 AVX2(simdpp 允许通过单个#define 在它们之间切换)。

现在,我希望我的小部件根据最受支持的指令集在这些实现之间自动切换。 simdpp 提供的指南使用了一些 makefile 魔法:

CXXFLAGS=""

test: main.o test_sse2.o test_sse3.o test_sse4_1.o test_null.o
    g++ $^ -o test

main.o: main.cc
    g++ main.cc $(CXXFLAGS) -c -o main.o

test_null.o: test.cc
    g++ test.cc -c $(CXXFLAGS) -DSIMDPP_EMIT_DISPATCHER \
        -DSIMDPP_DISPATCH_ARCH1=SIMDPP_ARCH_X86_SSE2 \
        -DSIMDPP_DISPATCH_ARCH2=SIMDPP_ARCH_X86_SSE3 \
        -DSIMDPP_DISPATCH_ARCH3=SIMDPP_ARCH_X86_SSE4_1 -o test_null.o

test_sse2.o: test.cc
    g++ test.cc -c $(CXXFLAGS) -DSIMDPP_ARCH_X86_SSE2 -msse2 -o test_sse2.o

test_sse3.o: test.cc
    g++ test.cc -c $(CXXFLAGS) -DSIMDPP_ARCH_X86_SSE3 -msse3 -o test_sse3.o

test_sse4_1.o: test.cc
    g++ test.cc -c $(CXXFLAGS) -DSIMDPP_ARCH_X86_SSE4_1 -msse4.1 -o test_sse4_1.o

这里是指南的链接:http://p12tic.github.io/libsimdpp/v2.0~rc2/libsimdpp/arch/dispatch.html

我不知道如何使用 qmake 实现这种行为。有什么想法吗?

首先想到的是创建一个包含已调度代码的共享库,并将其链接到项目。在这里,我又被困住了。应用程序是跨平台的,这意味着它必须同时使用 GCC 和 MSVC(准确地说是 vc120)编译,这迫使在 Windows 中使用 nmake,我确实尝试过,但这就像我整个程序员生涯中最糟糕的经历.

提前致谢,全世界的程序员!

【问题讨论】:

  • 您不能使用 qmake 多次构建同一个文件。您需要找到解决方法(将 ifdef 代码拆分到多个文件等)

标签: c++ qt qmake simd avx


【解决方案1】:

抱歉,这有点晚了。希望我仍然可以提供帮助。

您需要考虑 2 个方面:编译时间和运行时间。

编译时间 - 需要创建代码来支持不同的功能。 运行时 - 需要创建代码来决定可以运行哪些功能。

您想要做的是创建一个调度程序...

FuncImpl.h:

#pragma once
void execAvx2();
void execAvx();
void execSse();
void execDefault();

FuncImpl.cpp:

// Compile this file once for each variant with different compiler settings.
#if defined(__AVX2__)
void execAvx2()
{
 // AVX2 impl
...
}

#elif defined (__AVX__)

void execAvx()
{
// AVX impl
...
}

#elif defined (__SSE4_2__)

void execSse()
{
 // Sse impl
...
}

#else

void execDefault()
{
 // Vanilla impl
...
}

#endif

DispatchFunc.cpp

#include "FuncImpl.h"

// Decide at runtime which code to run
void dispatchFunc()
{
     if(CheckCpuAvx2Flag())
     {
         execAvx2();
     } 
     else if(CheckCpuAvxFlag())
     {
         execAvx();
     }
     else if(CheckCpuSseFlags())
     {
         execSse();
     }
     else
     {
         execDefault();
     }
}

您可以做的是创建一组 QMAKE_EXTRA_COMPILERS。

SampleCompiler.pri(对每个变体执行此操作):

MyCompiler.name = MyCompiler         # Name
MyCompiler.input = MY_SOURCES        # Symbol of the source list to compile
MyCompiler.dependency_type = TYPE_C
MyCompiler.variable_out = OBJECTS
# EXTRA_CXXFLAGS = -mavx / -mavx2 / -msse4.2
# _var = creates FileName_var.o => replace with own variant (_sse, etc)  
MyCompiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}_var$${first(QMAKE_EXT_OBJ)}
MyCompiler.commands = $${QMAKE_CXX} $(CXXFLAGS) $${EXTRA_CXXFLAGS} $(INCPATH) -c ${QMAKE_FILE_IN} -o${QMAKE_FILE_OUT}
QMAKE_EXTRA_COMPILERS += MyCompiler   # Add my compiler

MyProject.pro

...
include(SseCompiler.pri)
include(AvxCompiler.pri)
include(Avx2Compiler.pri)
..

# Normal sources
# Will create FuncImpl.o and DispatchFunc.o
SOURCES += FuncImpl.cpp \
           DispatchFunc.cpp

# Give the other compilers their sources
# Will create FuncImpl_avx2.o FuncImpl_avx.o FuncImpl_sse.o
AVX2_SOURCES += FuncImpl.cpp
AVX_SOURCES += FuncImpl.cpp
SSE_SOURCES += FuncImpl.cpp

# Link all objects
...

您现在只需要调用 dispatchFunc()!

检查 CPU 标志是您的另一个练习: cpuid

【讨论】:

    【解决方案2】:

    这些只是项目定义。您可以在 .pro 文件中使用 DEFINES += 设置它们。您为要支持的指令集设置标志,simdpp 会在运行时为处理器选择最佳的。

    例如,请参阅Add a define to qmake WITH a value?

    【讨论】:

    • 在 makefile 中表达的想法是基于基于单个 .cpp 文件构建多个目标文件,将它们全部链接到更改的名称,然后在必要时使用正确的名称。这是我不知道如何做的。定义一个符号不是问题。
    • 我明白你现在的意思了,我认为 peppe 是对的,因为 Qt 没有办法轻松做到这一点。我认为您可以为要构建的每个版本的文件创建一个不同的 .pro 文件。您将创建不同的库(TEMPLATE = lib),然后将所有库版本链接到您的应用程序。您可能还必须使#defines 更改函数/类的命名空间,否则您将拥有相同函数的多个版本,这些版本将不起作用。也许这已经在 simdpp 中完成了?
    【解决方案3】:

    这是一个用于 SIMD 调度程序的 qmake .pro 文件。它非常冗长,因此对于更多指令集,最好通过脚本生成分派块,将其写入 .pri 文件,然后从主 .pro 文件中包含它。

    TEMPLATE = app
    TARGET = simd_test
    INCLUDEPATH += .
    
    QMAKE_CXXFLAGS = -O3 -std=c++17
    
    SOURCES += main.cpp
    
    SOURCES_dispatch = test.cpp
    {
        # SSE2
        DISPATCH_CXXFLAGS = -msse2
        DISPATCH_SUFFIX = _sse2
    
        src_dispatch_sse2.name = src_dispatch_sse2
        src_dispatch_sse2.input = SOURCES_dispatch
        src_dispatch_sse2.dependency_type = TYPE_C
        src_dispatch_sse2.variable_out = OBJECTS
        src_dispatch_sse2.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${DISPATCH_SUFFIX}$${first(QMAKE_EXT_OBJ)}
        src_dispatch_sse2.commands = $${QMAKE_CXX} $(CXXFLAGS) $${DISPATCH_CXXFLAGS} $(INCPATH) -c ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
        QMAKE_EXTRA_COMPILERS += src_dispatch_sse2
    }
    {
        # SSE3
        DISPATCH_CXXFLAGS = -msse3
        DISPATCH_SUFFIX = _sse3
    
        src_dispatch_sse3.name = src_dispatch_sse3
        src_dispatch_sse3.input = SOURCES_dispatch
        src_dispatch_sse3.dependency_type = TYPE_C
        src_dispatch_sse3.variable_out = OBJECTS
        src_dispatch_sse3.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${DISPATCH_SUFFIX}$${first(QMAKE_EXT_OBJ)}
        src_dispatch_sse3.commands = $${QMAKE_CXX} $(CXXFLAGS) $${DISPATCH_CXXFLAGS} $(INCPATH) -c ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
        QMAKE_EXTRA_COMPILERS += src_dispatch_sse3
    }
    {
        # SSE41
        DISPATCH_CXXFLAGS = -msse4.1
        DISPATCH_SUFFIX = _sse41
    
        src_dispatch_sse41.name = src_dispatch_sse41
        src_dispatch_sse41.input = SOURCES_dispatch
        src_dispatch_sse41.dependency_type = TYPE_C
        src_dispatch_sse41.variable_out = OBJECTS
        src_dispatch_sse41.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${DISPATCH_SUFFIX}$${first(QMAKE_EXT_OBJ)}
        src_dispatch_sse41.commands = $${QMAKE_CXX} $(CXXFLAGS) $${DISPATCH_CXXFLAGS} $(INCPATH) -c ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
        QMAKE_EXTRA_COMPILERS += src_dispatch_sse41
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-29
      • 2014-06-20
      • 1970-01-01
      • 2017-01-09
      • 2023-03-06
      • 2015-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多