vectorizar vectoriales vectorial utilizados online mas imagenes imagen formatos formato conversion caracteristicas archivo c++ opencv gcc vectorization sse

c++ - vectoriales - Auto-vectorización: convencer al compilador de que la comprobación de alias no es necesaria



online raster to vector conversion system (3)

Estoy haciendo algo de procesamiento de imágenes, para lo cual me beneficio de la vectorización. Tengo una función que vectoriza bien, pero para la cual no puedo convencer al compilador de que el búfer de entrada y salida no se superponen, por lo que no es necesario verificar el alias. Debería poder hacerlo usando __restrict__ , pero si los buffers no están definidos como __restrict__ al llegar como argumento de función, no hay forma de convencer al compilador de que estoy absolutamente seguro de que los 2 buffers nunca se superpondrán.

Esta es la función:

__attribute__((optimize("tree-vectorize","tree-vectorizer-verbose=6"))) void threshold(const cv::Mat& inputRoi, cv::Mat& outputRoi, const unsigned char th) { const int height = inputRoi.rows; const int width = inputRoi.cols; for (int j = 0; j < height; j++) { const uint8_t* __restrict in = (const uint8_t* __restrict) inputRoi.ptr(j); uint8_t* __restrict out = (uint8_t* __restrict) outputRoi.ptr(j); for (int i = 0; i < width; i++) { out[i] = (in[i] < valueTh) ? 255 : 0; } } }

La única forma en que puedo convencer al compilador de que no realice la comprobación de alias es si pongo el bucle interno en una función separada, en la que los punteros se definen como __restrict__ argumentos. Si declaro esta función interna como en línea, nuevamente se activa la verificación de alias.

También puede ver el efecto con este ejemplo, que creo que es consistente: http://goo.gl/7HK5p7

(Nota: Sé que podría haber mejores formas de escribir la misma función, pero en este caso solo estoy tratando de entender cómo evitar la verificación de alias)

Editar:
¡¡El problema está resuelto!! (Ver respuesta abajo )
Usando gcc 4.9.2, aquí está el ejemplo completo . Tenga en cuenta el uso de la bandera del compilador -fopt-info-vec-optimized en lugar de la suplantada -ftree-vectorizer-verbose=N
Entonces, para gcc, use #pragma GCC ivdep y disfrute! :)


El compilador de Intel, al menos a partir de la versión 14, no genera comprobaciones de alias para el threshold2 en el código que vinculó, lo que indica que su enfoque debería funcionar. Sin embargo, gcc auto-vectorizer pierde esta oportunidad de optimización pero genera código vectorizado, pruebas de alineación adecuada, pruebas de aliasing y código de retroceso / limpieza no vectorizado.


Otro enfoque para este problema específico que está estandarizado y completamente portátil a través del compilador (razonablemente moderno) es usar la directiva OpenMP simd , que es parte del estándar desde la versión 4.0. El código se convierte entonces en:

void threshold(const unsigned char* inputRoi, const unsigned char valueTh, unsigned char* outputRoi, const int width, const int stride, const int height) { #pragma omp simd for (int i = 0; i < width; i++) { outputRoi[i] = (inputRoi[i] < valueTh) ? 255 : 0; } }

Y cuando se compila con la compatibilidad con OpenMP habilitada (ya sea con compatibilidad total o solo parcial solo para simd , como con -qopenmp-simd para el compilador de Intel), el código está completamente vectorizado.

Además, esto le da la oportunidad de indicar una posible alineación de los vectores, lo que puede ser útil en algunas circunstancias. Por ejemplo, si sus arrays de entrada y salida hubieran sido asignados con un asignador de memoria que tenga en cuenta la alineación , como posix_memalign() con un requisito de alineación de 256b, entonces el código podría convertirse en:

void threshold(const unsigned char* inputRoi, const unsigned char valueTh, unsigned char* outputRoi, const int width, const int stride, const int height) { #pragma omp simd aligned(inputRoi, outputRoi : 32) for (int i = 0; i < width; i++) { outputRoi[i] = (inputRoi[i] < valueTh) ? 255 : 0; } }

Esto debería permitir generar un binario aún más rápido. Y esta característica no está disponible fácilmente usando las directivas ivdep . Más razones para usar la directiva OpenMP simd .


Si está utilizando el compilador de Intel , puede intentar incluir la línea:

#pragma ivdep

El siguiente párrafo se cita en el manual del usuario del compilador de Intel:

El pragma ivdep le indica al compilador que ignore las supuestas dependencias vectoriales. Para garantizar el código correcto, el compilador trata una dependencia supuesta como una dependencia probada, lo que evita la vectorización. Este pragma anula esa decisión. Utilice este pragma solo cuando sepa que las dependencias de bucle asumidas son seguras de ignorar.

En gcc , uno debe agregar la línea:

#pragma GCC ivdep

Dentro de la función y justo antes del bucle que desea vectorizar (consulte la documentation ). Esto solo se admite a partir de gcc 4.9 y, por cierto, hace que el uso de __restrict__ redundante.