相关疑难解决方法(0)

如何在C++中重复一次字符串变量?

我想在C++中的字符串开头插入'n'个空格(或任何字符串).有没有直接的方法来使用std :: strings或char*字符串?

例如,在Python中你可以做到

>>> "." * 5 + "lolcat"
'.....lolcat'
Run Code Online (Sandbox Code Playgroud)

c++

103
推荐指数
8
解决办法
9万
查看次数

为什么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增强了REP MOVSB

我想使用增强的REP MOVSB(ERMSB)为自定义获得高带宽memcpy.

ERMSB引入了Ivy Bridge微体系结构.如果您不知道ERMSB是什么,请参阅英特尔优化手册中的"增强型REP MOVSB和STOSB操作(ERMSB)" 部分.

我知道直接执行此操作的唯一方法是使用内联汇编.我从https://groups.google.com/forum/#!topic/gnu.gcc.help/-Bmlm_EG_fE获得了以下功能

static inline void *__movsb(void *d, const void *s, size_t n) {
  asm volatile ("rep movsb"
                : "=D" (d),
                  "=S" (s),
                  "=c" (n)
                : "0" (d),
                  "1" (s),
                  "2" (n)
                : "memory");
  return d;
}
Run Code Online (Sandbox Code Playgroud)

然而,当我使用它时,带宽远小于memcpy. 使用我的i7-6700HQ(Skylake)系统,Ubuntu 16.10,DDR4 @ 2400 MHz双通道32 GB,GCC 6.2,__movsb获得15 GB/s并memcpy获得26 GB/s.

为什么带宽如此低REP MOVSB?我该怎么做才能改善它?

这是我用来测试它的代码.

//gcc -O3 -march=native -fopenmp foo.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include …
Run Code Online (Sandbox Code Playgroud)

c x86 assembly gcc memcpy

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

为什么复杂的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
查看次数

涉及Intel SnB系列CPU上的微编码指令的循环分支对齐

这与此问题有关,但不一样:x86-64汇编的性能优化 - 对齐和分支预测与我之前的问题略有关系:无符号64位到双倍转换:为什么这个算法来自g ++

以下是一个不真实的测试用例.这种素性测试算法是不明智的.我怀疑任何真实世界的算法都不会执行如此多的小内循环(num大概是2**50的大小).在C++ 11中:

using nt = unsigned long long;
bool is_prime_float(nt num)
{
   for (nt n=2; n<=sqrt(num); ++n) {
      if ( (num%n)==0 ) { return false; }
   }
   return true;
}
Run Code Online (Sandbox Code Playgroud)

然后g++ -std=c++11 -O3 -S生成以下内容,包含RCX n和包含XMM6 sqrt(num).请参阅我之前发布的剩余代码(在此示例中从未执行过,因为RCX永远不会变得足够大,不能被视为带符号的否定).

jmp .L20
.p2align 4,,10
.L37:
pxor    %xmm0, %xmm0
cvtsi2sdq   %rcx, %xmm0
ucomisd %xmm0, %xmm6
jb  .L36   // Exit the loop
.L20:
xorl    %edx, %edx
movq    %rbx, %rax …
Run Code Online (Sandbox Code Playgroud)

performance x86 assembly intel micro-optimization

21
推荐指数
3
解决办法
2156
查看次数

memcpy()通常比strcpy()快吗?

memcpy()通常速度比strcpy()(上最真实的平台)?(我假设字符串的大小是已知的.)

如果我正确地记得i386汇编程序,则会有loop指令复制给定数量的字节或单词.所以它是最快的方式,而strcpy()i386汇编程序实现将'\0'在一个简单的循环中使用手动检查.

所以我觉得在x86上memcpy()要快于strcpy().

其他架构是什么?

c performance x86 memcpy strcpy

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

如何找到英特尔x86 CPU解码指令的微操作?

英特尔优化参考,根据第3.5.1节,建议:

"赞成单微操作指令."

"避免使用复杂指令(例如,输入,离开或循环),这些指令超过4个微操作并需要多个周期才能解码.请使用简单指令序列."

虽然英特尔自己告诉编译器编写者使用解码为少数微操作的指令,但我在他们的任何手册中都找不到任何东西,这解释了每个ASM指令解码的微操作数量!这些信息是否随处可用?(当然,我希望不同代CPU的答案会有所不同.)

x86 intel compiler-optimization

16
推荐指数
3
解决办法
3570
查看次数

rep stosb指令如何比等效循环执行得更快?

指令如何rep stosb比这段代码执行得更快?

    Clear: mov byte [edi],AL       ; Write the value in AL to memory
           inc edi                 ; Bump EDI to next byte in the buffer
           dec ecx                 ; Decrement ECX by one position
           jnz Clear               ; And loop again until ECX is 0
Run Code Online (Sandbox Code Playgroud)

在所有现代CPU上都能保证这一点吗?我是否应该总是喜欢使用rep stosb而不是手动编写循环?

optimization performance x86 assembly micro-optimization

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

Branch Target Buffer检测到哪些分支错误预测?

我目前正在查看CPU管道的各个部分,它们可以检测分支错误预测.我发现这些是:

  1. 分支目标缓冲区(BPU CLEAR)
  2. 分支地址计算器(BA CLEAR)
  3. 跳转执行单元(这里不确定信号名称?)

我知道2和3检测到了什么,但我不明白在BTB中检测到了什么错误预测.BAC检测BTB错误地预测非分支指令的分支的位置,其中BTB未能检测到分支,或者BTB错误预测了x86 RET指令的目标地址.执行单元评估分支并确定它是否正确.

在分支目标缓冲区中检测到什么类型的错误预测?究竟在这里发现了什么错误预测?

我能找到的唯一线索是英特尔开发者手册第3卷(底部的两个BPU CLEAR事件计数器):

在此输入图像描述

BPU在错误地认为未采取分支后预测了一个分支.

这似乎暗示预测并非"同步",而是"异步",因此"在错误地假设"之后?

更新:

Ross,这是CPU分支电路,来自最初的英特尔专利(如何用于"阅读"?):

在此输入图像描述

我在任何地方都看不到"分支预测单位"?读过这篇论文的人会认为"BPU"是将BTB电路,BTB缓存,BAC和RSB分组在一起的懒惰方式吗?

所以我的问题仍然存在,哪个组件会引发BPU CLEAR信号?

optimization intel cpu-architecture computer-architecture branch-prediction

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

组装:REP MOV机制

查看以下汇编代码:

MOV ESI, DWORD PTR [EBP + C]
MOV ECX, EDI
MOV EAX, EAX
SHR ECX, 2
LEA EDI, DWORD PTR[EBX + 18]
REP MOVS DWORD PTR ES:[EDI], DWORD PTR [ESI]
MOV ECX, EAX
AND ECX, 3
REP MOVS BYTE PTR ES:[EDI], BYTE PTR[ESI]
Run Code Online (Sandbox Code Playgroud)

我得到代码摘录的书解释了第一个REP MOVS复制4字节块,第二个REP MOVS复制剩余的2字节块(如果存在).

REP MOVS说明书如何运作?根据MSDN,"该指令可以用REP作为前缀,重复操作ecx寄存器指定的次数." 难道不会一遍又一遍地重复同样的操作吗?

x86 assembly

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