相关疑难解决方法(0)

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

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

optimization x86 memory-management cpu-architecture micro-optimization

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

为什么std :: fill(0)比std :: fill(1)慢?

我在一个系统std::fill上观察到,与常量值或动态值相比,std::vector<int>设置常量值时,大型系统显着且持续地较慢:01

5.8 GiB/s vs 7.5 GiB/s

但是,对于较小的数据大小,结果是不同的,其中fill(0)更快:

不同数据大小的单线程性能

对于4个GiB数据大小的多个线程,fill(1)显示更高的斜率,但达到的峰值远低于fill(0)(51 GiB/s对90 GiB/s):

大数据大小的各种线程计数的性能

这提出了次要问题,为什么峰值带宽fill(1)要低得多.

测试系统是一个双插槽Intel Xeon CPU E5-2680 v3,设置为2.5 GHz(通道/sys/cpufreq),带有8x16 GiB DDR4-2133.我使用GCC 6.1.0(-O3)和英特尔编译器17.0.1(-fast)进行了测试,结果都相同.GOMP_CPU_AFFINITY=0,12,1,13,2,14,3,15,4,16,5,17,6,18,7,19,8,20,9,21,10,22,11,23被设定了.Strem/add/24个线程在系统上获得85 GiB/s.

我能够在不同的Haswell双插槽服务器系统上重现这种效果,但没有任何其他架构.例如在Sandy Bridge EP上,内存性能是相同的,而在缓存fill(0)中则要快得多.

这是重现的代码:

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <omp.h>
#include <vector>

using value = int;
using vector = std::vector<value>;

constexpr size_t write_size = 8ll * 1024 * 1024 * 1024;
constexpr size_t …
Run Code Online (Sandbox Code Playgroud)

c++ performance x86 memset compiler-optimization

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

更快的替代memcpy?

我有一个正在执行memcpy的功能,但它占用了大量的周期.有没有比使用memcpy移动内存更快的替代/方法?

c performance memcpy

37
推荐指数
5
解决办法
6万
查看次数

非常快速的图像处理memcpy?

我在C中进行图像处理,需要在内存周围复制大块数据 - 源和目标永远不会重叠.

使用GCC(其中SSE,SSE2但不是SSE3可用)在x86平台上执行此操作的绝对最快方法是什么?

我希望解决方案可以是汇编还是使用GCC内在函数?

我发现下面的链接,但不知道它是否去了解它的最佳方式(笔者也表示有一些错误):http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm. 86/2006-02/msg00123.html

编辑:请注意,副本是必要的,我无法复制数据(我可以解释为什么,但我会饶你解释:))

c optimization assembly image-processing memcpy

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

Intel 64,rsi和rdi寄存器

在Intel 64架构中,有rax..rdx寄存器,它们只是A..D通用寄存器.

但是也有一些名为rsi和rdi的寄存器,它们是"源索引"和"目标索引"寄存器.为什么这些寄存器有实际名称(与A等相比)?
"源索引"和"目标索引"实际上意味着什么?是否有一些惯例说这些寄存器应该在特定情况下使用?

assembly x86-64

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

x86汇编语言中的CLD和STD是什么?DF做什么?

好吧,我知道CLD清除方向标志和STD设置方向标志.但是设置和清除方向标志的重点是什么?

x86 assembly

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

这个memcpy实现中缺少什么/次优?

我对编写一个memcpy()教育练习感兴趣.我不会写一篇关于我做了什么和没想过的论文,但这里 有一些人的实现:

__forceinline   // Since Size is usually known,
                // most useless code will be optimized out
                // if the function is inlined.

