tutorial raspberry pinout datasheet black beaglebone c linux-kernel arm beagleboneblack

raspberry - Cálculo del recuento de ciclos del reloj en ARM Cortex-a8 BeagleBone Black



beaglebone black wireless (1)

Quiero calcular el recuento del ciclo del reloj para una función específica dentro de mi código c que se compilará y ejecutará en BeagleBone Black. No tengo idea de cómo puedo hacer esto. Busqué en la web y encontré esta instrucción:

Método Clock Read en la placa de Arndale:

Paso-1: Insertar el módulo kernel para habilitar el acceso del espacio de usuario a los contadores PMU. Descomprima el archivo adjunto "arndale_clockread.tar.bz2" que tiene Makefile y enableccnt.c. En Makefile, cambie el "KERNELDIR" con su directorio fuente de kernel, por ejemplo / usr/src/linux-kernel-version luego ejecute el comando.

linaro@linaro-server:~/enableccnt$ make

El comando anterior debe dar salida como enableccnt.ko , que es un módulo kernel para permitir el acceso del espacio de usuario a los contadores PMU. Luego ejecuta el comando.

linaro@linaro-server:~/enableccnt$ sudo insmod enableccnt.ko

El siguiente comando debería mostrar que el módulo enableccnt se está insertando en el kernel en ejecución.

linaro@linaro-server:~/enableccnt$ lsmod

Paso 2: leer el contador de las aplicaciones de espacio de usuario. Una vez que el módulo kernel se está configurando. La siguiente función se puede usar para leer el contador

