Linux 在海思3516上移植Oprofile----最新3.2虚拟上编译出错及解决办法

最近由于项目需求,需要将Oprofile移植到海思3516平台上。Oprofile是一款比较好用的开源的性能分析工具。它通过采样CPU来计算程序中每个部分占用的时间。应该说是比较准确的。

在安装oprofile之前,需要保证系统支持oprofile。即在系统编译内核的时候要将一下两项勾上

make menuconfig
General setup --->

[*] Profiling support
<*> OProfile system profiling

Oprofile 需要popt库和binutils库的支持,因此在安装Oprofile 之前,要先安装popt和binutils。

在安装之前需要设定几个环境变量

复制代码
export CC=arm-none-linux-gnueabi-gcc //修改成你的编译器

export CXX=arm-none-linux-gnueabi-g++ //修改成你的编译器

export CFLAGS=-static

export CXXFLAGS=-static

export CPPFLAGS=-static

export ac_cv_va_copy=C99
复制代码

一、安装popt库
下载地址:http://download.chinaunix.net/download.php?id=16763&ResourceID=8268

下载完成后,解压:

tar zxvf popt-1.7.tar.gz 

然后到目录中执行一下命令

./configure --with-kernel-support --target= <arm-hisiv100-linux> --host=<arm-hisiv100-linux> --prefix=</home/XXX/oprofile> && make && make install

--target 和 --host 都是你系统的名称。--prefix 是你要库的生成目录。 --with-kernel-support是在2.6的核才可以这样,不需要核的源码。在2.4的核上时,则需要指定--with-kernel=<核的源码路径>

编译完成之后,将生成的include和lib目录下的文件分别拷贝到交叉编译器的include和lib目录下。这样popt也就安装完成了。

二、安装binutils

下载地址:http://ftp.gnu.org/gnu/binutils/

下载完成后,解压:

tar zxvf binutils-2.20.1.tar.gz

然后在目录中执行以下命令:

./configure --with-kernel-support --target=arm-hisiv100-linux --host=arm-hisiv100-linux --enable-install-libbfd --prefix=/home/xxx/oprofile/binutils --disable-nls

--enable-install-libbfd 是为了安装bfd库,因为在默认情况下,binutils 是不安装bfd库的。这样会导致后面编译Oprofile 的时候出错

--disable-nls ,如果不增加这个选项,那么在后面编译的时候就会增加对/devel/gettext库的依赖。可能会导致后面Oprofile的编译出错。

三、安装oprofile

下载地址:http://oprofile.sourceforge.net/news/

解压:

tar zxvf oprofile-0.9.6.tar.gz

如果你是2.6的核,那么在编译之前你还需要修改几处代码,以消除对2.4核的支持(不然后面会出错的)。主要有以下几个地方(将红色部分删除)。

./daemon/Makefile.am

Line 1:

SUBDIRS = liblegacy .

Line 49:

复制代码
bin_PROGRAMS = oprofiled

oprofiled_LDADD = \
liblegacy/liblegacy.a \
../libabi/libabi.a \
../libdb/libodb.a \
../libop/libop.a \
../libutil/libutil.a
复制代码

./daemon/Makefile.in

Line 73:

oprofiled_DEPENDENCIES = liblegacy/liblegacy.a  ../libabi/libabi.a \

Line 239:

SUBDIRS = liblegacy .

Line 284:

oprofiled_LDADD = \
liblegacy/liblegacy.a \
../libabi/libabi.a \
../libdb/libodb.a \
../libop/libop.a \
../libutil/libutil.a

./daemon/oprofiled.c
Line 80:

extern struct oprofiled_ops opd_24_ops;

Line 480:

