标签: micro-optimization

重新排列条件评估会加快循环吗?

有点奇怪的是:我刚才有一位朋友告诉我重新安排这个示例for循环:

for(int i = 0; i < constant; ++i) {
    // code...
}
Run Code Online (Sandbox Code Playgroud)

至:

for(int i = 0; constant > i; ++i) {
    // code...
}
Run Code Online (Sandbox Code Playgroud)

会略微提高C++的性能.我没有看到如何将常量值与变量进行比较比反之亦然,并且我运行的一些基本测试没有显示两种实现之间的速度差异.测试这个Python while循环也是如此:

while i < constant:
    # code...
    i += 1
Run Code Online (Sandbox Code Playgroud)

VS:

while constant > i:
    # code...
    i += 1
Run Code Online (Sandbox Code Playgroud)

我错了吗?我的简单测试不足以确定速度变化吗?这是否适用于其他语言?或者这只是一个新的最佳实践?

c++ optimization premature-optimization micro-optimization

11
推荐指数
5
解决办法
1298
查看次数

Java中哪一段代码更快?

一个) for(int i = 100000; i > 0; i--) {}

b) for(int i = 1; i < 100001; i++) {}

答案就在这个网站上(问题3).我只是想不通为什么?来自网站:

3. a

java performance micro-optimization

11
推荐指数
7
解决办法
4174
查看次数

通过分析程序集列表验证gcc/g ++中的编译器优化

我刚刚问了一个与编译器如何优化某些C++代码有关的问题,我正在寻找有关如何验证编译器是否已执行某些优化的任何问题.我试图查看用g ++(g++ -c -g -O2 -Wa,-ahl=file.s file.c)生成的汇编列表,可能会看到底层发生了什么,但输出对我来说太神秘了.人们使用什么技术来解决这个问题,是否有任何关于如何解释优化代码的汇编列表或特定于GCC工具链的文章的讨论这个问题的参考?

c c++ compiler-construction assembly micro-optimization

11
推荐指数
3
解决办法
6556
查看次数

LINQ Count()直到,这样效率更高吗?

假设我想检查集合中是否至少有N个元素.

这比做好吗?

Count() >= N

使用:

    public static bool AtLeast<T>(this IEnumerable<T> enumerable, int max)
    {
        int count = 0;
        return enumerable.Any(item => ++count >= max);
    }
Run Code Online (Sandbox Code Playgroud)

甚至

    public static bool Equals<T>(this IEnumerable<T> enumerable, int amount)
    {
        return enumerable.Take(amount).Count() == amount;
    }
Run Code Online (Sandbox Code Playgroud)

我怎么能对此进行基准测试

    /// <summary>
    /// Returns whether the enumerable has at least the provided amount of elements.
    /// </summary>
    public static bool HasAtLeast<T>(this IEnumerable<T> enumerable, int amount)
    {
        return enumerable.Take(amount).Count() == amount;
    }

    /// <summary>
    /// Returns whether the enumerable …
Run Code Online (Sandbox Code Playgroud)

c# linq performance ienumerable micro-optimization

11
推荐指数
1
解决办法
1584
查看次数

为什么交换不在C++中使用Xor操作

我已经了解到Xor操作可用于实现有效的交换功能.像这样:

template<class T>
void swap(T& a, T& b)
{
    a = a^b;
    b = a^b;
    a = a^b;
}
Run Code Online (Sandbox Code Playgroud)

但是我可以在互联网上找到的交换实现基本上是这样的:

template<class T>
void swap(T& a, T& b)
{
    T temp(a);
    a = b;
    b = temp;
}
Run Code Online (Sandbox Code Playgroud)

似乎编译器没有为上面的两个表单生成相同的代码,因为我在VC++ 2010上测试了它,第一个更快地完成了工作(并且比std :: swap更快).第一个是便携式还是其他任何问题?随意纠正我的任何错误,因为我不是英语本地人,不擅长C++.

c++ swap xor premature-optimization micro-optimization

11
推荐指数
2
解决办法
3045
查看次数

使用少于5个按位运算符实现"逻辑非"

作为我的CS课程的一部分,我最近完成了非常受欢迎的"数据实验室"作业.在这些分配中,您应该使用尽可能少的操作在C中实现简单的二进制操作.

