13 votos

¿Cuál es el mejor enfoque a la hora de escribir las funciones de la Embedded Software en orden para un mejor rendimiento?

He visto algunas de las bibliotecas para los microcontroladores y sus funciones hacer una sola cosa a un tiempo. Por ejemplo algo como esto

void setCLK()
{
    //code to set the clock
}

void setConfig()
{
    //code to set the config
}

void setSomethingElse()
{ 
   //1 line code to write something to a register.
}

Luego vienen otras funciones en la parte superior de la misma que utiliza este 1 de la línea de código que contiene la función de servir a otro propósito. Por ejemplo:

void initModule()
{
   setCLK();
   setConfig();
   setSomethingElse();
}

No estoy seguro, pero creo que de esta forma sería la creación de más llamar a los saltos y la creación de la sobrecarga de apilamiento de las direcciones de retorno cada vez que el tiempo se llama a una función o salido. Y que haría que el programa de trabajo lento?

He buscado y en todos lados dicen que el dedo pulgar de la regla de la programación es la de que una función debe realizar sólo una tarea.

Así que si escribo directamente un InitModule módulo de función que ajusta el reloj, añade algo de la configuración deseada y hace algo más, sin llamar a las funciones. Es un mal enfoque de la escritura de software embebido?


EDIT2 : 1) parece Que mucha gente lo ha entendido esta pregunta como si yo estoy tratando de optimizar un programa . NO, NO TENGO NINGUNA INTENCIÓN DE HACER. Estoy dejando que el compilador de hacerlo, porque va a ser siempre(espero que no, aunque!)mejor que yo.

2) Toda la culpa en mí para la elección de un ejemplo que representa algún código de inicialización. La pregunta no tiene ninguna intención de considerar la función de las llamadas realizadas para la inicialización de propósito.Mi pregunta es ¿romper una cierta tarea en pequeños funciones de multi-línea(modo en línea está fuera de toda duda) que se ejecuta dentro de un bucle infinito tiene ninguna ventaja sobre la escritura de largo la función sin función anidada?

Por favor, considere la posibilidad de mejorar la legibilidad se define en la respuesta de @Jonk

Espero que esta no es una opinión basada en cuestión.

29voto

Swapnil Tathe Puntos 11

Podría decirse que, en su ejemplo, el rendimiento no importa, como el código sólo se ejecuta una vez en el inicio.

Una regla de oro que uso: Escribir el código tan legible como sea posible y sólo empezar a optimizar si usted nota que su compilador no está correctamente haciendo su magia.

El costo de una llamada a una función en un ISR podría ser el mismo que el de una llamada de función durante el inicio en términos de almacenamiento y de distribución. Sin embargo, los requisitos de tiempo durante el que la ISR puede ser mucho más crítico.

Además, como ya se ha notado por otros, el costo y el significado de la 'costo') de una llamada de función difiere de la plataforma, compilador de compilador de optimización de la configuración, y los requisitos de la aplicación. Habrá una gran diferencia entre un 8051 y un cortex-m7, y un marcapasos y un interruptor de luz.

8voto

Crazor Puntos 81

1) el Código para mejorar la legibilidad y mantenibilidad en primer lugar. El aspecto más importante de cualquier codebase es que es bien estructurado. Muy bien escrito el software tiende a tener menos errores. Puede que necesite hacer cambios en un par de semanas/meses/años, y que ayuda enormemente si su código es agradable de leer. O tal vez alguien más tiene que hacer un cambio.

2) el Rendimiento de código que se ejecuta una vez, no importa mucho. La atención por el estilo, no para el rendimiento

3) Incluso el código en estrecha lazos debe ser correcta en primer lugar. Si se enfrentan a problemas de rendimiento, a continuación, optimizar una vez que el código es correcto.

4) Si usted necesita para optimizar, se tienen que medir! No importa si usted piensa o alguien le dice a usted que static inline es sólo una recomendación para el compilador. Tienes que echar un vistazo a lo que el compilador hace. Usted también tiene que medir si inline hizo mejorar el rendimiento. En sistemas embebidos, usted también tiene que medir el tamaño del código, ya que el código de la memoria suele ser bastante limitada. Esta es LA regla más importante que distingue a la ingeniería de las conjeturas. Si usted no medir, no ayuda. La ingeniería es la medición. La ciencia es la escritura hacia abajo ;)

