Funciones utilizadas con frecuencia, ¿mejoras de rendimiento con variables estáticas?

3

¿Las variables de definición (matrices grandes) como estáticas dentro de una función tienen mejoras en el rendimiento si se va a llamar a la función repetidamente en el orden de segundos?

    
pregunta Hassan Nadeem

3 respuestas

2

En resumen: depende. Sobre más cosas que quieras saber.

Algunas arquitecturas tienen instrucciones y / o modos de direccionamiento que acceden a datos relativos a la pila. Casi todas las arquitecturas tienen instrucciones y / o modos de direccionamiento que acceden a los datos en una dirección absoluta. Lo que es más rápido depende de la arquitectura particular.

Tenga en cuenta que algunas arquitecturas solo permiten un desplazamiento muy pequeño o una dirección (de cero páginas) en una instrucción, por lo que en tal arquitectura, mucho depende de si el desplazamiento se ajusta. Cuando tiene muchas variables estáticas (= tiempo de vida global), es más probable que exceda una pequeña dirección de cero páginas (porque comparten el mismo espacio de direcciones absolutas) que con una gran cantidad de automática (tiempo de vida local, direccionado por desplazamiento de pila) ) variables (cada una con su propia compensación SP pequeña).

Pero en las arquitecturas modernas de clase PC, el acceso a la memoria (incluidos los problemas de caché) es a menudo mucho más importante que la ejecución de instrucciones, especialmente cuando el código es un bucle cerrado y los datos están por todos lados. En tal caso, la velocidad de ejecución puede variar en un 10% dependiendo de cómo se alinean los datos con respecto a varios problemas de caché (líneas, páginas, búferes, etc.), que se ven afectados por casi todo excepto la fase de la luna, incluidos Otras aplicaciones que están o incluso han sido cargadas. Esto hace que la evaluación comparativa en una situación así sea muy dudosa.

    
respondido por el Wouter van Ooijen
0

¿Mejoras en comparación con qué? Supongo que tiene un programa en C (o está utilizando la terminología en C para describir su programa) y desea comparar

  • (a) la matriz grande se declaró "const" en cualquier ámbito
  • (b) matriz grande declarada como estática dentro de una función (alcance de función)
  • (c) matriz grande declarada como estática fuera de una función ("archivo" alcance)
  • (d) matriz grande declarada fuera de una función (alcance global)
  • (e) matriz grande dentro de una función ("automática", alcance de función) sin un inicializador
  • (f) matriz grande dentro de una función ("automática", alcance de función) con un inicializador

(¿O hay algo más con lo que quieras comparar?)

automático con inicializador vs otros

La mayor diferencia de rendimiento es entre (f) y los demás: (f) copia el inicializador a la matriz y elimina a cero los elementos restantes, cada vez que llama a la función. El otro uso, sea lo que sea que esté en la memoria RAM en ese momento.

Si la función usualmente usa solo unos pocos elementos de la matriz, pero necesita una matriz muy grande para manejar los casos de esquina, (f) perderá mucho tiempo escribiendo en cada byte de la matriz cada vez que Llámelo, en comparación con los otros enfoques que omiten esa inicialización.

Por otra parte, a veces una función necesita tener una matriz modificable que se restablece de cierta manera cada vez que la llamas. Cuando elige (f), es probable que su compilador utilice la forma más eficiente de hacerlo: es poco probable que alguno de los otros métodos (seguidos de un reajuste manual de la matriz) sea más rápido.

automático frente a otros (relativo a la pila frente a absoluto)

Algunos compiladores para algunos procesadores usan exactamente la misma instrucción de acceso a la matriz genérica para cada tipo de matriz (a) a (f). Para esos compiladores, el tipo particular de matriz que elija no tiene efecto en el tiempo de ejecución.

A menudo, los procesadores obligan a un compilador a usar diferentes instrucciones para acceder a diferentes tipos de arreglos.

En los procesadores con caché, las diferencias entre estas instrucciones son generalmente insignificantes.

Sin embargo, la mayoría de los procesadores no tienen caché, como los procesadores de 8 bits que superan a todos los procesadores de 64 bits combinados. En esos procesadores, las diferencias en las instrucciones elegidas por el compilador pueden llevar a una diferencia notable en el tiempo de ejecución en un bucle interno estrecho que accede a los elementos de la matriz sin muchos otros cálculos.

(Mi impresión es que las instrucciones "automáticas" relativas a la pila son las más rápidas en los microcontroladores ARM, mientras que las instrucciones "absolutas" para global y "file static" y "function static" son las más rápidas en los microcontroladores PIC16).

    
respondido por el davidcary
0

