我想使用增强的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) 当我解决以下示例算法问题时,我很好奇理解字符串比较在python中如何工作的内部:
给定两个字符串,返回最长公共前缀的长度
我的直觉告诉我,最佳解决方案是在两个单词的开头用一个光标开始并向前迭代,直到前缀不再匹配.就像是
def charByChar(smaller, bigger):
assert len(smaller) <= len(bigger)
for p in range(len(smaller)):
if smaller[p] != bigger[p]:
return p
return len(smaller)
Run Code Online (Sandbox Code Playgroud)
为了简化代码,该函数假定第一个字符串的长度smaller始终小于或等于第二个字符串的长度bigger.
另一种方法是将两个字符串平分以创建两个前缀子字符串.如果前缀相等,我们知道公共前缀点至少与中点一样长.否则,公共前缀点至少不大于中点.然后我们可以递归以找到前缀长度.
阿卡二进制搜索.
def binarySearch(smaller, bigger):
assert len(smaller) <= len(bigger)
lo = 0
hi = len(smaller)
# binary search for prefix
while lo < hi:
# +1 for even lengths
mid = ((hi - lo + 1) // 2) + lo
if smaller[:mid] == bigger[:mid]:
# prefixes equal
lo = mid
else: …Run Code Online (Sandbox Code Playgroud) 我在C中进行图像处理,需要在内存周围复制大块数据 - 源和目标永远不会重叠.
使用GCC(其中SSE,SSE2但不是SSE3可用)在x86平台上执行此操作的绝对最快方法是什么?
我希望解决方案可以是汇编还是使用GCC内在函数?
我发现下面的链接,但不知道它是否去了解它的最佳方式(笔者也表示有一些错误):http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm. 86/2006-02/msg00123.html
编辑:请注意,副本是必要的,我无法复制数据(我可以解释为什么,但我会饶你解释:))
我记得假设在我的架构类中L1缓存命中是1个周期(即与寄存器访问时间相同),但在现代x86处理器上实际上是这样吗?
L1缓存命中多少个周期?它与寄存器访问相比如何?
performance x86 cpu-architecture micro-optimization cpu-cache
当试图理解汇编(启用编译器优化)时,我看到这种行为:
这样一个非常基本的循环
outside_loop;
while (condition) {
statements;
}
Run Code Online (Sandbox Code Playgroud)
经常被编译成(伪代码)
; outside_loop
jmp loop_condition ; unconditional
loop_start:
loop_statements
loop_condition:
condition_check
jmp_if_true loop_start
; outside_loop
Run Code Online (Sandbox Code Playgroud)
但是,如果未打开优化,则会编译为通常可理解的代码:
loop_condition:
condition_check
jmp_if_false loop_end
loop_statements
jmp loop_condition ; unconditional
loop_end:
Run Code Online (Sandbox Code Playgroud)
根据我的理解,编译后的代码更像是这样的:
goto condition;
do {
statements;
condition:
}
while (condition_check);
Run Code Online (Sandbox Code Playgroud)
我看不到巨大的性能提升或代码可读性提升,为什么经常出现这种情况呢?是否有此循环样式的名称,例如"尾随条件检查"?
我正在尝试使用AVX -AVX2指令集来查看连续阵列上的流媒体性能.所以我有下面的例子,我做基本的内存读取和存储.
#include <iostream>
#include <string.h>
#include <immintrin.h>
#include <chrono>
const uint64_t BENCHMARK_SIZE = 5000;
typedef struct alignas(32) data_t {
double a[BENCHMARK_SIZE];
double c[BENCHMARK_SIZE];
alignas(32) double b[BENCHMARK_SIZE];
}
data;
int main() {
data myData;
memset(&myData, 0, sizeof(data_t));
auto start = std::chrono::high_resolution_clock::now();
for (auto i = 0; i < std::micro::den; i++) {
for (uint64_t i = 0; i < BENCHMARK_SIZE; i += 1) {
myData.b[i] = myData.a[i] + 1;
}
}
auto end = std::chrono::high_resolution_clock::now();
std::cout << (end - start).count() / …Run Code Online (Sandbox Code Playgroud) 我的笔记本电脑配备Intel Core 2 Duo 2.4GHz CPU和2x4Gb DDR3模块1066MHz.
我希望这个内存可以以1067 MiB/sec的速度运行,并且只要有两个通道,最大速度为2134 MiB/sec(如果OS内存调度程序允许的话).
我做了一个小Java应用程序来测试:
private static final int size = 256 * 1024 * 1024; // 256 Mb
private static final byte[] storage = new byte[size];
private static final int s = 1024; // 1Kb
private static final int duration = 10; // 10sec
public static void main(String[] args) {
long start = System.currentTimeMillis();
Random rnd = new Random();
byte[] buf1 = new byte[s];
rnd.nextBytes(buf1);
long count = 0;
while (System.currentTimeMillis() …Run Code Online (Sandbox Code Playgroud) 在编写模拟时,我的伙伴说他喜欢尝试编写足够小的程序以适应缓存.这有什么实际意义吗?据我所知,缓存比RAM和主内存快.是否可以指定您希望程序从缓存运行或至少将变量加载到缓存中?我们正在编写模拟,因此任何性能/优化收益都是巨大的好处.
如果您知道任何解释CPU缓存的好链接,那么请指出我的方向.
c++在某些英特尔至强处理器上运行以下代码时,我偶然发现了一个特殊的性能问题:
// array_a contains permutation of [0, n - 1]
// array_b and inverse are initialized arrays
for (int i = 0; i < n; ++i) {
array_b[i] = array_a[i];
inverse[array_b[i]] = i;
}
Run Code Online (Sandbox Code Playgroud)
循环的第一行按顺序复制array_a到array_b(预期很少有缓存未命中)。第二行计算array_b(许多缓存未命中,因为array_b是随机排列)的倒数。我们也可以将代码分成两个单独的循环:
for (int i = 0; i < n; ++i)
array_b[i] = array_a[i];
for (int i = 0; i < n; ++i)
inverse[array_b[i]] = i;
Run Code Online (Sandbox Code Playgroud)
我原以为这两个版本(单循环与双循环)在相对现代的硬件上的性能几乎相同。但是,在执行单循环版本时,某些 Xeon 处理器似乎非常慢。
您可以在下方看到以纳秒为单位n的挂机时间除以在一系列不同处理器上运行代码段的时间。出于测试目的,代码是使用 GCC 7.5.0 编译的,并-O3 -funroll-loops -march=native …