2009-09-29 21 views
7

Tengo una función que necesita bastante almacenamiento temporal interno para sus cálculos (algunas operaciones de matriz) y sé que esta función se llamará con frecuencia (por ejemplo, cada milisegundo a lo largo del tiempo de ejecución del programa). Mi instinto me dice que es mejor declarar esas variables temporales estáticas, por lo que no hay tanto esfuerzo administrativo para crearlas una y otra vez con cada llamada de la función. Tengo que inicializarlos de todos modos cada vez que se llama a la función, por lo que mantenerlos vivos no es necesaria para fines funcionales. Soy consciente de que convertirlos en estáticos rompe la seguridad del hilo, pero esto no es un problema aquí.¿Usar variables estáticas internas para aumentar el rendimiento?

Como el conocimiento es mejor que cualquier sensación visceral, me gustaría saber cuál es la forma "correcta" de manejar este caso.

void frequentlyCalledFunction(void) 
{ 
    double matrix1[10][10]; 
    double matrix2[10][10]; 
    /* do something with the matrices ... */ 
} 

o

void frequentlyCalledFunction(void) 
{ 
    static double matrix1[10][10]; 
    static double matrix2[10][10]; 
    /* do something with the matrices ... */ 
} 

Respuesta

16

No hay diferencia. No se necesita código para "crear" una matriz no inicializada.

En el caso de una matriz estática, la memoria está reservada y disponible todo el tiempo. En el caso de una matriz automática, está en la pila, y todo lo que se necesita para "crearla" es mover el puntero de la pila, que de todos modos se producirá al ingresar a la función.

(Y un día usted intenta utilizar esa función en un programa de multiproceso, y la versión estática van a sufrir fallos intermitentes ocasionales que conduce a beber y las drogas. Es simplemente no vale la pena el riesgo.)

+0

Puede que no exista una sobrecarga para crear las variables locales, pero tendrán que accederse en relación con la pila o el puntero base, por lo que podría haber un rendimiento mensurable – Christoph

+0

@Christoph: punto interesante. Me pregunto si hace una diferencia en un procesador moderno. Apuesto a que no, pero no soy un asistente de montaje. :-) – RichieHindle

+0

Estoy tratando de pensar en una plataforma en la que esto sea un problema. Dado que se fijará desde el marco de pila dado, no debería causar un problema. Por ejemplo, en mips podrías hacer un LD r1, frame_offset (stack_frame_base) para que fuera gratis. mov eax, [esp + frame_offset] es gratuito, así ... – Goz

1

La única forma de saber es probarlo y probarlo. Sin embargo, es poco probable que haga mucha diferencia.

2

Está tratando de realizar una microoptimización sin realizar una evaluación comparativa, que generalmente se considera mala. Usted siempre debe comparar. De lo contrario, ¿cómo sabrá con seguridad que funcionó cualquier intento de optimización?

Es poco probable que gane nada al hacerlo, y la legibilidad del código y la facilidad de mantenimiento deberían ser lo primero.

+0

y el downvote es porque? –

5

Como de costumbre, primero debería crear perfiles. Las variables locales probablemente solo causen que el puntero de la pila se reduzca un poco más, lo que no debería tener ninguna penalización de rendimiento.

9

Definitivamente lo escribiría de la manera más simple y legible primero. Una vez por milisegundo suena como una muy rara vez función de ejecución para la micro-optimización.

Una vez que lo tenga funcionando, compárelo. Decide si el rendimiento es lo suficientemente bueno. Si no es así, optimice y comparta de nuevo. No haga código de curva doblada fuera de forma sin números muy sólidos para respaldar su decisión.

2

Asignar variables de pila no es como asignar variables de pila; todo lo que ocurre es que el puntero de pila se mueve lo suficiente para asignar toda la memoria que necesita la función. No hay sobrecarga en la asignación de una o cien variables en un marco de pila. El puntero de la pila ya se moverá cuando se llame a la función incluso si hay cero variables (para registrar dónde volver, etc.)

0

Reservar espacio para variables con duración de almacenamiento automático significa simplemente disminuir el puntero de la pila, por lo siempre que estas no sean las únicas variables locales, no hay gastos generales.

Lo que puede perjudicar el rendimiento es que las variables asignadas a la pila deben abordarse en relación con la pila o el puntero base, por lo que usar static podría mejorar ligeramente el rendimiento.

Como siempre, el punto de referencia de código para asegurarse.

1

En SPARC especialmente en 64 bits de modo, el caso estático es más lenta. El acceso a una variable global (que es la estática, es sólo el nombre que se limita al ámbito de la función) necesita instrucciones usando 5 3 registro, en su caso, sólo 10 instrucciones para obtener la dirección de las matrices. La versión no estática, como ya se ha señalado, no tiene gastos indirectos, como el bastidor está construido en anycase, si el puntero de pila crece 16 bytes o 200 no hace ninguna diferencia. Pero tenga cuidado si inicia su matriz, esto puede producir un memset oculto que puede ser costoso.

void frequentlyCalledFunction(void) 
{ 
    double matrix1[10][10]={0.0}; 
    double matrix2[10][10]={0.0}; 
    /* do something with the matrices ... */ 
} 

probablemente realice 1 o 2 llamadas memcpy o memset para inicializar las matrices.