关注+星号公众号,不容错过精彩
作者:HywelStar
根据上一章节了解perf 工具的定义和用法,本章节将以实例进行去使用它,帮助在开发过程中去优化程序代码,让系统能够达到一个最优。
上一章:掌握性能分析工具Perf(一)
1. perf stat 整体性能分析
使用 perf stat
来获取程序的整体性能统计信息:
perf stat ./hywelstar_perf_demo
从这些统计信息中,我们可以得出以下结论:
程序的总运行时间为 13 秒。 CPU 利用率非常高(1.010 CPUs utilized)。 程序产生了 9831 次页面错误(page-faults),这可能是由于内存分配导致的。 每个周期执行了 0.85 条指令,说明存在一定的性能瓶颈。
2. perf record 详细分析
为了进一步定位性能瓶颈,我们使用 perf record
记录程序运行期间的详细性能数据:
perf record -g ./hywelstar_perf_demo
然后使用 perf report
分析记录的数据:
perf report
通过这个report
在 perf report
中,我们可以看到各个函数的运行时间分布,以及各个函数的调用关系。通过这个工具,我们可以找出哪些函数占用了大部分的CPU时间。cpu_intensive_task
, 原函数确实是在做一些耗时工作。这样就可以进行去优化。
3. 使用 perf annotate 查看热点代码
对于占用大量CPU时间的函数,可以使用 perf annotate
查看这些函数的具体代码执行情况。
perf annotate
从图中将展现热点代码,左边是运行时间的比例,右边的对照的代码,可以通过方向上下移动,查看函数之间的关系。
4. 使用perf top 进行监控
开发过程中可以通过perf top
进行实时的性能监控。
perf top -p <pid>
5. 总结
从上面这个例子查看,cpu_intensive_task
函数中,绝大部分时间消耗在以下几条指令上:
cvtsi2sdq
指令:将整数转换为双精度浮点数。comisd
指令:比较两个双精度浮点数。
这种类型的任务是计算密集型的,优化方法包括:
减少不必要的浮点数转换:检查算法是否可以优化,减少或避免浮点数的使用。 并行化计算:如果可能,可以使用多线程或SIMD指令集来并行处理这些计算任务。
在实际开发过程中,优化也需要去查看自身的代码涉及性能相关的问题,一般来说通过perf 工具可以轻松找到相关问题,另外还可以通过生成火焰图进行更加直观找到问题的位置。
本案例源码 hywelstar_perf_demo.c
:
// 示例函数,模拟计算密集型任务
void cpu_intensive_task() {
for (long i = 0; i < 1e8; i++);
}
// 示例函数,模拟缓存未命中任务
void cache_miss_task() {
int *array = (int*)malloc(1e7 * sizeof(int));
for (long i = 0; i < 1e7; i++) {
array[i] = i;
}
free(array);
}
// 示例函数,模拟上下文切换任务
void* context_switch_task(void *arg) {
cpu_intensive_task();
return NULL;
}
// 示例函数,模拟热点函数
void hotspot_function() {
for (int i = 0; i < 100; i++) {
cpu_intensive_task();
}
}
// 示例函数,模拟系统调用
void system_call_task() {
for (int i = 0; i < 1000; i++) {
FILE *fp = fopen("/dev/null", "w");
fprintf(fp, "test\n");
fclose(fp);
}
}
// 示例函数,模拟锁竞争
pthread_mutex_t lock;
void* lock_task(void *arg) {
pthread_mutex_lock(&lock);
cpu_intensive_task();
pthread_mutex_unlock(&lock);
return NULL;
}
int main() {
// CPU 密集型任务
printf("Running CPU intensive task...\n");
cpu_intensive_task();
// 缓存未命中任务
printf("Running cache miss task...\n");
cache_miss_task();
// 上下文切换任务
printf("Running context switch task...\n");
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, context_switch_task, NULL);
pthread_create(&thread2, NULL, context_switch_task, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
// 热点函数
printf("Running hotspot function...\n");
hotspot_function();
// 系统调用任务
printf("Running system call task...\n");
system_call_task();
// 锁竞争任务
printf("Running lock contention task...\n");
pthread_mutex_init(&lock, NULL);
pthread_create(&thread1, NULL, lock_task, NULL);
pthread_create(&thread2, NULL, lock_task, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_mutex_destroy(&lock);
return 0;
}
往期推荐