相关疑难解决方法(0)

最后的性能优化策略

这个网站上已经存在很多性能问题,但是我发现几乎所有这些都是特定于问题且相当狭窄的问题.几乎所有人都重复这些建议,以避免过早优化.

我们假设:

  • 代码已经正常工作
  • 所选择的算法对于问题的情况已经是最佳的
  • 已经测量了代码,并且已经隔离了违规的例程
  • 所有优化尝试也将被测量,以确保它们不会使事情变得更糟

我在这里寻找的是在一个关键算法中挤出最后几个百分点的策略和技巧,除此之外别无他法.

理想情况下,尝试使答案语言不可知,并在适用的情况下指出建议策略的任何缺点.

我将使用我自己的初步建议添加回复,并期待Stack Overflow社区可以想到的任何其他内容.

language-agnostic optimization performance

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

从Java String中删除所有不可打印字符的最快方法

StringJava中删除所有不可打印字符的最快方法是什么?

到目前为止,我已经尝试并测量了138字节,131个字符的字符串:

  • 字符串replaceAll()- 最慢的方法
    • 517009结果/秒
  • 预编译模式,然后使用匹配器 replaceAll()
    • 637836结果/秒
  • 使用StringBuffer,codepointAt()逐个获取代码点并附加到StringBuffer
    • 711946结果/秒
  • 使用StringBuffer,charAt()逐个获取字符并附加到StringBuffer
    • 1052964结果/秒
  • 预分配char[]缓冲区,charAt()逐个获取字符并填充此缓冲区,然后转换回String
    • 2022653结果/秒
  • 预分配2个char[]缓冲区 - 旧的和新的,一次获取现有String的所有字符,getChars()逐个迭代旧缓冲区并填充新缓冲区,然后将新缓冲区转换为String - 我自己的最快版本
    • 2502502结果/秒
  • 与2个缓冲区相同的东西 - 仅使用byte[],getBytes()并指定编码为"utf-8"
    • 857485结果/秒
  • 具有2个byte[]缓冲区的相同内容,但将编码指定为常量Charset.forName("utf-8")
    • 791076结果/秒
  • 与2个byte[]缓冲区相同的东西,但指定编码为1字节本地编码(几乎没有理智的事情要做)
    • 370164结果/秒

我最好的尝试如下:

    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)

java string optimization performance micro-optimization

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

微融合和寻址模式

我使用英特尔®架构代码分析器(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上的相同示例".那么正确的答案是什么?

cpu x86 assembly intel iaca

44
推荐指数
4
解决办法
4504
查看次数

为什么mulss在Haswell上只用了3个周期,与Agner的指令表不同?

我是指令优化的新手.

我对一个简单的函数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 …

c optimization assembly sse micro-optimization

31
推荐指数
1
解决办法
1471
查看次数

循环展开以实现Ivy Bridge和Haswell的最大吞吐量

我用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 …

c++ x86 sse intel avx

15
推荐指数
2
解决办法
3038
查看次数

如何解释这两个简单循环中的性能差异?

对于那些对我如何进行基准测试感兴趣的人,请看这里,我简单地在"Loop 1K"方法中替换/添加几个方法.

对不起,我忘了说我的测试环境..Net 4.5 x64(不要选择32位首选).在x86中,这两种方法的时间都是时间的5倍.

Loop2花费的时间是3倍Loop.我认为x++/ x+=yx变大时不应该减速(因为它需要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)

c# performance

9
推荐指数
1
解决办法
408
查看次数

将一组nullables复制到相同基类型的非nullables数组的有效方法?

有没有一种有效的方法将一组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)

c# arrays nullable

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

std :: vector <int>和ASM的解释

我正在玩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)

c++ optimization assembly vector

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