相关疑难解决方法(0)

使用 SIMD (System.Numerics) 编写向量和函数并使其比 for 循环更快

double[]我编写了一个函数来使用 SIMD 将数组的所有元素相加(System.Numerics.Vector,性能比 na\xc3\xafve 方法差。

\n

在我的电脑上Vector<double>.Count是 4,这意味着我可以创建一个包含 4 个值的累加器,并运行数组,按组将元素相加。

\n

例如,一个 10 元素数组,带有 4 元素累加器和 2 个剩余元素,我会得到

\n
//     | loop                  | remainder\nacc[0] = vector[0] + vector[4] + vector[8]\nacc[1] = vector[1] + vector[5] + vector[9]\nacc[2] = vector[2] + vector[6] \nacc[3] = vector[3] + vector[7] \n
Run Code Online (Sandbox Code Playgroud)\n

和结果sum = acc[0]+acc[1]+acc[2]+acc[3]

\n

下面的代码产生了正确的结果,但与仅将值相加的循环相比,速度不高

\n
public static double SumSimd(this Span<double> a)\n{\n    var n = System.Numerics.Vector<double>.Count;\n    var count = a.Length;\n    // divide array into n=4 element groups\n …
Run Code Online (Sandbox Code Playgroud)

c# arrays performance simd avx

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

故意提高 L1 缓存未命中率的程序

我目前正在尝试编写一个 L1 缺失率尽可能高的程序。

为了测量 L1 缺失率,我在 Intel Core i7 处理器上使用 MEM_LOAD_RETIRED.L1_MISS 和 MEM_LOAD_RETIRED.L1_HIT 性能计数器事件(我对填充缓冲区命中不感兴趣)。我修改了 Linux 内核,以便在每次上下文切换时提供准确的测量结果,以便我可以准确地确定每个程序的命中和未命中次数。

硬件预取器被禁用。

这是我目前拥有的代码:

#define LINE_SIZE 64
#define CACHE_SIZE 4096 * 8
#define MEM_SIZE CACHE_SIZE * 64


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

    volatile register char* addr asm ("r12") = mmap(0, MEM_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);

    volatile register unsigned long idx asm ("r13") = 0;
    volatile register unsigned long store_val asm ("r14") = 0;

    volatile register unsigned long x64 asm ("r15") = 88172645463325252ull;

    while(1) …
Run Code Online (Sandbox Code Playgroud)

c linux intel cpu-cache

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

为什么向量上的“调整大小删除”比“擦除删除”更快?

当谈到从容器中删除多个元素时,C++ 中有一个“擦除-删除”习惯用法,并且有关于替代“调整大小-删除”方式的讨论,例如,此处。人们说“擦除删除”比“调整大小删除”更好,但根据我的测试,后者在矢量上(稍微)更快。那么,当涉及到矢量时我应该使用“调整大小删除”吗?

这是我的基准测试代码:

#include <benchmark/benchmark.h>

#include <algorithm>
#include <functional>
#include <iostream>
#include <random>
#include <vector>

using namespace std;

constexpr size_t N_ELEMS = 1000000;
constexpr int MAX_VAL = N_ELEMS / 10;
constexpr int THRESH = MAX_VAL / 5 * 3;

static vector<int> generate_input() {
  vector<int> nums(N_ELEMS);

  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<> dist(0, N_ELEMS);

  std::generate(nums.begin(), nums.end(), std::bind(dist, std::ref(gen)));

  return std::move(nums);
}

static void bm_erase_remove(benchmark::State &state) {
  for (auto _ : state) {
    state.PauseTiming();
    auto nums = generate_input();
    state.ResumeTiming();
    nums.erase(std::remove_if(nums.begin(), …
Run Code Online (Sandbox Code Playgroud)

c++ benchmarking erase-remove-idiom

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

计算Linux中几个"时间"命令的平均值

我正在使用"time"命令在Linux上分析程序.问题是它的输出在统计上不是很相关,因为它只运行一次程序.是否有工具或方法可以获得平均几次"时间"运行?可能与偏差等统计信息一起?

language-agnostic linux statistics benchmarking profiling

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

测量 C 中经过的时间?

所以,我想看看我的代码中的函数需要多长时间才能运行。(实时)。最初,我有这个:

clock_t begin = clock();
my_function();
clock_t end = clock();
double time_spent = (double)(end - begin);
Run Code Online (Sandbox Code Playgroud)

但显然,这种方法存在一些问题。

  1. 它仅测量 CPU 处理我的应用程序所花费的时间。
  2. 从我所看到的来看,它仅在微秒级别上进行测量 - 这对于我的情况来说不够精确。

那么,获取函数运行时间的正确方法是什么?CPU 时间真的是正确的方法吗?我可以测量多精确?我在想纳秒级?

c time benchmarking timing microbenchmark

4
推荐指数
1
解决办法
1683
查看次数

对于启用优化的大型数组,内联汇编数组总和基准时间接近于零,即使使用结果

我编写了两个获取数组总和的函数,第一个是用 C++ 编写的,另一个是用内联汇编 (x86-64) 编写的,我比较了这两个函数在我的设备上的性能。

  • 如果在编译期间未启用-O标志,则使用内联汇编的函数几乎比 C++ 版本快 4-5 倍。

    cpp time : 543070068 nanoseconds
    cpp time : 547990578 nanoseconds
    
    asm time : 185495494 nanoseconds
    asm time : 188597476 nanoseconds
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果-O标志设置为-O1,它们会产生相同的性能。

    cpp time : 177510914 nanoseconds
    cpp time : 178084988 nanoseconds
    
    asm time : 179036546 nanoseconds
    asm time : 181641378 nanoseconds
    
    Run Code Online (Sandbox Code Playgroud)
  • 但是,如果我尝试将-O标志设置为-O2或-O3,则使用内联汇编编写的函数会得到不寻常的2-3 位纳秒性能,该性能速度很快(至少对我来说,请耐心等待,因为我对汇编编程没有扎实的经验,所以我不知道它与用 C++ 编写的程序相比有多快或多慢。)

    cpp time : 177522894 nanoseconds
    cpp time : 183816275 nanoseconds …
    Run Code Online (Sandbox Code Playgroud)

c++ optimization performance gcc inline-assembly

4
推荐指数
1
解决办法
243
查看次数

Can(x == 0)比(0 == x)更有效吗?

可能重复:
哪一个执行得更快,if(flag == 0)或if(0 == flag)?

我通常把我的平等条件写成:

if(0==x)
Run Code Online (Sandbox Code Playgroud)

和许多人一样

if(x==0) 
Run Code Online (Sandbox Code Playgroud)

这样编译器会告诉我什么时候不小心输入=而不是==.

有人告诉我,有些编译器将其实现为两个寄存器加载,而不是使用不等于零的操作,因此效率较低.

有人知道这是否是一个合理的评论?

c++

3
推荐指数
1
解决办法
243
查看次数

为什么 Java 矢量 API 与标量相比如此慢?

我最近决定尝试一下 Java 的新孵化矢量 API,看看它能达到多快。我实现了两种相当简单的方法,一种用于解析 int,另一种用于查找字符串中字符的索引。在这两种情况下,与标量方法相比,我的矢量化方法都慢得令人难以置信。

这是我的代码:

public class SIMDParse {

private static IntVector mul = IntVector.fromArray(
        IntVector.SPECIES_512,
        new int[] {0, 0, 0, 0, 0, 0, 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1},
        0
);
private static byte zeroChar = (byte) '0';
private static int width = IntVector.SPECIES_512.length();
private static byte[] filler;

static {
    filler = new byte[16];
    for (int i = 0; i < 16; i++) {
        filler[i] = zeroChar;
    }
}

public static int parseInt(String str) …
Run Code Online (Sandbox Code Playgroud)

java simd vectorization

3
推荐指数
1
解决办法
2016
查看次数

为什么 Tigerlake 的 gcc 自动矢量化使用 ymm 而不是 zmm 寄存器

我想探索 gcc (10.3) 的自动矢量化。我有以下简短的程序(请参阅https://godbolt.org/z/5v9a53aj6),它计算向量所有元素的总和:

#include <stdio.h>
#define LEN 1024

// -ffast-math -march=tigerlake -O3 -fno-unroll-loops
  
int
main()
{
  float v[LEN] __attribute__ ((aligned(64)));
  float s = 0;
  for (unsigned int i = 0; i < LEN; i++) s += v[i];
  printf("%g\n", s);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我用选项编译-ffast-math -march=tigerlake -O3 -fno-unroll-loops。由于 Tigerlake 处理器具有 avx512,我希望 gcc 自动向量化使用 zmm 寄存器,但它实际上在最内层循环中使用 ymm 寄存器(avx/avx2):

vaddps  ymm0, ymm0, YMMWORD PTR [rax]
Run Code Online (Sandbox Code Playgroud)

如果我替换-march=tigerlake为-mavx512f,则使用 zmm 寄存器:

vaddps  zmm0, zmm0, ZMMWORD PTR [rax]
Run Code Online (Sandbox Code Playgroud)

如果我只是指定,为什么不使用 …

c gcc avx auto-vectorization avx512

3
推荐指数
1
解决办法
531
查看次数

为什么一行代码性能会下降 10 倍?

代码行

\n
next += val;\n
Run Code Online (Sandbox Code Playgroud)\n

性能下降到 10 倍,我检查了 ASM 代码,而不是结果。

\n

为什么这行代码会使性能下降 10 倍?

\n

结果如下:

\n
\xe2\x9e\x9c  ~ clang-13 1.c -O3\n\xe2\x9e\x9c  ~ ./a.out\nrand_read_1\nsum = 2624b18779c40, time = 0.19s\nrand_read_2\nsum = 2624b18779c40, time = 1.24s\n
Run Code Online (Sandbox Code Playgroud)\n

CPU:Intel(R) Xeon(R) Silver 4210 CPU @ 2.20GHz

\n

这是代码:

\n
#include <stdio.h>\n#include <time.h>\n#include <stdint.h>\n#include <unistd.h>\n#include <string.h>\n#include <assert.h>\n#include <stdlib.h>\n\n#define CCR_MULTIPLY_64           6364136223846793005\n#define CCR_ADD_64                1\nstatic inline uint64_t my_rand64(uint64_t *r)\n{\n    *r = *r * CCR_MULTIPLY_64 + CCR_ADD_64;\n    return *r;\n}\n\n#define NUM 10000000UL\n\nuint64_t rand_read_1(uint64_t *ptr, uint64_t nr_words)\n{\n    uint64_t i, next, …
Run Code Online (Sandbox Code Playgroud)

c performance x86 clang

3
推荐指数
1
解决办法
192
查看次数