2012-07-15 17 views
7

He intentado utilizar restringir punteros calificados, y he encontrado un problema. El siguiente programa es solo uno simple para presentar el problema.Restringir punteros y alinear

La calc_function usa tres punteros, que están restringidos por lo que "DEBERÁN" no tener alias entre sí. Al compilar este código en Visual Studio, la función estará en línea, por lo que por ningún motivo Visual Studio 2010 ignorará los calificadores. Si deshabilito la línea, el código se ejecuta más de seis veces más rápido (de 2200 ms a 360 ms). Pero no quiero inhabilitar la creación de líneas en todo el proyecto ni el archivo completo (porque entonces se tratará de gastos generales de llamadas, por ejemplo, todos los getters y setters, lo que sería horrible).

(Podría ser que la única solución es desactivar procesos en línea de tan sólo esta función?)

He tratado de crear restringir temporal punteros calificados en la función, tanto en la parte superior y en el bucle interior para tratar de decir la compilador que prometo que no hay aliasing, pero el compilador no me creerá, y no funcionará. También he intentado ajustar la configuración del compilador, pero la única que he encontrado que funciona, es desactivar la creación de líneas.

Agradecería ayuda para resolver este problema de optimización.

Para ejecutar el programa (en el modo de realease) no olvide utilizar los argumentos 0 1000 2000. Por qué el uso de argumentos de entrada/programa de usuario es para asegurarse de que el compilador no puede saber si hay o no ' t aliasing entre los punteros a, b y c.

#include <cstdlib> 
#include <cstdio> 
#include <ctime> 

// Data-table where a,b,c will point into, so the compiler cant know if they alias. 
const size_t listSize = 10000; 
int data[listSize]; 

//void calc_function(int * a, int * b, int * c){ 
void calc_function(int *__restrict a, int *__restrict b, int *__restrict c){ 
    for(size_t y=0; y<1000*1000; ++y){ // <- Extra loop to be able to messure the time. 
     for(size_t i=0; i<1000; ++i){ 
      *a += *b; 
      *c += *a; 
     } 
    } 
} 
int main(int argc, char *argv[]){ // argv SHALL be "0 1000 2000" (with no quotes) 
    // init 
    for(size_t i=0; i<listSize; ++i) 
     data[i] = i; 

    // get a, b and c from argv(0,1000,2000) 
    int *a,*b,*c; 
    sscanf(argv[1],"%d",&a); 
    sscanf(argv[2],"%d",&b); 
    sscanf(argv[3],"%d",&c); 
    a = data + int(a); // a, b and c will (after the specified argv) be, 
    b = data + int(b); // a = &data[0], b = &data[1000], c = &data[2000], 
    c = data + int(c); // So they will not alias, and the compiler cant know. 

    // calculate and take time 
    time_t start = clock(); 
     funcResticted(a,b,c); 
    time_t end = clock(); 
    time_t t = (end-start); 
    printf("funcResticted  %u (microSec)\n", t); 

    system("PAUSE"); 
    return EXIT_SUCCESS; 
} 
+1

+1 para buenas prácticas de creación de perfiles. Optaré por no quejarme sobre el especificador de formato. PD 'clock' devuelve' clock_t', no 'time_t'. – Hurkyl

+1

Intente proteger la llamada de función con una comprobación de que los desplazamientos son lo suficientemente grandes. Probablemente tengas que usar variables 'int' reales para almacenar las compensaciones, en lugar del truco que usaste. – Hurkyl

+0

@Hurkyl Pensé que clock_t y time_t eran ambos typedefs a la misma cosa, pero estás en lo cierto. (Por cierto, ¿cómo puedo editar mi pregunta-publicación?) – Boll

Respuesta

3

Si se declara una función con __declspec(noinline), que obligará a no ser inline:

http://msdn.microsoft.com/en-us/library/kxybs02x%28v=vs.80%29.aspx

Se puede usar esta desactivar manualmente procesos en línea en función de cada función.


En cuanto a restrict, el compilador es libre de usarlo sólo cuando quiere. Así que juguetear con diferentes versiones del mismo código es algo inevitable cuando intentamos "engañar" a los compiladores para que realicen dichas optimizaciones.

+0

Esta solución funciona, tanto en el código de prueba en la pregunta, como en mi aplicación real. Pero habrá algunos problemas si una función muy pequeña, que se llama muchas veces, necesita punteros calificados restringidos, donde __declspec (noinline) obligará a una sobrecarga de llamada bastante grande. Por lo tanto, esperaré aceptando esto como la mejor respuesta. – Boll

+0

Sí, sé lo que quieres decir. Mi suposición es que el análisis de alias puntero utilizado en VS2010 es solo a nivel de función granularidad. Por lo tanto, no es capaz de distinguir punteros sin alias que se "generan" en el medio de una función. No estoy seguro de si 'restrict' se puede utilizar en punteros localmente declarados. Si lo hace, podría ser algo para probar. – Mysticial

+0

Tiene toda la razón, y traté de usar punteros localmente declarados con restricciones sin suerte.Su "__declspec (noinline)" es la mejor solución, y funciona en mi caso actual (mi aplicación) así que la acepto como la Respuesta. Gracias. – Boll