versiones torvalds sistema resumida operativo linus historia linux-kernel

linux kernel - torvalds - Medición del tiempo de ejecución de una función dentro del núcleo de Linux



unix (3)

Estoy usando enlaces de Linux Security Module para agregar alguna funcionalidad personalizada a la llamada al sistema recv (). Quiero medir la sobrecarga de esta funcionalidad en comparación con el pristine recv (). He escrito un servidor TCP simple que ejecuto con y sin mi módulo. Este servidor tcp llama a una función recv () ''N'' número de veces. Mide el tiempo necesario para cada grabación con algo como:

clock_gettime(before); recv() clock_gettime(after); global_time += after - before.

Al final, imprimo el tiempo promedio para un solo recv () con "global_time / N". Permite llamar a esta hora como tiempo "user_space_avg_recv".

Dentro de mi módulo, quiero colocar funciones de medición de tiempo para calcular el tiempo de ejecución exacto de mi gancho. Probé 3 métodos.

  1. Usé jiffies de la siguiente manera:

    sj = jiffies; my_hook(); ej = jiffies; current->total_oh = ej - sj;

    Pero veo que no hay diferencia entre los valores sj y ej. Por lo tanto, total_oh no ha cambiado.

  2. Utilicé current_kernel_time () ya que pensé que devuelve el tiempo en nanosegundos. Sin embargo, una vez más, no hubo diferencia en el tiempo antes y después.

  3. Utilicé get_cycles. Imprimo los ciclos totales cuando sale el proceso. Sin embargo, cuando convierto esos valores de ciclos totales a milisegundos, sale mucho mayor que el valor "user_space_avg_recv". Esto no tiene sentido ya que el valor medido dentro del kernel siempre será menor que el valor de tiempo medido desde el espacio del usuario. Esto podría significar que no estoy midiendo usando la API correcta o que estoy cometiendo un error al convertir el valor de ciclos a milisegundos.

Básicamente estoy usando la siguiente fórmula para convertir ciclos a milisegundos:

avg overhead of my hook in milliseconds = (((cycles / 2.99) / 10^6) / N)

2.99 porque mi frecuencia de reloj es 2.99Ghz

Algunos puntos:

  • Mi programa de espacio de usuario está vinculado a un solo núcleo mediante el conjunto de afinidad.

  • Estoy usando el kernel 2.6.22.14

  • Para evitar que el kernel cambie de contexto mientras estoy dentro de mi gancho, uso preempt_disable () y preempt_enable (). Por lo tanto, no contará los tiempos de ejecución de otros subprocesos del núcleo. Incluso entonces, dado que mi gancho usa alguna E / S, mi hilo podría liberar el control voluntariamente o podría producirse una interrupción que podría aumentar el recuento total de ciclos.

Pregunta: ¿Cómo puedo medir con precisión los tiempos de ejecución de funciones dentro del núcleo?


¿Has probado con OProfile?


No estoy seguro de que obtenga el resultado que desea, pero usamos el siguiente código para tener microsegundos.

double Microsecs() { static struct timeval _t; static struct timezone tz; gettimeofday(&_t, &tz); return (double)_t.tv_sec + (double)_t.tv_usec/(1000*1000); }

Que lo llame antes y después de la llamada que desea y vea cuántas veces.
Hemos estado usando este método para evaluar la operación de lectura / escritura / búsqueda de tiempo de IO para optimizar el rendimiento y estamos obteniendo buenos resultados.

HTH.


Puede utilizar la función de seguimiento de la API para obtener un seguimiento de todas las llamadas y devoluciones de funciones, con marcas de tiempo de alta precisión. Esto incluye eventos de interrupción y cambios de contexto. Luego, puede analizar la traza resultante en el espacio de usuario para tener una idea precisa de cuánto tarda en ejecutarse su función.

Si no puede usar la función de seguimiento de la API, puede llamar a la llamada do_gettimeofday() para obtener una marca de tiempo de resolución de microsegundos, o getnstimeofday() para una resolución de nanosegundos. Estas son las mismas funciones que utiliza internamente la llamada gettimeofday() del espacio de usuario. Por supuesto, para funciones muy rápidas esto puede no ser suficiente precisión; con una precisión más rápida que eso, y probablemente deba profundizar en el código del temporizador para ver cómo implementa las conversiones de ciclo. Tenga en cuenta también que el hecho de que tengan una alta resolución no significa que tengan tanta precisión, sino que deberían ser útiles para fines de evaluación comparativa.

Tenga en cuenta que cualquier forma de seguimiento resultará en una latencia adicional: do_gettimeofday() requiere una serie de operaciones atómicas de comparación e intercambio, y ftrace coloca el código de registro en cada función previa y posterior . Debe tener esto en cuenta al interpretar los resultados.