我希望计算c代码中特定函数的时钟周期计数,该函数将在BeagleBone黑色上编译和运行。我不知道该怎么做。我在网上搜索发现了这样的指令:
阿恩代尔板上的时钟读取方法:
步骤-1:插入内核模块以允许用户空间访问PMU计数器.解压附带的文件“arndale_clockread.tar.bz2”,它具有Makefile和enableccnt.c。在Makefile中,用内核源目录(例如/usr/src/linux-kernel-version )修改“KERNELDIR”,然后运行命令。
linaro@linaro-server:~/enableccnt$ make上面的命令应该以enableccnt.ko的形式给出输出,它是内核模块,用于支持对PMU计数器的用户空间访问。然后运行命令。
linaro@linaro-server:~/enableccnt$ sudo insmod enableccnt.ko下面的命令应该显示enableccnt模块被插入到正在运行的内核中。
linaro@linaro-server:~/enableccnt$ lsmod步骤2:从用户空间应用程序读取计数器的。一旦内核模块被设置。下面的函数可用于读取计数器
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;
}我认为这个指令应该适用于任何ARMv7平台。因此,我按照指令并更改内核源目录。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现在,当我运行make时,我得到了这个错误,它是对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我试着安装arm-linux-gnueabihf-ar,但它不起作用。所以,我不知道我现在该怎么做!
正如注释中提到的EDIT1 1-,我使用以下方法将工具链路径添加到环境变量中:
export PATH=/path/to/mytoolchain/bin:$PATH现在我不知道以前的错误了。但是,我发现了这个语法错误,我认为它与内核头文件有关:
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我想到的唯一合理的解决方案是下载内核源代码及其头文件,然后再次尝试。有人想办法解决这个问题吗?
发布于 2015-12-07 16:58:34
由于在此过程中可能存在许多障碍,下面是如何构建内核模块和用户空间应用程序的完整指南。
工具链
首先,您需要下载并安装两个工具链:
我建议您使用Linaro工具链,因为它们是免费的,可靠的,并且很好地优化了ARM。这里您可以选择所需的工具链(在"Linaro“部分)。在BeagleBone Black上,默认情况下您有很少的endian体系结构(就像在大多数ARMv7处理器上一样),所以请下载下面两个档案:
下载后,将这些档案解压缩到/opt目录中。
核源
首先,您需要知道到底使用了哪些内核源来构建闪烁到您的板上的内核。您可以尝试(通过您的董事会修订)从这里中找出这一点。或者,您可以构建自己的内核,将其闪现到您的板上,现在您可以确切地知道使用的是哪个内核版本。
无论如何,您需要下载正确的内核源(它们对应于您的板上的内核)。这些源将进一步用于构建内核模块。如果内核版本不正确,那么在加载模块时就会出现“神奇的错配”错误或类似的错误。
我将使用来自稳定的kernel.org内核源代码作为引用(至少应该足以构建模块)。
构建内核
在终端中运行下一步命令,为内核构建配置shell环境(裸金属工具链):
$ export PATH=/opt/gcc-linaro-5.1-2015.08-x86_64_arm-eabi/bin:$PATH
$ export CROSS_COMPILE=arm-eabi-
$ export ARCH=arm使用defconfig为您的板配置内核(来自arch/arm/configs/)。例如,我将使用omap2plus_defconfig:
$ make omap2plus_defconfig现在要么构建整个内核:
$ make -j4或者准备构建外部模块所需的内核文件:
$ make prepare
$ make modules_prepare在第二种情况下,模块将没有依赖列表,在加载时可能需要使用“强制”选项。因此,首选选项是构建整个内核。
核模块
注意到:我要进一步使用的代码来自这个答案。
首先,您需要为用户空间访问启用ARM性能计数器(详细信息为这里)。它只能在内核空间中完成。下面是您可以使用的模块代码和Makefile:
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构建内核模块
使用前面步骤中配置的shell环境,让我们再导出一个环境变量:
$ export KDIR=/path/to/your/kernel/sources/dir现在就跑吧:
$ make模块构建(perfcnt_enable.ko文件)。
用户空间应用
一旦在内核空间(通过内核模块)启用了ARM性能计数器,您就可以在用户空间应用程序中读取其值。以下是此类应用程序的示例。
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注意,我添加了-static选项,以防使用Android等。如果您的发行版有固定的libc,您可能可以删除该标志以减小结果二进制文件的大小。
构建用户空间应用程序
准备shell环境(Linux工具链):
$ export PATH=/opt/gcc-linaro-5.1-2015.08-x86_64_arm-linux-gnueabihf/bin:$PATH
$ export CROSS_COMPILE=arm-linux-gnueabihf-构建应用程序:
$ make输出二进制是perfcnt_test。
测试
https://stackoverflow.com/questions/34081183
复制相似问题