复制代码
 switch (op_get_interface()) {
case OP_INTERFACE_24:
printf("Using 2.4 OProfile kernel interface.\n");
return &opd_24_ops;
case OP_INTERFACE_26:
printf("Using 2.6+ OProfile kernel interface.\n");
return &opd_26_ops;
复制代码

主要就是以上的地方,可能由于版本不同等原因,行号等可能有变化。

修改完成后输入一下命令:

 ./configure --with-kernel-support --target=arm-hisiv100-linux --host=arm-hisiv100-linux --with-binutils=/home/xxx/oprofile/binutils --prefix=/home/xxx/oprofile/oprofile && make && make install 

命令执行完成之后,就在oprofile目录下生成了oprofile的文件。将这些文件拷贝到嵌入式平台上,至此,oprofile就移植成功了。


+++++++++++++++++++++++++++=

3.2版本中出现错误

18:30: error: linux/perf_event.h: No such file or directory

下载一个perf_event.h

添加__NR_perf_event_open 298

从Linux Kernel2.6.31版本开始,Linux内核开始提供一个叫__NR_perf_counter_open(最新的版本里叫__NR_perf_event_open)的系统调用。使用这个系统调用我们可以像使用文件一样打开一个Performance counter,通过设置不同的参数让这个Performance Counter统计不同的软件或硬件事件,然后就可以向读文件一样来读取这些事件的统计结果。比如我可以打开一个Performance Counter统计某一个进程的CPU Cache Miss次数。关于如何传递参数构造Performance Counter来统计不同的事件可以看这篇日志: http://tblog29.appspot.com/blog/1004

 

下面是我写的一个小程序,它为每个CPU和每个进程开一个Performance Counter,统计每个CPU上的Cache miss和每个进程上的Cache miss(不能统计每个进程在单个CPU上的事件,详见上边那篇日志)。本代码参考了 perf 的stat部分。运行需要CAP_SYS_ADMIN权限

 

1 mperf.h

C代码   收藏代码
  1. /* 
  2.  * eperf.h 
  3.  * 
  4.  *  Created on: Jan 28, 2010 
  5.  *      Author: hchen 
  6.  */  
  7.   
  8. #ifndef EPERF_H_  
  9. #define EPERF_H_  
  10. #include <time.h>  
  11. #include <asm/unistd.h>  
  12. #include "perf_event.h"  
  13.   
  14. #define MAX_COUNTERS        256  
  15. #define MAX_NR_CPUS         32  
  16. #define PROC        "/proc"  
  17. /* 
  18.  * We define u64 as unsigned long long for every architecture 
  19.  * so that we can print it with %Lx without getting warnings. 
  20.  */  
  21. typedef unsigned long long u64;  
  22. typedef signed long long   s64;  
  23. typedef unsigned int       u32;  
  24. typedef signed int     s32;  
  25. typedef unsigned short     u16;  
  26. typedef signed short       s16;  
  27. typedef unsigned char      u8;  
  28. typedef signed char    s8;  
  29.   
  30. static inline int  
  31. sys_perf_event_open(struct perf_event_attr *attr,  
  32.               pid_t pid, int cpu, int group_fd,  
  33.               unsigned long flags)  
  34. {  
  35.     attr->size = sizeof(*attr);  
  36.     //This system call is defined in asm/unistd.h, in the latest linux kernel  
  37.     //it's name has been changed to __NR_perf_event_open .  
  38.     return syscall(__NR_perf_counter_open, attr, pid, cpu, group_fd, flags);  
  39. }  
  40.   
  41. #endif /* EPERF_H_ */  

 2 eperf.c

C代码   收藏代码
  1. #include <time.h>  
  2. #include <unistd.h>  
  3. #include <stdlib.h>  
  4. #include <stdio.h>  
  5. #include <asm/unistd.h>  
  6. #include <dirent.h>  
  7.   
  8. #include "eperf.h"  
  9.   
  10. unsigned int verbose = 0;  
  11. //event to be countered  
  12. static struct perf_event_attr attrs[] = {  
  13.   { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES    }  
  14. };  
  15.   
  16. int nr_counters = 0;  
  17. static unsigned int nr_cpus             =  0; // amount of cpus  
  18.   
  19. static int          inherit             =  1;  
  20. static int          scale               =  1;  
  21. //used to save performance counter  
  22. static int          fd[MAX_COUNTERS];  
  23.   
  24. /* 
  25.  * Read out the results of a single counter: 
  26.  */  
  27. static void read_counter(int counter)  
  28. {  
  29.     u64 single_count[3];  
  30.     size_t res, nv;  
  31.   
  32.     if (fd[counter] <= 0)  
  33.         return;  
  34.   
  35.     nv = scale ? 3 : 1;  
  36.     res = read(fd[counter], single_count, nv * sizeof(u64));  
  37.   
  38.     if(res == nv * sizeof(u64)){  
  39.         if(verbose)  
  40.             printf("Counter %d: %llu\n", counter, single_count[0]);  
  41.     }else{  
  42.         fprintf(stderr, "Fail to read counter %d\n", counter);  
  43.     }  
  44. }  
  45.   
  46. void close_all_counters(){  
  47.     int counter, tn;  
  48.     tn = nr_cpus + nr_counters;  
  49.   
  50.     for (counter = 0; counter < tn; counter++){  
  51.         if (fd[counter] <= 0)  
  52.             continue;  
  53.   
  54.         close(fd[counter]);  
  55.         fd[counter] = -1;  
  56.     }  
  57.   
  58. }  
  59.   
  60. void run_perf_stat()  
  61. {  
  62.     int counter, tn;  
  63.     tn = nr_cpus + nr_counters;  
  64.   
  65.     for (counter = 0; counter < tn; counter++)  
  66.         read_counter(counter);  
  67. }  
  68.   
  69. static void create_perf_stat_counter(int counter, int pid, int system_wide)  
  70. {  
  71.     struct perf_event_attr attr; //cache miss  
  72.     memcpy(&attr, attrs, sizeof(struct perf_event_attr));  
  73.   
  74.     if (scale)  
  75.         attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |  
  76.                     PERF_FORMAT_TOTAL_TIME_RUNNING;  
  77.   
  78.     if (system_wide) {  
  79.         unsigned int cpu;  
  80.   
  81.         for (cpu = 0; cpu < nr_cpus; cpu++) {  
  82.             fd[cpu] = sys_perf_event_open(&attr, -1, cpu, -1, 0);  
  83.         }  
  84.     } else {  
  85.         attr.inherit         = inherit;  
  86.         attr.disabled        = 0;  
  87.         attr.enable_on_exec = 1;  
  88.   
  89.         fd[counter + nr_cpus] = sys_perf_event_open(&attr, pid, -1, -1, 0);  
  90.     }  
  91. }  
  92.   
  93. int main(int argc, const char **argv)  
  94. {  
  95.     if(argc > 1)  
  96.         verbose = atoi(argv[1]);  
  97.   
  98.     DIR *dir;  
  99.     struct dirent *drp;  
  100.     int run_count, p, pid;  
  101.     struct timespec tim, tim2;  
  102.     tim.tv_sec = 1; tim.tv_nsec = 0;  
  103.   
  104.     nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);//the the number of CPU  
  105.   
  106.     int counter = 0;  
  107.     /* Open /proc directory */  
  108.     if ((dir = opendir(PROC)) == NULL) {  
  109.         perror("opendir /proc error!");  
  110.         exit(4);  
  111.     }  
  112.   
  113.     //create counters for each CPU  
  114.     create_perf_stat_counter(-1, 1, 1);  
  115.   
  116.     p = 0;  
  117.     while ((p++) < 254) {  
  118.         /* Get directory entries */  
  119.         while ((drp = readdir(dir)) != NULL) {  
  120.             if (isdigit(drp->d_name[0]))  
  121.                 break;  
  122.         }  
  123.   
  124.         if (drp) {  
  125.             pid = atoi(drp->d_name);  
  126.             create_perf_stat_counter(counter, pid, 0);  
  127.             if(fd[counter] != -1)  
  128.                 counter++;  
  129.         }  
  130.   
  131.     }  
  132.   
  133.     nr_counters = counter - 1;  
  134.     /* Close /proc directory */  
  135.     closedir(dir);  
  136.   
  137.     run_count = 100;  
  138. //  for (run_idx = 0; run_idx < run_count; run_idx++) {  
  139.     while (1) {  
  140.         nanosleep(&tim , &tim2);  
  141.         run_perf_stat();  
  142.     }  
  143.   
  144.     close_all_counters();  
  145.   
  146.     return 1;  
  147. }  
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值