首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

用 OProfile 彻底了解性能(3)Oprofile 分析:转移的错误预测

用 OProfile 彻底了解性能(3)Oprofile 分析:转移的错误预测

Oprofile 分析:转移的错误预测现代处理器可以实现程序转移预测(请参看 ),因为底层的算法和数据是有规律的。如果预测是正确的,那么程序转移的成本就比较低廉。然而程序转移的预测并不总是正确,并且某些程序转移是很难预测的。可以通过改进软件中的转移预测功能来解决这个问题,也可以通过评测应用程序和内核的事件来解决问题。      
清单5 中的代码显示了程序转移的错误预测。这个程序例子创建了一个与其父进程共享存储器空间的克隆线程。运行在一个处理器上的父进程根据         num_proc2 的值来切换         num_proc1 的值(并且根据由另一个处理器修改的该变量的值进行转移)。编译器简单地假设在任何时候         num_proc2 都等于 1,并且默认地为该转移生成代码 。如果         num_proc2 不等于 1,就说明发生了转移的错误预测。      
运行在另一个处理器上的克隆的线程切换          num_proc1 的值(并且根据由另一个处理器修改的该变量的值进行转移)。这导致         num_proc2 不总是等于 1,因而在父线程中发生了转移的错误预测。与此类似,由父线程切换的          num_proc1          的值导致了克隆线程中的转移的错误预测。      
清单 5. 显示错误转移预测的程序代码
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
/*shared structure between the two processes */
struct share_both {
    unsigned int num_proc1;
    unsigned int num_proc2;
};
     
/*
* The parent process clones a thread by sharing its memory space. The parent
* process just toggles the value of num_proc1 in loop.
*/
/* Declare local shared data */
struct share_both common;
    /* clones a thread with memory space same as parent thread*/
    if ((pid = clone(func1, buff+8188, CLONE_VM, &common)) < 0) {
        perror("clone");
        exit(1);
    }
    /* toggles the value of num_proc1 in loop */   
    for (j = 0; j < 200; j++)
        for(i = 0; i < 100000; i++) {
            if (common.num_proc2)
                common.num_proc1 = 0;
            else
                common.num_proc1 = 1;
        }
     
/*
* The function below is called by the cloned thread, which just toggles the
* value of num_proc2 every time in the loop.
*/
int func1(struct share_both *com)
{
    int i, j;
    /* toggles the value of num_proc2 in loop */   
    for (j = 0; j < 200; j++)
        for (i = 0; i < 100000; i++) {
            if (com->num_proc1)
                   com->num_proc2 = 0;
            else
                   com->num_proc2 = 1;
        }
}




转移的错误预测可以通过编译上面未经优化的代码来表明:
#gcc -o branch parent_thread_source_code  clone_thread_source_code
现在评测该应用程序的         BR_MISS_PRED_TAKEN_RET 事件,同时将计数设置为 500,如        清单 2 所示。注意在         main 和         func1  中收集的采样。      
另外评测同一可执行文件的          CPU_CLK_UNHALTED 事件 ,同时将计数设置为 10000,如        清单 2 所示。      
也可以通过使用编译器的 -02 选项来优化转移的错误预测:
#gcc -O2 -c clone_thread_source_code         
#gcc -o branch clone_thread_source_code.o parent_thread_source_code        
现在开始评测应用程序的          BR_MISS_PRED_TAKEN_RET  和         CPU_CLK_UNHALTED         事件 ,如        清单 2 所示。请注意性能的改善。      
让我们在下面关于内核评测的小节中考察另一个错误预测转移的例子。
返回列表