es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Organizando múltiples implementaciones (para SIMD)

Este es claramente una pregunta abierta y subjetiva, pero estoy buscando diferentes ideas sobre cómo “organizar” múltiples implementaciones alternativas de las mismas funciones.

Tengo un conjunto de varias funciones que tienen implementaciones específicas para plataformas. Específicamente, cada una tiene una implementación diferente para un tipo de SIMD en particular: NEON (64 bits), NEON (128 bits), SSE3, AVX2, etc. (y una implementación sin SIMD).

Todas las funciones tienen una implementación sin SIMD. No todas las funciones están especializadas para cada tipo de SIMD.

Actualmente, tengo un archivo monolítico que utiliza muchas directivas #ifdef para implementar las especializaciones específicas de SIMD. Funcionaba cuando solo estábamos especializando algunas de las funciones para uno o dos tipos de SIMD. Ahora, se ha vuelto difícil de manejar.

Básicamente, necesito algo que funcione como una función virtual o una función sobrescrita. Las implementaciones sin SIMD están implementadas en una clase base y las especializaciones SIMD (si las hay) las sobrescribirían. Pero no quiero polimorfismo en tiempo de ejecución real. Este código es crítico en cuanto al rendimiento y muchas de las funciones pueden (y deben) ser en línea.

Algo como esto lograría lo que necesito (que sigue siendo un lío de #ifdefs).

// functions.h

void function1();
void function2();

#ifdef _ARM_NEON

#include "functions_neon64.h"

#elif SSE3

#include "functions_sse3.h"

#endif

#include "functions_unoptimized.h"


// functions_neon64.h

#ifndef FUNCTION1_IMPL
#define FUNCTION1_IMPL

void function1() {
  // Implementación NEON64
}

#endif


// functions_sse3.h

#ifndef FUNCTION2_IMPL
#define FUNCTION2_IMPL

void function2() {
  // Implementación SSE3
}

#endif


// functions_unoptimized.h

#ifndef FUNCTION1_IMPL
#define FUNCTION1_IMPL

void function1() {
  // Implementación sin SIMD
}

#endif

#ifndef FUNCTION2_IMPL
#define FUNCTION2_IMPL

void function2() {
  // Implementación sin SIMD
}

#endif

¿Alguien tiene ideas mejores?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Un enfoque alternativo sería utilizar la especialización de plantillas para proporcionar las diferentes implementaciones. Esto eliminaría la necesidad de #ifdefs y mejoraría la legibilidad del código.

    Primero, define una función de plantilla con una implementación predeterminada/no SIMD:

    “`c++
    template
    void funcion1() {
    // Implementación no SIMD
    }


    Luego, especializa la función de plantilla para cada tipo SIMD: ```c++ // Implementación NEON (64 bits) template <> void funcion1<neon64>() { // Implementación NEON (64 bits) } // Implementación NEON (128 bits) template <> void funcion1<neon128>() { // Implementación NEON (128 bits) } // Implementación SSE3 template <> void funcion1<sse3>() { // Implementación SSE3 } // Implementación AVX2 template <> void funcion1<avx2>() { // Implementación AVX2 }

    Finalmente, utiliza la función de plantilla en tu código especificando el tipo SIMD deseado:

    c++
    funcion1<neon64>(); // llama a la especialización neon64
    funcion1<sse3>(); // llama a la especialización SSE3
    funcion1<int>(); // llama a la implementación predeterminada/no SIMD

    Este enfoque facilita la adición de nuevas implementaciones SIMD en el futuro sin tener que modificar el código existente. También elimina la necesidad de #ifdefs y mejora la legibilidad del código.

Comments are closed.