对于那些不熟悉"数据实验室"的人,可以快速了解规则:

  • 您不能调用函数,强制转换或使用控制结构(例如,如果)
  • 您可以分配没有运营商成本的变量,但只允许使用int)
  • 您使用的运营商越少越好
  • 您可以假设sizeof(int)== 32
  • 负数用2的补码表示

任务是通过仅使用以下运算符来实现一个不称为'bang'的逻辑(其中bang(x)返回!x):〜&^ | + << >>

函数原型定义为

int bang(int x)
Run Code Online (Sandbox Code Playgroud)

我能找到的最佳实现(使用5个运算符)如下:

return ((x | (~x +1)) >> 31) + 1
Run Code Online (Sandbox Code Playgroud)

然而,似乎有一种方法可以通过更少的操作员来实现这一目标,因为我在一些德国大学找到了一个结果网站[1],其中两个人显然找到了一个少于5个操作员的解决方案.但我似乎无法弄清楚他们是如何完成的.

[1] http://rtsys.informatik.uni-kiel.de/~rt-teach/ss09/v-sysinf2/dlcontest.html(logicalNeg专栏)

澄清:这不是关于如何解决问题,而是如何用较少的操作来解决问题.

c bit-manipulation micro-optimization

11
推荐指数
1
解决办法
1934
查看次数

使用xmm寄存器而不是ymm时,vxorps在AMD Jaguar/Bulldozer/Zen上的归零速度是否更快?

AMD CPU通过解码为两个128b操作来处理256b AVX指令.例如,vaddps ymm0, ymm1,ymm1在AMD上,Steamroller解码为2个宏操作,吞吐量的一半vaddps xmm0, xmm1,xmm1.

XOR归零是一种特殊情况(没有输入依赖性,并且在Jaguar上至少避免消耗物理寄存器文件条目,并且使得来自该寄存器的movdqa在发出/重命名时被消除,就像Bulldozer一直在做非零的REG)中. 但它是否足够vxorps ymm0,ymm0,ymm0早被检测到仍然只能解码为1个具有相同性能的宏操作 vxorps xmm0,xmm0,xmm0?(不像vxorps ymm3, ymm2,ymm1)

或者,在已经解码为两个uop之后,独立检测是否会发生?此外,AMD CPU上的向量xor-zeroing是否仍然使用执行端口?在Intel-CPU上,Nehalem需要一个端口,但Sandybridge系列在发布/重命名阶段处理它.

Agner Fog的指令表没有列出这个特例,他的微指南没有提到uop的数量.


这可能意味着vxorps xmm0,xmm0,xmm0更好的实施方式_mm256_setzero_ps().

对于AVX512 _mm512_setzero_ps(),如果可能的话,也只使用VEX编码的归零惯用语而不是EVEX来保存字节.(即对于zmm0-15. vxorps xmm31,xmm31,xmm31仍然需要EVEX).gcc/clang目前使用他们想要的任何寄存器宽度的xor-zeroing习语,而不是总是使用AVX-128.

报告为clang bug 32862和gcc bug 80636.MSVC已经使用了xmm.尚未向ICC报告,ICC也使用zmm regs进行AVX512归零.(虽然英特尔可能不会改变,因为目前任何英特尔CPU都没有任何好处,只有AMD.如果他们发布的低功耗CPU将矢量分成两半,他们可能.他们目前的低功耗设计(Silvermont)没有t支持AVX,只支持SSE4.)


我知道使用AVX-128指令清零256b寄存器唯一可能的缺点是它不会触发Intel CPU上256b执行单元的预热.可能会破坏试图加热它们的C或C++黑客攻击.

(在第一个256b指令之后的第一个~56k周期内,256b向量指令较慢.请参阅Agner Fog微格式pdf中的Skylake部分).如果调用noinline返回的函数_mm256_setzero_ps不是预热执行单元的可靠方法,那可能没问题.(一个仍然可以在没有AVX2的情况下工作,并且避免任何负载(可以缓存未命中)是__m128 onebits = _mm_castsi128_ps(_mm_set1_epi8(0xff));
return _mm256_insertf128_ps(_mm256_castps128_ps256(onebits), onebits)应该编译为pcmpeqd xmm0,xmm0,xmm0/ vinsertf128 ymm0,xmm0,1.对于你曾经呼叫一次预热(或保持)执行单元的事情,这仍然是非常微不足道的.关键循环.如果你想要内联的东西,你可能需要inline-asm.)


