Pregunta

¿Cómo se puede medir la cantidad de tiempo que tardará en ejecutarse una función?

Esta es una función relativamente corta y el tiempo de ejecución probablemente estaría en el rango de milisegundos.

Esta pregunta en particular se relaciona con un sistema integrado, programado en C o C++.

¿Fue útil?

Solución

La mejor manera de hacerlo en un sistema integrado es establecer un pin de hardware externo cuando ingresa a la función y borrarlo cuando sale de la función.Esto se hace preferiblemente con algunas instrucciones de ensamblaje para no sesgar demasiado los resultados.

Editar:Uno de los beneficios es que puede hacerlo en su aplicación real y no necesita ningún código de prueba especial.Pines de depuración externos como ese son (¡deberían ser!) una práctica estándar para todos los sistemas integrados.

Otros consejos

Hay tres posibles soluciones:

Solución de hardware:

Utilice un pin de salida libre en el procesador y conecte un osciloscopio o analizador lógico al pin.Inicialice el pin a un estado bajo, justo antes de llamar a la función que desea medir, afirme el pin a un estado alto y justo después de regresar de la función, desactive el pin.


    *io_pin = 1;
    myfunc();
    *io_pin = 0;

Solución de ratón de biblioteca:

Si la función es bastante pequeña y puede administrar el código desensamblado, puede abrir el libro de datos de la arquitectura del procesador y contar los ciclos que le tomará al procesador ejecutar cada instrucción.Esto le dará la cantidad de ciclos necesarios.
Tiempo = # ciclos * Velocidad del reloj del procesador / ticks del reloj por instrucciones

Esto es más fácil de hacer para funciones más pequeñas o código escrito en ensamblador (para un microcontrolador PIC, por ejemplo)

Solución de contador de marca de tiempo:

Algunos procesadores tienen un contador de marca de tiempo que aumenta rápidamente (cada pocos tictac del reloj del procesador).Simplemente lea la marca de tiempo antes y después de la función.Esto le dará el tiempo transcurrido, pero tenga en cuenta que es posible que tenga que lidiar con el contador.

Invócalo en un bucle con un montón de invocaciones, luego divídelo por el número de invocaciones para obtener el tiempo promedio.

entonces:

// begin timing
for (int i = 0; i < 10000; i++) {
    invokeFunction();
}
// end time
// divide by 10000 to get actual time.

Si estás usando Linux, puedes cronometrar el tiempo de ejecución de un programa escribiendo en la línea de comando:

time [funtion_name]

Si ejecuta solo la función en main() (asumiendo C++), el resto del tiempo de la aplicación debería ser insignificante.

Repito la llamada a la función muchas veces (millones), pero también empleo el siguiente método para descontar la sobrecarga del bucle:

start = getTicks();

repeat n times {
    myFunction();
    myFunction();
}

lap = getTicks();

repeat n times {
    myFunction();
}

finish = getTicks();

// overhead + function + function
elapsed1 = lap - start;

// overhead + function
elapsed2 = finish - lap;

// overhead + function + function - overhead - function = function
ntimes = elapsed1 - elapsed2;

once = ntimes / n; // Average time it took for one function call, sans loop overhead

En lugar de llamar a la función() dos veces en el primer bucle y una vez en el segundo bucle, puedes llamarla una vez en el primer bucle y no llamarla en absoluto (es decir,bucle vacío) en el segundo, sin embargo, el compilador podría optimizar el bucle vacío, lo que le dará resultados de sincronización negativos :)

start_time = timer
function()
exec_time = timer - start_time

Windows XP/NT Embedded o Windows CE/Mobile

Puede utilizar QueryPerformanceCounter() para obtener el valor de un contador MUY RÁPIDO antes y después de su función.Luego restas esos valores de 64 bits y obtienes un "tics" delta.Usando QueryPerformanceCounterFrequency() puedes convertir los "tics delta" a una unidad de tiempo real.Puede consultar la documentación de MSDN sobre esas llamadas WIN32.

Otros sistemas integrados

Sin sistemas operativos o con SO solo básicos tendrás que:

  • Programe uno de los temporizadores internos de la CPU para que se ejecute y cuente libremente.
  • configúrelo para generar una interrupción cuando el temporizador se desborde, y en esta rutina de interrupción incremente una variable de "transporte" (esto es para que pueda medir un tiempo más largo que la resolución del temporizador elegido).
  • antes de su función, guarda AMBOS el valor de "transporte" y el valor del registro de la CPU que contiene los ticks en ejecución para el temporizador de conteo que configuró.
  • Lo mismo después de tu función.
  • restarlos para obtener un tic del contador delta.
  • a partir de ahí, es sólo cuestión de saber cuánto tiempo significa un tic en su CPU/Hardware dado el reloj externo y la desmultiplicación que configuró mientras configuraba su temporizador.Multiplica esa "longitud de tics" por los "tics delta" que acaba de obtener.

