这个网站上已经存在很多性能问题,但是我发现几乎所有这些都是特定于问题且相当狭窄的问题.几乎所有人都重复这些建议,以避免过早优化.
我们假设:
我在这里寻找的是在一个关键算法中挤出最后几个百分点的策略和技巧,除此之外别无他法.
理想情况下,尝试使答案语言不可知,并在适用的情况下指出建议策略的任何缺点.
我将使用我自己的初步建议添加回复,并期待Stack Overflow社区可以想到的任何其他内容.
从StringJava中删除所有不可打印字符的最快方法是什么?
到目前为止,我已经尝试并测量了138字节,131个字符的字符串:
replaceAll()- 最慢的方法
replaceAll()
codepointAt()逐个获取代码点并附加到StringBuffer
charAt()逐个获取字符并附加到StringBuffer
char[]缓冲区,charAt()逐个获取字符并填充此缓冲区,然后转换回String
char[]缓冲区 - 旧的和新的,一次获取现有String的所有字符,getChars()逐个迭代旧缓冲区并填充新缓冲区,然后将新缓冲区转换为String - 我自己的最快版本
byte[],getBytes()并指定编码为"utf-8"
byte[]缓冲区的相同内容,但将编码指定为常量Charset.forName("utf-8")
byte[]缓冲区相同的东西,但指定编码为1字节本地编码(几乎没有理智的事情要做)
我最好的尝试如下:
char[] oldChars = new char[s.length()];
s.getChars(0, s.length(), oldChars, 0);
char[] newChars = new char[s.length()];
int newLen = 0;
for (int j = 0; j < s.length(); …Run Code Online (Sandbox Code Playgroud) 我使用英特尔®架构代码分析器(IACA)发现了一些意想不到的东西(对我而言).
以下指令使用[base+index]寻址
addps xmm1, xmmword ptr [rsi+rax*1]
Run Code Online (Sandbox Code Playgroud)
根据IACA没有微熔丝.但是,如果我用[base+offset]这样的
addps xmm1, xmmword ptr [rsi]
Run Code Online (Sandbox Code Playgroud)
IACA报告它确实融合了.
英特尔优化参考手册的第2-11节给出了以下"可以由所有解码器处理的微融合微操作"的示例
FADD DOUBLE PTR [RDI + RSI*8]
Run Code Online (Sandbox Code Playgroud)
和Agner Fog的优化装配手册也给出了使用[base+index]寻址的微操作融合的例子.例如,请参见第12.2节"Core2上的相同示例".那么正确的答案是什么?
我是指令优化的新手.
我对一个简单的函数dotp进行了简单的分析,该函数用于获取两个浮点数组的点积.
C代码如下:
float dotp(
const float x[],
const float y[],
const short n
)
{
short i;
float suma;
suma = 0.0f;
for(i=0; i<n; i++)
{
suma += x[i] * y[i];
}
return suma;
}
Run Code Online (Sandbox Code Playgroud)
我用昂纳雾在网络上提供的测试框架testp.
在这种情况下使用的数组是对齐的:
int n = 2048;
float* z2 = (float*)_mm_malloc(sizeof(float)*n, 64);
char *mem = (char*)_mm_malloc(1<<18,4096);
char *a = mem;
char *b = a+n*sizeof(float);
char *c = b+n*sizeof(float);
float *x = (float*)a;
float *y = (float*)b;
float *z = (float*)c;
Run Code Online (Sandbox Code Playgroud)
然后我调用函数dotp,n = 2048,repeat …
我用AVX一次计算八个点产品.在我目前的代码中,我做了类似的事情(在展开之前):
常春藤桥/桑迪桥
__m256 areg0 = _mm256_set1_ps(a[m]);
for(int i=0; i<n; i++) {
__m256 breg0 = _mm256_load_ps(&b[8*i]);
tmp0 = _mm256_add_ps(_mm256_mul_ps(arge0,breg0), tmp0);
}
Run Code Online (Sandbox Code Playgroud)
Haswell的
__m256 areg0 = _mm256_set1_ps(a[m]);
for(int i=0; i<n; i++) {
__m256 breg0 = _mm256_load_ps(&b[8*i]);
tmp0 = _mm256_fmadd_ps(arge0, breg0, tmp0);
}
Run Code Online (Sandbox Code Playgroud)
我需要多少次为每个案例展开循环以确保最大吞吐量?
对于使用FMA3的Haswell,我认为答案是每个循环的FLOPS用于沙桥和haswell SSE2/AVX/AVX2.我需要将循环展开10次.
对于Ivy Bridge,我认为它是8.这是我的逻辑.AVX添加的延迟为3,延迟乘以5.Ivy Bridge可以使用不同的端口同时进行一次AVX乘法和一次AVX添加.使用符号m进行乘法,a表示加法,x表示无操作,以及表示部分和的数字(例如m5表示乘以第5部分和)我可以写:
port0: m1 m2 m3 m4 m5 m6 m7 m8 m1 m2 m3 m4 m5 ...
port1: x x x x x a1 a2 a3 a4 a5 a6 a7 a8 ...
Run Code Online (Sandbox Code Playgroud)
因此,通过在9个时钟周期后使用8个部分和(4个来自负载,5个来自乘法),我可以在每个时钟周期提交一个AVX负载,一个AVX加法和一个AVX乘法.
我想这意味着在Ivy …
对于那些对我如何进行基准测试感兴趣的人,请看这里,我简单地在"Loop 1K"方法中替换/添加几个方法.
对不起,我忘了说我的测试环境..Net 4.5 x64(不要选择32位首选).在x86中,这两种方法的时间都是时间的5倍.
Loop2花费的时间是3倍Loop.我认为x++/ x+=y当x变大时不应该减速(因为它需要1或2个cpu指令)
是因为参考地点?但是我认为在Loop2变量不多的情况下,它们应该彼此接近......
public long Loop(long testSize)
{
long ret = 0;
for (long i = 0; i < testSize; i++)
{
long p = 0;
for (int j = 0; j < 1000; j++)
{
p+=10;
}
ret+=p;
}
return ret;
}
public long Loop2(long testSize)
{
long ret = 0;
for (long i = 0; i < testSize; i++) …Run Code Online (Sandbox Code Playgroud) 有没有一种有效的方法将一组nullables(比方说byte?[])复制到一个非nullables数组(比方说byte[]),假设源数组保证没有任何nullables(如果确实如此,可以抛出异常)?显然,我可以遍历索引并单独复制每个元素.
这不起作用.它编译,但ArrayTypeMismatchException在运行时抛出.
byte?[] sourceNullable = new byte?[]{1,2,3};
byte[] destNonNullable = new byte[3];
Array.Copy(sourceNullable,destNonNullable,3);
Run Code Online (Sandbox Code Playgroud)
这会有效但我正在寻找"更好"的东西
for(int i=0;i<3;i++) {
destNonNullable[i] = sourceNullable[i] ?? 0;
}
Run Code Online (Sandbox Code Playgroud)
我愿意接受答案:显式循环有什么问题?你为什么要浪费时间来优化这个?:)
编辑:我尝试使用Linq样式Cast<>(),但事实证明要慢得多.我的代码的时间摘要如下:
for loop = 585 ms
Linq Cast = 3626毫秒
输入image文件是稀疏数组,填充了空值部分.
uint rowsize = 16;
Stopwatch sw = new Stopwatch();
sw.Start();
for (UInt32 address = start & 0xFFFFFFF0; address <= last; address += rowsize)
{
Int32 imageOffset = (Int32)(address - start);
Int32 maxRowLen = (int)rowsize;
if …Run Code Online (Sandbox Code Playgroud) 我正在玩Compiler Explorer,我很难理解简单std::vector<int>求和函数的ASM输出(x86 Clang 3.7 -O3):
#include <vector>
#include <numeric>
int sum(const std::vector<int>& v)
{
return std::accumulate(v.begin(), v.end(), 0);
}
Run Code Online (Sandbox Code Playgroud)
此代码的ASM是:
sum(std::vector<int, std::allocator<int> > const&): # @sum(std::vector<int, std::allocator<int> > const&)
movq (%rdi), %rsi
movq 8(%rdi), %r11
xorl %eax, %eax
cmpq %r11, %rsi
je .LBB0_13
movabsq $9223372036854775800, %rax # imm = 0x7FFFFFFFFFFFFFF8
leaq -4(%r11), %rdx
movq %rdx, %r10
subq %rsi, %r10
shrq $2, %r10
incq %r10
xorl %edi, %edi
movq %r10, %r8
andq %rax, %r8
pxor %xmm0, %xmm0 …Run Code Online (Sandbox Code Playgroud)