如何计算分支预测错误?

How to count branch mispredictions?

我有一个任务来计算分支预测错误的惩罚(以滴答为单位),所以我写了这段代码:

int main (int argc, char ** argv) {
    unsigned long long start, end;
    FILE *f;
    f = fopen("output", "w");
    long long int k = 0;
    unsigned long long min;
    int n = atoi(argv[1]);// n1 = atoi(argv[2]);
    for (int i = 1; i <= n + 40; i++) {
        min = 9999999999999;
        for(int r = 0; r < 1000; r++) {
            start = rdtsc();
            for (long long int j = 0; j < 100000; j++) {
                if (j % i == 0) {
                    k++;
                }
            }
            end = rdtsc();
        if (min > end - start) min = end - start;
    }
    fprintf (f, "%d %lld \n", i, min);

}
fclose (f);
return 0;
}

(rdtsc 是一个以滴答为单位测量时间的函数)

这段代码的想法是它周期性地(周期等于 i)进入分支(if (j % i == 0)),所以在某个时候它开始做错误预测。代码的其他部分主要是多次测量,我需要得到更精确的结果。

测试表明分支预测错误开始发生在 i = 47 左右,但我不知道如何计算错误预测的确切数量来计算滴答的确切数量。谁能向我解释一下,如何在不使用 Vtune 等辅助程序的情况下做到这一点?

这取决于您使用的处理器,通常 cpuid 可用于获取有关处理器的大量信息,而 cpuid 不提供的信息通常可通过 smbios 或其他内存区域访问。

在没有处理器支持功能和手册的情况下在一般级别的代码中执行此操作不会在很大程度上告诉您您想要的信息,但可能会根据您的查找内容和方式作为估计有用你有你的代码编译,例如您在编译等过程中使用的标志

通常,所谓的镜面或推测执行通常不会被程序观察到,因为它们通过管道转换的逻辑被确定为不被使用,然后被丢弃。

根据您在程序中使用特定指令的方式,您可能会更好或更坏地使用此类过时的缓存信息,但其中的逻辑会因使用的 CPU 而有很大差异。

另请参阅 Spectre 和 RowHammer,了解使用此类技术进行特权执行的有趣示例。

请参阅下面的评论以获取包含与使用 cpuid 以及 rdrand、rdseed 和其他一些代码相关的代码的链接。 (rdtsc)

您可能并不完全清楚您在寻找什么,但肯定会帮助您入门并提供一些有用的示例。

另见 Branch mispredictions