static void readticks(unsigned int *result) { struct timeval t; unsigned int cc; if (!enabled) { // program the performance-counter control-register: asm volatile("mcr p15, 0, %0, c9, c12, 0" :: "r"(17)); //enable all counters. asm volatile("mcr p15, 0, %0, c9, c12, 1" :: "r"(0x8000000f)); //clear overflow of coutners asm volatile("mcr p15, 0, %0, c9, c12, 3" :: "r"(0x8000000f)); enabled = 1; } //read the counter value. asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(cc)); gettimeofday(&t,(struct timezone *) 0); result[0] = cc; result[1] = t.tv_usec; result[2] = t.tv_sec; }

Creo que esta instrucción debería funcionar para cualquier plataforma ARMv7 . Entonces, seguí las instrucciones y cambio el directorio fuente del kernel. Así es como se ve el archivo Makefile:

KERNELDIR := /usr/src/linux-headers-3.8.13-bone70 obj-m := enableccnt.o CROSS=arm-linux-gnueabihf- all: CC=arm-cortex_a15-linux-gnueabihf-gcc $(MAKE) ARCH=arm -C $(KERNELDIR) M=`pwd` CROSS_COMPILE=$(CROSS) -I/lib/arm-linux-gnueabihf/lib

Ahora, cuando ejecuto make , tengo este error que se queja de arm-linux-gnueabihf-ar :

CC=arm-cortex_a08-linux-gnueabihf-gcc make ARCH=arm -C /usr/src/linux-headers-3.8.13-bone70 M=`pwd` CROSS_COMPILE=arm-linux-gnueabihf- -I/lib/arm-linux-gnueabihf/ make[1]: Entering directory `/usr/src/linux-headers-3.8.13-bone70'' LD /root/crypto_project/Arndale_enableccnt/built-in.o /bin/sh: 1: arm-linux-gnueabihf-ar: not found make[2]: *** [/root/crypto_project/Arndale_enableccnt/built-in.o] Error 127 make[1]: *** [_module_/root/crypto_project/Arndale_enableccnt] Error 2 make[1]: Leaving directory `/usr/src/linux-headers-3.8.13-bone70'' make: *** [all] Error 2

Intenté instalar arm-linux-gnueabihf-ar pero no funciona. Entonces, no tengo idea de qué debería hacer ahora.

EDIT1- Como se menciona en los comentarios, agrego mi ruta a la cadena de herramientas en mi variable de entorno usando:

export PATH=/path/to/mytoolchain/bin:$PATH

Y ahora no obtengo el error anterior. Sin embargo, tengo este error de sintaxis que creo que se relaciona con los archivos de encabezado del kernel:

CC=arm-cortex_a15-linux-gnueabihf-gcc make ARCH=arm -C /usr/src/linux-headers-3.8.13-bone70 M=`pwd` CROSS_COMPILE=arm-linux-gnueabihf- -I/lib/arm-linux-gnueabihf/bin /root/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/arm-linux-gnueabihf-gcc: 1: /root/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/arm-linux-gnueabihf-gcc: Syntax error: "(" unexpected make[1]: Entering directory `/usr/src/linux-headers-3.8.13-bone70'' LD /root/crypto_project/Arndale_enableccnt/built-in.o /root/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/arm-linux-gnueabihf-ar: 1: /root/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/arm-linux-gnueabihf-ar: Syntax error: "(" unexpected make[2]: *** [/root/crypto_project/Arndale_enableccnt/built-in.o] Error 2 make[1]: *** [_module_/root/crypto_project/Arndale_enableccnt] Error 2 make[1]: Leaving directory `/usr/src/linux-headers-3.8.13-bone70'' make: *** [all] Error 2

La única solución razonable que me viene a la mente es descargar el código fuente del núcleo con sus archivos de encabezado e intentar hacer nuevamente. ¿Alguien tiene alguna idea para resolver este problema?


Como puede haber muchos obstáculos en el camino, a continuación se encuentra la guía completa sobre cómo construir ese módulo de kernel y aplicación de espacio de usuario.

Toolchain

En primer lugar, debe descargar e instalar 2 cadenas de herramientas:

  1. Herramienta para construir kernel (y módulos kernel): bare-metal (EABI) toolchain
  2. Herramienta para construir aplicaciones de espacio de usuario: cadena de herramientas GNU / Linux

Te recomiendo que uses Linaro ARM toolchains, ya que son gratis , confiables y están bien optimizados para ARM. Aquí puede elegir las cadenas de herramientas deseadas (en la sección "Linaro Toolchain"). En BeagleBone Black tiene arquitectura little-endian por defecto (como en la mayoría de los procesadores ARMv7), así que descargue los siguientes dos archivos:

  1. linaro-toolchain-binaries (little-endian) Bare Metal
  2. linaro-toolchain-binary (little-endian) Linux

Una vez descargado, extraiga esos archivos en el directorio /opt .

Fuentes de kernel

En primer lugar, debe averiguar qué fuentes exactamente del kernel se usaron para construir el kernel que brilló en su tablero. Puede tratar de resolver eso (mediante la revisión de su placa) desde aquí . O puede construir su propio kernel, llevarlo a su tablero y ahora sabe exactamente qué versión del núcleo está en uso.

De todos modos, debe descargar las fuentes correctas del kernel (que corresponden al núcleo en su tablero). Esas fuentes se usarán más para construir el módulo kernel. Si la versión del kernel es incorrecta, tendrá el error "magic mismatch" o algo así en la carga del módulo.

Utilizaré fuentes kernel estables de kernel.org solo para referencias (al menos debería ser suficiente para compilar el módulo).

Construir kernel

Ejecute los siguientes comandos en su terminal para configurar el entorno del shell (cadena de herramientas bare-metal) para la construcción del kernel:

$ export PATH=/opt/gcc-linaro-5.1-2015.08-x86_64_arm-eabi/bin:$PATH $ export CROSS_COMPILE=arm-eabi- $ export ARCH=arm

Configure kernel usando defconfig para su placa (desde arch/arm/configs/ ). omap2plus_defconfig por ejemplo:

$ make omap2plus_defconfig

Ahora bien, construye todo el kernel:

$ make -j4

o prepare los archivos kernel necesarios para construir un módulo externo:

$ make prepare $ make modules_prepare

En el segundo caso, el módulo no tendrá una lista de dependencias y probablemente tendrá que usar la opción "forzar" al cargarlo. Entonces, la opción preferida es construir todo el kernel.

Módulo kernel

NOTA : el código que voy a usar más es de esta respuesta .

Primero necesita habilitar el contador de rendimiento ARM para el acceso de espacio de usuario (los detalles están aquí ). Se puede hacer solo en kernel-space. Aquí está el código del módulo y Makefile que puede usar para hacerlo:

perfcnt_enable.c :

#include <linux/module.h> static int __init perfcnt_enable_init(void) { /* Enable user-mode access to the performance counter */ asm ("mcr p15, 0, %0, C9, C14, 0/n/t" :: "r"(1)); /* Disable counter overflow interrupts (just in case) */ asm ("mcr p15, 0, %0, C9, C14, 2/n/t" :: "r"(0x8000000f)); pr_debug("### perfcnt_enable module is loaded/n"); return 0; } static void __exit perfcnt_enable_exit(void) { } module_init(perfcnt_enable_init); module_exit(perfcnt_enable_exit); MODULE_AUTHOR("Sam Protsenko"); MODULE_DESCRIPTION("Module for enabling performance counter on ARMv7"); MODULE_LICENSE("GPL");

Makefile :

ifneq ($(KERNELRELEASE),) # kbuild part of makefile CFLAGS_perfcnt_enable.o := -DDEBUG obj-m := perfcnt_enable.o else # normal makefile KDIR ?= /lib/modules/$(shell uname -r)/build module: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: $(MAKE) -C $(KDIR) M=$(PWD) clean .PHONY: module clean endif

Construir módulo kernel

Usando el entorno de shell configurado en el paso anterior, exportaremos una variable de entorno más:

$ export KDIR=/path/to/your/kernel/sources/dir

Ahora solo ejecuta:

$ make

El módulo está construido (archivo perfcnt_enable.ko ).

Aplicación de espacio de usuario

Una vez que el contador de rendimiento de ARM está habilitado en kernel-space (por módulo kernel), puede leer su valor en la aplicación de espacio de usuario. Aquí está el ejemplo de tal aplicación.

perfcnt_test.c :

#include <stdio.h> #include <stdlib.h> #include <unistd.h> static unsigned int get_cyclecount(void) { unsigned int value; /* Read CCNT Register */ asm volatile ("mrc p15, 0, %0, c9, c13, 0/t/n": "=r"(value)); return value; } static void init_perfcounters(int32_t do_reset, int32_t enable_divider) { /* In general enable all counters (including cycle counter) */ int32_t value = 1; /* Peform reset */ if (do_reset) { value |= 2; /* reset all counters to zero */ value |= 4; /* reset cycle counter to zero */ } if (enable_divider) value |= 8; /* enable "by 64" divider for CCNT */ value |= 16; /* Program the performance-counter control-register */ asm volatile ("mcr p15, 0, %0, c9, c12, 0/t/n" :: "r"(value)); /* Enable all counters */ asm volatile ("mcr p15, 0, %0, c9, c12, 1/t/n" :: "r"(0x8000000f)); /* Clear overflows */ asm volatile ("mcr p15, 0, %0, c9, c12, 3/t/n" :: "r"(0x8000000f)); } int main(void) { unsigned int overhead; unsigned int t; /* Init counters */ init_perfcounters(1, 0); /* Measure the counting overhead */ overhead = get_cyclecount(); overhead = get_cyclecount() - overhead; /* Measure ticks for some operation */ t = get_cyclecount(); sleep(1); t = get_cyclecount() - t; printf("function took exactly %d cycles (including function call)/n", t - overhead); return EXIT_SUCCESS; }

Makefile :

CC = gcc APP = perfcnt_test SOURCES = perfcnt_test.c CFLAGS = -Wall -O2 -static default: $(CROSS_COMPILE)$(CC) $(CFLAGS) $(SOURCES) -o $(APP) clean: -rm -f $(APP) .PHONY: default clean

Tenga en cuenta que agregué la opción -static solo en caso de que esté usando Android, etc. Si su distribución tiene libc regular, probablemente pueda eliminar ese indicador para reducir el tamaño del resultado binario.

Crear una aplicación de espacio de usuario

Preparar entorno de shell (Linux toolchain):

$ export PATH=/opt/gcc-linaro-5.1-2015.08-x86_64_arm-linux-gnueabihf/bin:$PATH $ export CROSS_COMPILE=arm-linux-gnueabihf-

Construye la aplicación:

$ make

El binario de salida es perfcnt_test .

Pruebas

  1. Cargue el módulo de núcleo y la aplicación de espacio de usuario en su placa.
  2. Cargue el módulo:

    # insmod perfcnt_enable.ko

  3. Ejecuta la aplicación:

    # ./perfcnt_test