En general, será más rápido acceder a las variables que tienen direcciones conocidas en el momento de la compilación. Sin embargo, el beneficio exacto, si lo hay, depende de muchos otros factores. Por ejemplo, que PIC? ¿Estático según lo indicado para qué tipo de asignación dinámica? ¿Qué tan grande es la matriz? Si está utilizando un compilador, esto puede depender de las estrategias elegidas por el diseñador del compilador.

Si está comparando variables estáticas (direcciones conocidas en el momento de la compilación) con variables de asignación dinámica en la pila de datos, entonces la estática será una ganancia en un PIC básico 16 ya que no tienen funciones de pila inherentes.

En un PIC 18, hay algunas capacidades limitadas de direccionamiento relativo fuera de las FSR, pero éstas generalmente tomarán más ciclos que si se conoce una dirección fija. El desplazamiento desde un registro de puntero es solo de 8 bits, por lo que el alcance también está limitado. Más allá de eso, tiene que hacer sus propios cálculos matemáticos para calcular la dirección y cargarla en una de las FSR.

En un PIC de 16 bits, hay más modos de direccionamiento relativos al registro, que permiten un acceso más flexible a los elementos en la pila. Sin embargo, hay aún más modos de direccionamiento disponibles si no tiene que pasar por un registro para obtener la dirección base. En algunos casos limitados, en realidad puede ser un acceso más rápido a una variable de 16 bits en la pila, ya que la dirección de la pila ya está en W15, mientras que la dirección estática de una variable debe cargarse primero en un registro. La penalización por acceder a la memoria dinámica será menor en un PIC de 16 bits, pero creo que, en general, el acceso a la memoria estática será más rápido. También hay una sección de memoria de datos, llamada "cerca", que permite instrucciones especiales que no están disponibles para acceder al resto de la memoria de datos. En algunos casos, si pudiera organizar que la pila estuviera cerca de la memoria, pero ese no sería el caso general.

Sin embargo, todo eso estaba considerando variables individuales. Estás preguntando por una gran variedad, lo que hace que las cosas vuelvan a ser diferentes. Los elementos de una matriz serán accedidos indirectamente con la dirección calculada en el tiempo de ejecución de todos modos, por lo que si la dirección de inicio de la matriz es una constante o algo que debe ser capturado o computado hace una diferencia general menor. En un PIC 18, el mayor problema probablemente sea la disputa por el número limitado de FSR (registros de puntero de hardware), ya que solo hay 3 de ellos, y lo más probable es que al menos 1 ya esté asignado como el puntero de la pila de datos. (El compilador C18 es "menos que brillante" en la forma en que usa los punteros PIC 18, y en realidad controla 2 de los 3 SFR para su propio uso). En un PIC de 16 bits, los ciclos de tiempo de ejecución serán incluso menos diferentes.

Básicamente, asigna las cosas de forma estática cuando puedas. La única razón por la que no debe usar los PIC es si necesita conservar la memoria y sabe que nunca se asignarán simultáneamente cantidades significativas de memoria asignada de forma dinámica. Por ejemplo, si dos subrutinas necesitan usar una matriz de 2 kB solo para uso temporal, pero estas subrutinas nunca se llaman una de la otra, luego, la asignación dinámica de las matrices cuando sea necesario ahorra 2 kB en general en comparación con la asignación estática.

Otra razón, particularmente en un PIC 16 y PIC 18, es permitir que se usen ubicaciones especiales de memoria de acceso rápido como rasguños dentro de cada rutina. Por ejemplo, en muchos PIC 16, los últimos 16 bytes de cada banco acceden a los mismos 16 bytes a nivel mundial. Estas ubicaciones de memoria limitada son, por lo tanto, bastante útiles como rasguño temporal rápido porque se puede acceder a ellas independientemente de la configuración del banco. Mi convención es reservar la mayoría de estos como si fueran registros en otras arquitecturas de procesadores. Por lo tanto, mis rutinas generalmente guardan las que serán eliminadas en la pila de datos en la entrada y las restaurarán en la salida. El banco de acceso en un PIC 18 funciona de manera similar, aunque es más grande, por lo que también es más fácil de usar para otras cosas. Este concepto no se aplica realmente a los PIC de 16 bits porque tienen 16 registros de hardware reales integrados.

Para recapitular, asigne estáticamente todo el estado persistente. Luego asigne estáticamente el estado restante a menos que necesite reducir el uso de la memoria.

    
respondido por el Olin Lathrop

Lea otras preguntas en las etiquetas