MUY IMPORTANTE No olvide deshabilitar antes y restaurar las interrupciones después de obtener esos valores del temporizador (tanto el valor de acarreo como el de registro); de lo contrario, corre el riesgo de guardar valores incorrectos.

NOTAS

  • Esto es muy rápido porque son solo unas pocas instrucciones de ensamblaje para deshabilitar las interrupciones, guardar dos valores enteros y volver a habilitar las interrupciones.La resta real y la conversión a unidades de tiempo real ocurre FUERA de la zona de medición del tiempo, es decir DESPUÉS de su función.
  • Es posible que desee poner ese código en una función para reutilizarlo en todos los aspectos, pero puede ralentizar un poco las cosas debido a la llamada a la función y al envío de todos los registros a la pila, además de los parámetros, y luego extraerlos nuevamente.En un sistema integrado esto puede ser significativo.Puede ser mejor que en C usar MACROS en su lugar o escribir su propia rutina de ensamblaje guardando/restaurando solo los registros relevantes.

Depende de su plataforma integrada y del tipo de sincronización que esté buscando.Para Linux integrado, hay varias formas de lograrlo.Si desea medir la cantidad de tiempo de CPU utilizado por su función, puede hacer lo siguiente:

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#define SEC_TO_NSEC(s) ((s) * 1000 * 1000 * 1000)

int work_function(int c) {
    // do some work here
    int i, j;
    int foo = 0;
    for (i = 0; i < 1000; i++) {
        for (j = 0; j < 1000; j++) {
            for ^= i + j;
        }
    }
}

int main(int argc, char *argv[]) {
    struct timespec pre;
    struct timespec post;
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &pre);
    work_function(0);
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &post);

    printf("time %d\n",
        (SEC_TO_NSEC(post.tv_sec) + post.tv_nsec) -
        (SEC_TO_NSEC(pre.tv_sec) + pre.tv_nsec));
    return 0;
}

Necesitará vincular esto con la biblioteca en tiempo real, simplemente use lo siguiente para compilar su código:

gcc -o test test.c -lrt

Quizás también quieras leer la página de manual en clock_gettime Existen algunos problemas al ejecutar este código en un sistema basado en SMP que podrían invalidar su prueba.Podrías usar algo como sched_setaffinity() o la línea de comando cpuset para forzar el código en un solo núcleo.

Si está buscando medir el tiempo del usuario y del sistema, entonces puede usar el times(NULL) que devuelve algo así como un santiamén.O puede cambiar el parámetro para clock_gettime() de CLOCK_THREAD_CPUTIME_ID a CLOCK_MONOTONIC...pero ten cuidado con envolverte con CLOCK_MONOTONIC.

Para otras plataformas, estás solo.

Dibujó

Siempre implemento una rutina de teletipo impulsada por interrupciones.Luego, esto actualiza un contador que cuenta la cantidad de milisegundos desde el inicio.Luego se accede a este contador con una función GetTickCount().

Ejemplo:

#define TICK_INTERVAL 1    // milliseconds between ticker interrupts
static unsigned long tickCounter;

interrupt ticker (void)  
{
    tickCounter += TICK_INTERVAL;
    ...
}

unsigned in GetTickCount(void)
{
    return tickCounter;
}

En su código, programaría el código de la siguiente manera:

int function(void)
{
    unsigned long time = GetTickCount();

    do something ...

    printf("Time is %ld", GetTickCount() - ticks);
}

En la terminal OS X (y probablemente también en Unix), use "time":

time python function.py

Si el código es .Net, use la clase de cronómetro (.net 2.0+) NO DateTime.Now.DateTime.Now no se actualiza con suficiente precisión y le dará resultados increíbles

Si busca una resolución inferior a milisegundos, pruebe uno de estos métodos de sincronización.Todos le brindarán una resolución en al menos decenas o cientos de microsegundos:

Si es Linux integrado, mire los temporizadores de Linux:

http://linux.die.net/man/3/clock_gettime

Java integrado, mire nanoTime(), aunque no estoy seguro de que esté en la edición integrada:

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html#nanoTime()

Si desea acceder a los mostradores de hardware, pruebe PAPI:

http://icl.cs.utk.edu/papi/

De lo contrario, siempre puedes acudir al ensamblador.Puede consultar la fuente PAPI de su arquitectura si necesita ayuda con esto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top