小编wei*_*huo的帖子

为什么英特尔这些年来改变了静态分支预测机制?

这里我知道英特尔近年来实施了几种静态分支预测机制:

  • 80486年龄:永远不被采取

  • Pentium4年龄:未采取后退/前锋

  • 像Ivy Bridge,Haswell这样的新型CPU变得越来越无形,请参阅Matt G的实验.

英特尔似乎不想再谈论它,因为我在英特尔文档中找到的最新资料大约是十年前写的.

我知道静态分支预测(远远不是)比动态更重要,但在很多情况下,CPU将完全丢失,程序员(使用编译器)通常是最好的指南.当然,这些情况通常不是性能瓶颈,因为一旦频繁执行分支,动态预测器就会捕获它.

由于英特尔不再在其文档中明确声明动态预测机制,因此GCC的builtin_expect()只能从热路径中删除不太可能的分支.

我不熟悉CPU的设计,我不知道究竟是什么机制,目前英特尔使用其静态预测,但我还是觉得英特尔的最佳机制应该清楚地记录他的CPU",我打算去当动态预测失败,向前或向后',因为通常程序员是当时最好的指南.

更新:
我发现你提到的主题逐渐超出我的知识范围.这里涉及一些动态预测机制和CPU内部细节,我在两三天内无法学习.所以请允许我暂时退出你的讨论并充电.
这里仍然欢迎任何答案,也许会帮助更多人

compiler-construction x86 intel cpu-architecture branch-prediction

9
推荐指数
3
解决办法
1637
查看次数

什么时候我们应该关心缓存缺失?

我想通过我在项目中遇到的实际问题来解释我的问题.

我正在编写ac库(其行为类似于可编程vi editor),我计划提供一系列API(总共超过20个):

void vi_dw(struct vi *vi);
void vi_de(struct vi *vi);
void vi_d0(struct vi *vi);
void vi_d$(struct vi *vi);
...
void vi_df(struct vi *, char target);
void vi_dd(struct vi *vi);
Run Code Online (Sandbox Code Playgroud)

这些API不执行核心操作,它们只是包装器.例如,我可以vi_de()像这样实现:

void vi_de(struct vi *vi){
    vi_v(vi);  //enter visual mode
    vi_e(vi);  //press key 'e'
    vi_d(vi);  //press key 'd'
}
Run Code Online (Sandbox Code Playgroud)

但是,如果包装器就这么简单,我必须编写20多个类似的包装器函数.
所以,我考虑实现更复杂的包装器来减少数量:

void vi_d_move(struct vi *vi, vi_move_func_t move){
   vi_v(vi);
   move(vi);
   vi_d(vi);
}
static inline void vi_dw(struct vi *vi){
    vi_d_move(vi, vi_w);
}
static inline void vi_de(struct vi *vi){
    vi_d_move(vi, …
Run Code Online (Sandbox Code Playgroud)

c vim caching

7
推荐指数
1
解决办法
402
查看次数

为什么gcc没有为此函数决定是否为inline-or-not?

从网上的一些话来看,我知道GCC足够聪明,可以决定是否内联函数.该inline关键词是只是一个提示:
GCC可以内嵌一个共同的功能,并且可以不内联的内联函数.

但是对于我的项目中的这个功能:

struct vb_pos{
    union{
        struct{
            int offset;
            int l;
        };
        unsigned long long g_offset;    
    };
};
static inline void vi_write_vtail_smart(struct vi *vi){
    struct vb_pos *vhead, *vtail, *cursor;
    vhead = &vi->v_head;                    
    vtail = &vi->v_tail;
    cursor = &vi->cursor;

    int curoff = vi->curr - vi->lines[vi->currl].buf;
    cursor->offset = curoff;    

    if(cursor->g_offset >= vhead->g_offset){
        *vtail = *cursor;
    }
    else{
        *vtail = *vhead;
        *vhead = *cursor;
    }
}
Run Code Online (Sandbox Code Playgroud)

用-O2编译.
我检查了汇编代码,并且知道这个函数是按预期内联的.
但是,当我删除它的inline修饰符并重新编译时,我发现它并不是独行侠.它的函数体出现在最终的二进制文件中:

0000000000000000 <vi_write_vtail_smart>:
       0:       48 63 47 …
Run Code Online (Sandbox Code Playgroud)

c c++ gcc

5
推荐指数
1
解决办法
325
查看次数

为什么GCC没有将'printf'优化为'put'?

这是我的测试代码:

#include<stdio.h>

static inline void foo(int a){
    printf("%x\n", a);  
}

int main(void){
    foo(0x1234);    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我认为GCC应该意识到这a是一个文字整数,并优化代码如下:

puts("1234");
Run Code Online (Sandbox Code Playgroud)

但是我得到了以下汇编代码:

?0x8048341 <main+17>     push   $0x1234                                        
?0x8048346 <main+22>     push   $0x80484e0                                  
?0x804834b <main+27>     push   $0x1                                        
?0x804834d <main+29>     call   0x8048310 <__printf_chk@plt> 
Run Code Online (Sandbox Code Playgroud)

在我的项目中存在很多这样的代码,因为我一直相信GCC会为我优化,甚至在某些可以简单地使用'write()'的上下文中,我坚持使用printf,因为我认为我会从中受益缓冲机制.

现在我感到遗憾,因为削减格式字符串的开销将会扼杀任何我获得的收益.我项目中的这些代码非常低级,可能会导致性能瓶颈.

c assembly gcc compiler-optimization

2
推荐指数
1
解决办法
889
查看次数