我没有AMD硬件所以我无法测试这个.

如果有人拥有AMD硬件但不知道如何测试,请使用perf计数器来计算周期(最好是m-ops或uops或AMD称之为的任何内容).

这是我用来测试短序列的NASM/YASM源:

section .text
global _start …
Run Code Online (Sandbox Code Playgroud)

x86 assembly avx micro-optimization amd-processor

11
推荐指数
1
解决办法
691
查看次数

为什么在嵌套函数之外声明一个计数器变量会使循环慢5倍?

我正在寻找一些我正在重新审视的JavaScript遗留代码的微优化,并注意到在大多数频繁调用的for循环中,计数器在全局范围内声明一次,在使用它们的函数之外.我很好奇这是否确实是一个优化,因此我在JavaScript中创建了以下测试用例:

var tmp = 0;

function test(){

    let j = 0;

    function letItBe(){

        for(j = 0; j < 1000; j++){
            tmp = Math.pow(j, 2);
        }
    }

    function letItNotBe(){
        for(let l = 0; l < 1000; l++){
            tmp = Math.pow(l, 2);
        }
    }

    console.time("let it be");
    for(var i =0; i < 10000; i++){

        letItBe();
    }
    console.timeEnd("let it be");


    console.time("let it not be");
    for(var i =0; i < 10000; i++){

        letItNotBe();
    }
    console.timeEnd("let it not be");
}

test();
Run Code Online (Sandbox Code Playgroud)

在Chrome,Firefox和NodeJS 中letItNotBe()运行的速度要快得多 …

javascript optimization micro-optimization

11
推荐指数
1
解决办法
174
查看次数

当base + offset与基数不同时,是否存在惩罚?

这三个片段的执行时间:

pageboundary: dq (pageboundary + 8)
...

    mov rdx, [rel pageboundary]
.loop:
    mov rdx, [rdx - 8]
    sub ecx, 1
    jnz .loop
Run Code Online (Sandbox Code Playgroud)

还有这个:

pageboundary: dq (pageboundary - 8)
...

    mov rdx, [rel pageboundary]
.loop:
    mov rdx, [rdx + 8]
    sub ecx, 1
    jnz .loop
Run Code Online (Sandbox Code Playgroud)

还有这个:

pageboundary: dq (pageboundary - 4096)
...

    mov rdx, [rel pageboundary]
.loop:
    mov rdx, [rdx + 4096]
    sub ecx, 1
    jnz .loop
Run Code Online (Sandbox Code Playgroud)

对于第一个片段,在4770K上,每次迭代大约5个周期,对于第二个片段,每次迭代大约9个周期,然后是第三个片段的5个周期.它们都访问完全相同的地址,这是4K对齐的.在第二个片段中,只有地址计算跨越页面边界:rdx并且rdx + 8不属于同一页面,负载仍然是对齐的.如果偏移量很大,则会再次回到5个周期.

这种效果一般如何起作用?


通过ALU指令从加载路由结果,如下所示:

.loop:
    mov rdx, …
Run Code Online (Sandbox Code Playgroud)

performance x86 assembly micro-optimization

11
推荐指数
1
解决办法
456
查看次数

内联递归函数

当我尝试编译此代码时:

#include <iostream>
#include <limits.h>

// End recursive template-expansion of function select below.
template <typename Type>
static inline constexpr Type select(unsigned index)
{ return Type(); }

// Select one of the items passed to it.
// e.g. select(0, a, b, c) = a; select(1, a, b, c) = b; etc.
template <typename Type, typename... Params>
[[gnu::always_inline]]
static inline constexpr Type select(unsigned index, Type value, Params... values)
{ return index == 0 ? value : select<Type>(index - 1, values...); }

template …
Run Code Online (Sandbox Code Playgroud)

c++ recursion inlining micro-optimization compiler-optimization

11
推荐指数
2
解决办法
1177
查看次数