小编Pet*_*des的帖子

用64位替换32位循环计数器会引入疯狂的性能偏差

我一直在寻找最快的方法来处理popcount大数据.我遇到了一个很奇怪的效果:改变从循环变量unsigneduint64_t50%在我的电脑上所做的性能下降.

基准

#include <iostream>
#include <chrono>
#include <x86intrin.h>

int main(int argc, char* argv[]) {

    using namespace std;
    if (argc != 2) {
       cerr << "usage: array_size in MB" << endl;
       return -1;
    }

    uint64_t size = atol(argv[1])<<20;
    uint64_t* buffer = new uint64_t[size/8];
    char* charbuffer = reinterpret_cast<char*>(buffer);
    for (unsigned i=0; i<size; ++i)
        charbuffer[i] = rand()%256;

    uint64_t count,duration;
    chrono::time_point<chrono::system_clock> startP,endP;
    {
        startP = chrono::system_clock::now();
        count = 0;
        for( unsigned k = 0; k < …
Run Code Online (Sandbox Code Playgroud)

c++ performance x86 assembly compiler-optimization

1370
推荐指数
9
解决办法
15万
查看次数

如果我优化大小而不是速度,为什么GCC会生成15-20%的代码?

我在2009年首先注意到GCC(至少在我的项目和我的机器上)如果我优化尺寸(-Os)而不是速度(-O2-O3),则会产生明显更快的代码,我一直想知道为什么.

我设法创建(相当愚蠢)代码,显示这种令人惊讶的行为,并且足够小,无法在此处发布.

const int LOOP_BOUND = 200000000;

__attribute__((noinline))
static int add(const int& x, const int& y) {
    return x + y;
}

__attribute__((noinline))
static int work(int xval, int yval) {
    int sum(0);
    for (int i=0; i<LOOP_BOUND; ++i) {
        int x(xval+sum);
        int y(yval+sum);
        int z = add(x, y);
        sum += z;
    }
    return sum;
}

int main(int , char* argv[]) {
    int result = work(*argv[1], *argv[2]);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

如果我用-Os它编译它,执行这个程序需要0.38秒,如果用-O2 …

c++ performance gcc x86-64 compiler-optimization

430
推荐指数
6
解决办法
9万
查看次数

为什么在强度降低乘法和循环进位加法之后,这段代码的执行速度会变慢?

我正在阅读Agner Fog优化手册,并且遇到了这个例子:

double data[LEN];

void compute()
{
    const double A = 1.1, B = 2.2, C = 3.3;

    int i;
    for(i=0; i<LEN; i++) {
        data[i] = A*i*i + B*i + C;
    }
}
Run Code Online (Sandbox Code Playgroud)

Agner 指出,有一种方法可以优化此代码 - 通过认识到循环可以避免使用昂贵的乘法,而是使用每次迭代应用的“增量”。

我用一张纸来证实这个理论,首先......

理论

...当然,他是对的 - 在每次循环迭代中,我们可以通过添加“增量”,基于旧结果计算新结果。该增量从值“A+B”开始,然后每一步增加“2*A”。

所以我们将代码更新为如下所示:

void compute()
{
    const double A = 1.1, B = 2.2, C = 3.3;
    const double A2 = A+A;
    double Z = A+B;
    double Y = C;

    int i;
    for(i=0; i<LEN; i++) {
        data[i] …
Run Code Online (Sandbox Code Playgroud)

optimization assembly x86-64 simd cpu-architecture

320
推荐指数
6
解决办法
9万
查看次数

为什么处理未排序数组与使用现代 x86-64 clang 处理排序数组的速度相同?

我发现了这个流行的大约 9 岁的SO 问题,并决定仔细检查其结果。

所以,我有 AMD Ryzen 9 5950X、clang++ 10 和 Linux,我从问题中复制粘贴了代码,这是我得到的:

排序 - 0.549702s

~/d/so_sorting_faster$ cat main.cpp | grep "std::sort" && clang++ -O3 main.cpp && ./a.out
    std::sort(data, data + arraySize);
0.549702
sum = 314931600000
Run Code Online (Sandbox Code Playgroud)

未分类 - 0.546554s

~/d/so_sorting_faster $ cat main.cpp | grep "std::sort" && clang++ -O3 main.cpp && ./a.out
    // std::sort(data, data + arraySize);
0.546554
sum = 314931600000
Run Code Online (Sandbox Code Playgroud)

我很确定 unsorted 版本比 3ms 快的事实只是噪音,但它似乎不再慢了。

那么,CPU 的架构发生了什么变化(使其不再慢一个数量级)?

以下是多次运行的结果:

Unsorted: 0.543557 0.551147 0.541722 0.555599
Sorted: …
Run Code Online (Sandbox Code Playgroud)

c++ performance cpu-architecture clang branch-prediction

153
推荐指数
1
解决办法
1万
查看次数

为什么long long n = 2000*2000*2000*2000;溢出?

long long int n = 2000*2000*2000*2000;    // overflow

long long int n = pow(2000,4);            // works
long long int n = 16000000000000;         // works
Run Code Online (Sandbox Code Playgroud)

为什么第一个溢出(乘以整数文字常量以分配给 long long)?

它与第二个或第三个有什么不同?

c++ math types integer-overflow literals

149
推荐指数
6
解决办法
1万
查看次数

^ = 32背后的想法是什么,将小写字母转换为高位字母,反之亦然?

我在解决代码问题上遇到了一些问题.通常我首先检查字符是英文字母的上部还是下部,然后减去或添加32以将其转换为相应的字母.但我发现有人^= 32做了同样的事情.这里是:

char foo = 'a';
foo ^= 32;
char bar = 'A';
bar ^= 32;
cout << foo << ' ' << bar << '\n'; // foo is A, and bar is a
Run Code Online (Sandbox Code Playgroud)

我已经搜索了这方面的解释并没有找到答案.那么为什么会这样呢?

c++ ascii bit-manipulation

146
推荐指数
10
解决办法
2万
查看次数

每个程序员应该了解的内存?

我想知道Ulrich Drepper 从2007年开始对每个程序员应该知道的内容有多少仍然有效.另外,我找不到比1.0更新的版本或勘误表.

optimization x86 memory-management cpu-architecture micro-optimization

145
推荐指数
3
解决办法
2万
查看次数

陷阱和中断有什么区别?

陷阱和中断有什么区别?

如果不同系统的术语不同,那么它们在x86上意味着什么?

x86 operating-system kernel interrupt cpu-architecture

143
推荐指数
5
解决办法
16万
查看次数

132
推荐指数
4
解决办法
10万
查看次数

从函数返回结构时可能存在 GCC 错误

我相信我在实现 O'Neill 的 PCG PRNG 时在 GCC 中发现了一个错误。(Godbolt 编译器资源管理器上的初始代码

相乘后oldstate通过MULTIPLIER,(存储在RDI结果),GCC不该结果添加到INCREMENT,movabs'ingINCREMENT到RDX代替,然后把它用作rand32_ret.state的返回值

最小可重现示例(编译器资源管理器):

#include <stdint.h>

struct retstruct {
    uint32_t a;
    uint64_t b;
};

struct retstruct fn(uint64_t input)
{
    struct retstruct ret;

    ret.a = 0;
    ret.b = input * 11111111111 + 111111111111;

    return ret;
}
Run Code Online (Sandbox Code Playgroud)

生成的程序集(GCC 9.2、x86_64、-O3):

fn:
  movabs rdx, 11111111111     # multiplier constant (doesn't fit in imm32)
  xor eax, eax                # ret.a = 0
  imul rdi, rdx
  movabs rdx, 111111111111 …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc x86-64 compiler-bug

131
推荐指数
3
解决办法
6198
查看次数