5voto

Mike Crittenden Puntos 2575

Cuando se llama a una función en un solo lugar (incluso dentro de otra función) el compilador siempre pone el código en el lugar, en lugar de llamar a la función. Si la función se llama en muchos lugares de los que tiene sentido utilizar una función de, al menos, desde el código de tamaño de punto de vista.

Después de compilar el código no tendrá las múltiples llamadas en lugar de la legibilidad se verá muy mejorado.

También usted va a querer tener, por ejemplo, el ADC en el código de inicialización en la misma biblioteca con otros ADC funciones no en la principal c archivo.

Muchos compiladores permiten especificar diferentes niveles de optimización de la velocidad o el tamaño del código, así que si usted tiene una pequeña función de llamada en muchos lugares, a continuación, la función de "entre líneas" , copiado allí en lugar de llamar.

La optimización de la velocidad de las funciones inline en muchos lugares se puede, la optimización de código para tamaño de llamar a la función, sin embargo , cuando se llama a una función en un solo lugar como en tu caso va a estar siempre "en línea".

Un código como este:

function_used_just_once{
   code blah blah;
}
main{
  codeblah;
  function_used_just_once();
  code blah blah blah;
{

va a compilar:

main{
 code blah;
 code blah blah;
 code blah blah blah;
}

sin el uso de cualquier tipo de llamada.

Y la respuesta a tu pregunta,en tu ejemplo o similar, la legibilidad del código no afecta el rendimiento, nada, es que muchos en la velocidad o el tamaño del código. Es común el uso de múltiples llamadas sólo para hacer que el código sea legible , al final son ser cumplido como una línea de código.

Actualización para especificar que las afirmaciones anteriores no son válidas para un propósito paralizado versión gratuita compiladores como el Microchip XCxx versión gratuita. Este tipo de llamadas de función es una mina de oro para los de Microchip para demostrar cuánto mejor es la versión de pago y si se compila este se encuentra en el ASM exactamente tanto las llamadas como la que tiene en la C código.

También no es para tontos programadores que esperar para utilizar el puntero a una línea de la función.

Esta es la sección de electrónica, no general en C, C++ o sección de programación, la pregunta es acerca de la programación de microcontroladores donde cualquier decente compilador hará por encima de la optimización por defecto.

Así que por favor deje de downvoting sólo porque en raras, inusuales casos, esto podría no ser cierto.

2voto

Bartosz Radaczyński Puntos 7160

Primero de que no hay mejor o peor de todo se trata de un asunto de opinión. Está muy correcto que este es ineficiente. Puede ser optimizado o no depende. Por lo general, usted va a ver estos tipos de funciones, reloj, gpio, temporizador, etc en distintos archivos/directorios. Los compiladores generalmente no han sido capaces de optimizar a través de estas brechas, hay uno que puede, que yo sepa, pero, no es ampliamente usado para cosas como esta.

solo archivo:

void dummy ( unsigned int );

void setCLK()
{
    //code to set the clock
    dummy(5);
}
void setConfig()
{
    //code to set the config
    dummy(6);
}
void setSomethingElse()
{
   //1 line code to write something to a register.
    dummy(7);
}
void initModule()
{
   setCLK();
   setConfig();
   setSomethingElse();
}

Escoger un destino y el compilador para fines de demostración.

Disassembly of section .text:

00000000 <setCLK>:
   0:   e92d4010    push    {r4, lr}
   4:   e3a00005    mov r0, #5
   8:   ebfffffe    bl  0 <dummy>
   c:   e8bd4010    pop {r4, lr}
  10:   e12fff1e    bx  lr

00000014 <setConfig>:
  14:   e92d4010    push    {r4, lr}
  18:   e3a00006    mov r0, #6
  1c:   ebfffffe    bl  0 <dummy>
  20:   e8bd4010    pop {r4, lr}
  24:   e12fff1e    bx  lr

00000028 <setSomethingElse>:
  28:   e92d4010    push    {r4, lr}
  2c:   e3a00007    mov r0, #7
  30:   ebfffffe    bl  0 <dummy>
  34:   e8bd4010    pop {r4, lr}
  38:   e12fff1e    bx  lr

0000003c <initModule>:
  3c:   e92d4010    push    {r4, lr}
  40:   e3a00005    mov r0, #5
  44:   ebfffffe    bl  0 <dummy>
  48:   e3a00006    mov r0, #6
  4c:   ebfffffe    bl  0 <dummy>
  50:   e3a00007    mov r0, #7
  54:   ebfffffe    bl  0 <dummy>
  58:   e8bd4010    pop {r4, lr}
  5c:   e12fff1e    bx  lr

Esto es lo que la mayoría de las respuestas que aquí se están diciendo, que son ingenuos y que todo esto se pone optimizado y las funciones son eliminados. Así que no se quitan como están definidos a nivel global por defecto. Se pueden quitar si no se necesita fuera de este archivo.

void dummy ( unsigned int );

static void setCLK()
{
    //code to set the clock
    dummy(5);
}
static void setConfig()
{
    //code to set the config
    dummy(6);
}
static void setSomethingElse()
{
   //1 line code to write something to a register.
    dummy(7);
}
void initModule()
{
   setCLK();
   setConfig();
   setSomethingElse();
}

quita ahora como lo estan alineadas.

Disassembly of section .text:

00000000 <initModule>:
   0:   e92d4010    push    {r4, lr}
   4:   e3a00005    mov r0, #5
   8:   ebfffffe    bl  0 <dummy>
   c:   e3a00006    mov r0, #6
  10:   ebfffffe    bl  0 <dummy>
  14:   e3a00007    mov r0, #7
  18:   ebfffffe    bl  0 <dummy>
  1c:   e8bd4010    pop {r4, lr}
  20:   e12fff1e    bx  lr

pero la realidad es que cuando usted toma en el chip proveedor o BSP bibliotecas

Disassembly of section .text:

00000000 <_start>:
   0:   e3a0d902    mov sp, #32768  ; 0x8000
   4:   eb000010    bl  4c <initModule>
   8:   eafffffe    b   8 <_start+0x8>

0000000c <dummy>:
   c:   e12fff1e    bx  lr

00000010 <setCLK>:
  10:   e92d4010    push    {r4, lr}
  14:   e3a00005    mov r0, #5
  18:   ebfffffb    bl  c <dummy>
  1c:   e8bd4010    pop {r4, lr}
  20:   e12fff1e    bx  lr

00000024 <setConfig>:
  24:   e92d4010    push    {r4, lr}
  28:   e3a00006    mov r0, #6
  2c:   ebfffff6    bl  c <dummy>
  30:   e8bd4010    pop {r4, lr}
  34:   e12fff1e    bx  lr

00000038 <setSomethingElse>:
  38:   e92d4010    push    {r4, lr}
  3c:   e3a00007    mov r0, #7
  40:   ebfffff1    bl  c <dummy>
  44:   e8bd4010    pop {r4, lr}
  48:   e12fff1e    bx  lr

0000004c <initModule>:
  4c:   e92d4010    push    {r4, lr}
  50:   ebffffee    bl  10 <setCLK>
  54:   ebfffff2    bl  24 <setConfig>
  58:   ebfffff6    bl  38 <setSomethingElse>
  5c:   e8bd4010    pop {r4, lr}
  60:   e12fff1e    bx  lr

Usted es la mayoría, sin duda va a empezar a agregar generales, lo que tiene un notable costo de rendimiento y espacio. Un par de a cinco por ciento de cada uno según el tamaño de cada función.

¿Por qué se hace esto de todos modos? Algunos de los es el conjunto de reglas profesores quieren o todavía enseñan a hacer de clasificación código sea más fácil. Funciones que debe caber en una página (de nuevo cuando impresa de su trabajo en el papel), no hacen este no hacerlo, etc. Mucho de esto es hacer que las bibliotecas de los nombres comunes para diferentes objetivos. si usted tiene decenas de familias de microcontroladores, algunos de los cuales compartir periféricos algunos no, tal vez tres o cuatro diferentes uart sabores mezclados en las familias, diferentes gpios, spi controladores, etc. Usted puede tener un genérico gpio_init() función, get_timer_count(), etc. Y re-uso de esas abstracciones para los diferentes periféricos.

Se convierte en un caso de la mayoría de la capacidad de mantenimiento y diseño de software, con algún posible mejorar la legibilidad. la facilidad de mantenimiento, la legibilidad, el rendimiento no puedes tener todo lo que sólo puede elegir uno o dos a la vez, no todos los tres.

Esto es en gran parte una opinión basada en cuestión, el de arriba muestra las tres principales maneras en que esto puede ir. En cuanto a qué camino es MEJOR que es estrictamente la opinión. Está haciendo todo el trabajo en una sola función? Una opinión basada en cuestión, algunas personas lo lean para el rendimiento, algunos definen la modularidad y su versión de la legibilidad como la MEJOR. El interesante tema con lo que mucha gente llama la legibilidad es un dolor intenso, para "ver" el código debe tener 50-10000 archivos abiertos a la vez y de alguna manera intentar linealmente ver las funciones en el orden de ejecución para ver lo que está pasando. Me parece que el opuesto de la legibilidad, para otros resulta legible, ya que cada elemento encaja en la pantalla o de la ventana del editor y puede ser consumido en su totalidad después de que han aprendido de memoria las funciones que se llama y/o tener un editor que pueden aparecer dentro y fuera de cada función dentro de un proyecto.

Que es otro factor importante cuando ves a diversas soluciones. Los editores de texto/IDEs/etc están muy personal que va más allá de la vi vs emacs. La programación de la eficiencia, las líneas por día/mes si usted se sienta cómodo y eficiente, con la herramienta que está utilizando. Las características de la herramienta puede intencionalmente o no inclinarse hacia cómo los fans de la herramienta de escritura de código. Y, como resultado, si una persona está escribiendo estas bibliotecas el proyecto en cierta medida, el reflejo de estos hábitos. Incluso si es un equipo, el desarrollador líder o jefe de los hábitos y preferencias puede ser forzado en el resto del equipo.

Estándares de codificación que tiene un montón de preferencias personales enterrados en ellos, muy religiosa vi vs emacs de nuevo, fichas vs espacios, cómo soportes están alineados, etc. Y estos juegan en cómo las bibliotecas están diseñados para cierta medida.

¿Cómo SE debe escribir el tuyo? Sin embargo, se quiere, en realidad no es una respuesta equivocada si funciona, no es mala, o de riesgo de código seguro, pero si está escrita de tal manera que usted puede mantener es necesario que cumpla con sus objetivos de diseño, renunciar a la legibilidad y algunos mantenibilidad si el rendimiento es importante, o viceversa. ¿Te gusta el corto nombres de variables, de modo que una sola línea de código se ajuste al ancho de la ventana del editor? Largo o demasiado nombres descriptivos para evitar la confusión, pero la legibilidad va hacia abajo, porque usted no puede obtener una línea en una página, ahora es visualmente roto, jugando con el flujo.

Usted no va a golpear un home run en el primer turno al bate, se puede/debe tomar décadas para definir realmente su estilo, al mismo tiempo, con el tiempo, su estilo puede cambiar, apoyado de una forma un rato, luego se inclina otro.

Usted va a escuchar un montón de no optimizar, nunca optimizar prematura de optimización. Pero como se muestra diseños como este desde el principio crear problemas de rendimiento, a continuación, empezar a ver hacks para resolver el problema en lugar de re-diseño desde el principio a realizar. Estoy de acuerdo en que hay situaciones, es una función solo un par de líneas de código que usted puede intentar es difícil de manipular el compilador basado en un miedo de lo que el compilador va a hacer lo contrario (nota con experiencia en este tipo de codificación se convierte en fácil y natural, la optimización de escribir sabiendo cómo el compilador va a compilar el código), entonces usted quiere confirmar que el ciclo stealer realmente es, antes de atacar.

También es necesario el diseño de su código para que el usuario, en cierta medida, si este es su proyecto, usted es el único desarrollador, su lo que quieras, si usted está tratando de hacer una biblioteca para regalar o vender, es probable que desee para hacer que el código se parece a todas las otras bibliotecas, cientos de miles de archivos con pequeñas funciones, largo de nombres de funciones, y a la larga los nombres de las variables. A pesar de los problemas de legibilidad y problemas de rendimiento, la OMI encontrará más gente va a ser capaz de usar ese código.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X