相关疑难解决方法(0)

为什么对这个数组结构体的成员求和比对结构体数组求和要快得多?

我一直在使用https://github.com/google/benchmark和g++ 9.4.0来检查不同场景下数据访问的性能(用“ -O3”编译)。结果令我惊讶。

我的基线是访问std::array(“减少数据”)中的长数。我想添加一个额外的字节数据。一次我创建一个额外的容器(“拆分数据”),一次我在数组中存储一个结构(“组合数据”)。

这是代码:

#include <benchmark/benchmark.h>

#include <array>
#include <random>

constexpr int width  = 640;
constexpr int height = 480;

std::array<std::uint64_t, width * height> containerWithReducedData;

std::array<std::uint64_t, width * height> container1WithSplitData;
std::array<std::uint8_t, width * height>  container2WithSplitData;

struct CombinedData
{
    std::uint64_t first;
    std::uint8_t  second;
};

std::array<CombinedData, width * height> containerWithCombinedData;

void fillReducedData(const benchmark::State& state)
{
    // Variable is intentionally unused
    static_cast<void>(state);

    // Generate pseudo-random numbers (no seed, therefore always the same numbers)
    // NOLINTNEXTLINE
    auto engine …
Run Code Online (Sandbox Code Playgroud)

c++ arrays caching compiler-optimization data-oriented-design

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

如何指示可以使用内联ASM参数*指向*的内存?

考虑以下小功能:

void foo(int* iptr) {
    iptr[10] = 1;
    __asm__ volatile ("nop"::"r"(iptr):);
    iptr[10] = 2;
}
Run Code Online (Sandbox Code Playgroud)

使用gcc,它将编译为

foo:
        nop
        mov     DWORD PTR [rdi+40], 2
        ret
Run Code Online (Sandbox Code Playgroud)

请特别注意,即在第一次写iptriptr[10] = 1根本不会发生:内联汇编nop是在函数的第一件事,只有最后写2(会出现ASM呼叫后)。显然,编译器决定只需要提供其iptr 自身值的最新版本,而不需要提供其指向的内存。

我可以告诉编译器,内存必须是最新的memory,就像这样:

void foo(int* iptr) {
    iptr[10] = 1;
    __asm__ volatile ("nop"::"r"(iptr):"memory");
    iptr[10] = 2;
}
Run Code Online (Sandbox Code Playgroud)

结果为预期的代码:

foo:
        mov     DWORD PTR [rdi+40], 1
        nop
        mov     DWORD PTR [rdi+40], 2
        ret
Run Code Online (Sandbox Code Playgroud)

但是,这太强了,因为它告诉编译器必须写入所有内存。例如,在以下功能中:

void foo2(int* iptr, long* …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc clang inline-assembly

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

Google 的“DoNotOptimize()”函数如何强制语句排序

我试图准确理解谷歌的DoNotOptimize()运作方式。

为了完整起见,以下是它的定义(对于 clang 和非常量数据):

template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) {
  asm volatile("" : "+r,m"(value) : : "memory");
}
Run Code Online (Sandbox Code Playgroud)

据我了解,我们可以在如下代码中使用它:

start_time = time();
bench_output = run_bench(bench_inputs);
result = time() - start_time;
Run Code Online (Sandbox Code Playgroud)

为了确保基准保持在关键部分:

start_time = time();
DoNotOptimize(bench_inputs);
bench_output = run_bench(bench_inputs);
DoNotOptimise(bench_output);
result = time() - start_time;
Run Code Online (Sandbox Code Playgroud)

具体来说,我不明白的是为什么这保证(是吗?)run_bench()不会移到上面start_time = time()

(有人在这个评论中问过这个问题,但我不明白答案)。

据我了解,上面DoNotOptimze()做了几件事:

  • 它强制value进入堆栈,因为它是通过 C++ 引用传递的。您不能有指向寄存器的指针,因此它必须位于内存中。
  • 因为value现在位于堆栈上,因此随后破坏内存(如在 asm 约束中完成的那样)将迫使编译器假设value通过调用DoNotOptimize(value).
  • (我不清楚+r,m …

benchmarking inline-assembly compiler-optimization google-benchmark instruction-reordering

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

有256位整数类型吗?

操作系统:Linux(Debian 10)

CC:GCC 8.3

CPU:i7-5775C

在GCC中有一个unsigned __int128/ __int128,但是有什么办法在GCC中有一个uint256_t/ int256_t

我读过一篇__m256i似乎来自英特尔的文章。我可以包含任何标头来获取它吗?

它像假设一样有用unsigned __int256吗?我的意思是,如果您可以为其分配/比较,比较,按位运算等。

它的等效符号是什么(如果有)?


编辑1:

我做到了:

#include <immintrin.h>
typedef __m256i uint256_t;
Run Code Online (Sandbox Code Playgroud)

并编译。如果可以进行一些操作,请在此处进行更新。


编辑2:

发现问题:

uint256_t   m;
ptrdiff_t   l = 5;

m = ~((uint256_t)1 << l);
Run Code Online (Sandbox Code Playgroud)

输出:

error: can’t convert a value of type ‘int’ to vector type ‘__vector(4) long long int’ which has different size
  m = ~((uint256_t)1 << l);
Run Code Online (Sandbox Code Playgroud)

c gcc types x86-64

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