void* myMemcpy(char* Dst, const char* Src, size_t Size)
{
        void* start = Dst;
        for ( ; Size >= sizeof(__m256i); Size -= sizeof(__m256i) )
        {
                __m256i ymm = _mm256_loadu_si256(((const __m256i* &)Src)++);
                _mm256_storeu_si256(((__m256i* &)Dst)++, ymm);
        }

#define CPY_1B *((uint8_t * &)Dst)++ = *((const uint8_t * &)Src)++
#define CPY_2B *((uint16_t* &)Dst)++ = *((const uint16_t* &)Src)++
#define CPY_4B …
Run Code Online (Sandbox Code Playgroud)

c optimization x86 simd avx

26
推荐指数
3
解决办法
4232
查看次数

为什么复杂的memcpy/memset优越?

在调试时,我经常进入memcpy和memset的手写汇编实现.这些通常使用流指令(如果可用),循环展开,对齐优化等实现...我最近也遇到了由于glibc中的memcpy优化而导致的"错误".

问题是:为什么硬件制造商(英特尔,AMD)不能优化具体情况

rep stos
Run Code Online (Sandbox Code Playgroud)

rep movs
Run Code Online (Sandbox Code Playgroud)

被认可,并尽可能快地填写和复制他们自己的架构?

c optimization 64-bit x86 assembly

22
推荐指数
3
解决办法
9127
查看次数

软件预取是否分配了行填充缓冲区(LFB)?

我已经意识到Little's Law限制了在给定的延迟和给定的并发级别下数据传输的速度.如果您想更快地传输某些内容,则需要更大的传输,更多的"飞行中"传输或更低的延迟.对于从RAM读取的情况,并发性受到行填充缓冲区数量的限制.

当加载错过L1缓存时,将分配行填充缓冲区.现代英特尔芯片(Nehalem,Sandy Bridge,Ivy Bridge,Haswell)每个核心有10个LFB,因此每个核心限制为10个未完成的缓存未命中.如果RAM延迟为70 ns(似乎合理),并且每次传输为128字节(64B高速缓存线加上其硬件预取双线),则将每个内核的带宽限制为:10*128B/75 ns = ~16 GB/s.诸如单线程Stream之类的基准确认这是相当准确的.

减少延迟的显而易见的方法是使用x64指令(如PREFETCHT0,PREFETCHT1,PREFETCHT2或PREFETCHNTA)预取所需数据,这样就不必从RAM中读取数据.但是我无法通过使用它们加快速度.问题似乎是__mm_prefetch()指令本身消耗LFB,因此它们也受到相同的限制.硬件预取不会触及LFB,也不会跨越页面边界.

但我无法在任何地方找到任何记录.我发现的最接近的是15年前的文章,其中提到Pentium III上的预取使用Line Fill Buffers.我担心事情可能会发生变化.由于我认为LFB与L1缓存相关联,我不确定为什么L2或L3的预取会消耗它们.然而,我测量的速度与这种情况一致.

那么:有没有办法在没有使用这10个线路填充缓冲器中的一个的情况下从存储器中的新位置开始取出,从而通过绕过Little's定律实现更高的带宽?

64-bit assembly caching bandwidth prefetch

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

SSE-copy,AVX-copy和std :: copy性能

我试图通过SSE和AVX提高复制操作的性能:

    #include <immintrin.h>

    const int sz = 1024;
    float *mas = (float *)_mm_malloc(sz*sizeof(float), 16);
    float *tar = (float *)_mm_malloc(sz*sizeof(float), 16);
    float a=0;
    std::generate(mas, mas+sz, [&](){return ++a;});

    const int nn = 1000;//Number of iteration in tester loops    
    std::chrono::time_point<std::chrono::system_clock> start1, end1, start2, end2, start3, end3; 

    //std::copy testing
    start1 = std::chrono::system_clock::now();
    for(int i=0; i<nn; ++i)
        std::copy(mas, mas+sz, tar);
    end1 = std::chrono::system_clock::now();
    float elapsed1 = std::chrono::duration_cast<std::chrono::microseconds>(end1-start1).count();

    //SSE-copy testing
    start2 = std::chrono::system_clock::now();
    for(int i=0; i<nn; ++i)
    {
        auto _mas = mas;
        auto _tar = tar; …
Run Code Online (Sandbox Code Playgroud)

c++ performance sse simd avx

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