C++动态性能验证

在对代码性能验证过程中,我们需要知道哪些部分是代码性能的瓶颈,这个过程需要对C++程序进行相应的动态性能验证,本文将针对动态验证的过程进行一些介绍,并针对AMD uProf性能验证工具的一些使用方法进行总结。

Profile原理

常见的性能分析程序原理一般分为三个阶段“

阶段 描述
数据收集 运行程序并收集分析数据
翻译 将分析数据集成并保存至一个DB中
分析 针对数据进行分析,获得性能瓶颈

下面将针对数据收集阶段具体工作内容进行总结:

数据收集阶段

基本介绍

待分析的目标可以是应用、整个系统或某个特定进程,分析的类型可以包括CPU性能、系统级别的功率分析以及功率应用分析等。数据收集可以分为事件触发或时间片,可收集的数据包括用户层和内核层部分。

重要数据

以CPU Profiling为例,其中比较重要的数据如下:

Profile类型 数据类型 采样事件
CPU Profiling 进程及线程ID,IP,函数调用栈 Timer、基于指令的采样以及核心的性能监测器

注意事项

  1. 在进行profile过程中,我们应当尽可能避免阻塞式IO,因为将会影响验证的结果,合理的做法是提供一组验证数据,对于模块进行验证,避免人机交互带来的对于运行过程的影响。
  2. profile软件可能需要在管理员模式下使用,这样才能访问exe的源码。

uProf 使用方法1

基本界面及功能

uProf界面

uProf基本功能

  • 性能分析
  • 系统分析(IPC、内存带宽等)
  • 热及功率分析以及能量分析

支持的语言包括C/C++、Java、Assembly等,支持的调试文件格式包括PDB、COFF等。

用例分析

1 待分析源码

这里提供了一个单词、字符以及句子统计的程序以供分析,其源代码如下:

点击显/隐内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
int wordCount(const string& file){
ifstream ifs;
ifs.open(file);
string sentence, word;
int count = 0;
if(ifs.is_open()){
while ( getline (ifs,sentence) ){
istringstream sentence_stream(sentence);
while(sentence_stream >> word)
count++;
}
ifs.close();
}
else{
cout << "Unable to open the file" << endl;
}
return count;
}

int characterCount(const string& file){
ifstream ifs;
ifs.open(file);
char character;
int count = 0;
if(ifs.is_open()){
while (ifs >> character){ //以段落对文本进行读取
if(character != '\r')
count++;
}

ifs.close();
}
else{
cout << "Unable to open the file" << endl;
}
return count;
}

// 这个函数写的比较丑,没什么参考价值,不断依靠重复的对标点符号进行判断从而断句。只是做一个示例
int sentenceCount(const string& file){
ifstream ifs;
ifs.open(file);
string sentence, word;
int count = 0;
if(ifs.is_open()){

while ( getline (ifs, sentence, '.') ){ //以段落对文本进行读取
count++;
}

ifs.clear();
ifs.seekg(0);

while ( getline (ifs, sentence, '?') ){ //以段落对文本进行读取
count++;
}

ifs.clear();
ifs.seekg(0);
while ( getline (ifs, sentence, ';') ){ //以段落对文本进行读取
count++;
}

ifs.clear();
ifs.seekg(0);
while ( getline (ifs, sentence, '!') ){ //以段落对文本进行读取
count++;
}
ifs.close();
}
else{
cout << "Unable to open the file" << endl;
}
return count;
}


int main()
{
string file{"test.txt"};
cout << "Character Number:" << characterCount(file) << endl;

// 统计单词个数
cout << "Word Number: " << wordCount(file) << endl;

// 统计句子个数
cout << "Sentence Number: " <<sentenceCount(file) << endl;

return 0;
}

2 配置分析类型以及待分析应用程序所在目录

1 以管理员模式启动uProf程序,在Select Profile Target处选择Application

uProf界面

2 设置好待分析的可执行程序路径及工作目录。

3 点击Next,选择profile类型以及对应的分析手段和分析过程的一些参数等,这里详见使用文档,然后点击Start Profile。这个过程可能会提示获得数据错误,多试几次即可。

4 观察profile结果,获得性能分析结果uProf界面

下图为运行后得到的分析结果,展示了热点函数、进程、模块以及线程。点击上面的Analyze,可以进一步查看更加详细的分析结果,例如某一个具体函数所占据的运行时间为多少。从而可以发现性能瓶颈。

uProf界面

在上面的详细结果中,我们可以看出每个函数所占用的时间,可以发现我们的characterCount以及wordCount占用时间都是比较短的。不算是性能上的瓶颈。

Very Sleepy CS使用方法

由于uProf只能用于AMD的CPU,这里介绍另一个profile软件Very Sleepy CS,这个软件十分轻量化,使用也非常简单,但是也能够给我们提供比较好的分析结果。同样的,该软件应当在管理员模式下使用。

基本界面及功能

Sleepy的界面如下所示:

uProf界面

界面左上部分为当前进程,右上为待分析进程。点击File——Launch并填写待分析程序路径和执行路径后,即可开始分析,下图为分析结果。

uProf界面

在filter中我们可以查看想看的函数运行情况,从图中我们可以看出characterCount的运行情况为:

  • Inclusive(考虑函数内部调用其他函数):占比19.33%
  • Exclusive(不考虑函数内部调用其他函数):占比0.00%

当然一般我们是要考虑内部函数调用情况的。

参考文献

0%