标签: micro-optimization

如何优化完全严格的循环

我正在尝试为Project Euler问题#145编写一个强力解决方案,我无法让我的解决方案在不到1分30秒的时间内运行.

(我知道有各种捷径,甚至是纸笔解决方案;出于这个问题的目的,我不考虑那些).

在迄今为止我提出的最佳版本中,分析显示大部分时间都花在了foldDigits.这个函数根本不需要是懒惰的,在我看来应该优化到一个简单的循环.正如你所看到的,我试图使程序的各个部分严格.

所以我的问题是:在不改变整体算法的情况下,是否有某种方法可以将该程序的执行时间降低到亚分钟?

(或者,如果没有,有没有办法看到代码foldDigits尽可能优化?)

-- ghc -O3 -threaded Euler-145.hs && Euler-145.exe +RTS -N4

{-# LANGUAGE BangPatterns #-}

import Control.Parallel.Strategies

foldDigits :: (a -> Int -> a) -> a -> Int -> a
foldDigits f !acc !n
    | n < 10    = i
    | otherwise = foldDigits f i d
  where (d, m) = n `quotRem` 10
        !i     = f acc m

reverseNumber :: Int -> Int
reverseNumber !n
    = foldDigits accumulate …
Run Code Online (Sandbox Code Playgroud)

performance haskell micro-optimization

6
推荐指数
1
解决办法
212
查看次数

根据JVM的内存粒度确定数组的最佳大小

为(例如)集合创建支持数组时,您并不真正关心所创建数组的确切大小,它只需要至少与您计算的一样大.

但是由于内存分配和VM的数组头,在某些情况下可以创建一个更大的阵列而不消耗更多的内存 - 对于Oracle 32位VM(至少这是互联网上的几个来源声称),内存粒度为8(意味着任何内存分配向上舍入到下一个8字节边界),并且数组头开销为12个字节.

这意味着在分配Object [2]时,它应该消耗20个字节(12 + 2*4),但由于粒度,它实际上需要24个字节.可以为相同的内存成本创建一个Object [3],这意味着集合必须稍后调整其后备阵列的大小.相同的原理可以应用于primitve数组,例如用于I/O缓冲区的byte [],字符串生成器中的char []等.

虽然这种优化不会产生明显的效果,但在最极端的情况下,调用静态方法来"优化"数组大小并不会太麻烦.

问题是,JDK中没有这种"圆形阵列大小直至内存粒度".并且自己编写这样的方法需要确定VM的一些关键参数:内存粒度,数组头开销以及最终每种类型的大小(主要是引用的问题,因为它们的大小可能随架构和VM选项而变化).

那么有没有一种方法来确定这些参数,或通过其他方式实现所需的"向上舍入"?

java arrays memory-management micro-optimization

6
推荐指数
1
解决办法
514
查看次数

如何加速棘手的随机数生成

我有一些代码执行许多日志tancos双打操作.我需要这个尽可能快.目前我使用的代码如

#include <stdio.h>
#include <stdlib.h>
#include "mtwist.h"
#include <math.h>


int main(void) {
   int i;
   double x;
   mt_seed();
   double u1;
   double u2;
   double w1;
   double w2;
   x = 0;
   for(i = 0; i < 100000000; ++i) {
     u1 = mt_drand();
     u2 = mt_drand();
     w1 = M_PI*(u1-1/2.0);
     w2 = -log(u2);
     x += tan(w1)*(M_PI_2-w1)+log(w2*cos(w1)/(M_PI_2-w1));
   }
   printf("%f\n",x); 

   return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

我正在使用gcc.

有两种明显的方法可以加快速度.首先是选择更快的RNG.第二是加快先验功能.
要做到这一点,我想知道

  1. 如何在x86上的程序集中实现tan和cos?我的CPU是AMD FX-8350,如果它有所作为.(答案fcoscosfptantan.)
  2. 如何使用查找表来加速计算?我只需要32位的精度.例如,你可以使用一个大小为2 ^ 16的表来加速tan和cos操作吗?

英特尔优化手册

如果不需要使用80位的扩展精度来评估超越函数,则应用程序应考虑使用基于软件的替代方法,例如使用插值技术的基于查找表的算法.通过选择所需的数值精度和查找表的大小,并利用SSE和SSE2指令的并行性,可以通过这些技术提高超越性能. …

c math performance assembly micro-optimization

6
推荐指数
4
解决办法
795
查看次数

连接器如何应对快速返回的功能?

在C中,如果我有一个看起来像的函数调用

// main.c
...
do_work_on_object(object, arg1, arg2);
...

// object.c
void do_work_on_object(struct object_t *object, int arg1, int arg2)
{
  if(object == NULL)
  {
    return;
  }
  // do lots of work
}
Run Code Online (Sandbox Code Playgroud)

那么编译器会在main.o中生成很多东西来保存状态,传递参数(在这种情况下希望在寄存器中),以及恢复状态.

但是,在链接时可以观察到arg1和arg2没有用在快速返回路径中,因此清理和状态恢复可以短路.链接器是否会自动执行此类操作,或者是否需要启用链接时优化(LTO)才能使此类工作正常工作?

(是的,我可以检查反汇编代码,但我对编译器和链接器的行为以及多种体系结构感兴趣,所以希望从别人的经验中学习.)

假设分析显示此函数调用值得优化,我们是否应该期望以下代码明显更快(例如,无需使用LTO)?

// main.c
...
if(object != NULL)
{
  do_work_on_object(object, arg1, arg2);
}
...

// object.c
void do_work_on_object(struct object_t *object, int arg1, int arg2)
{
  assert(object != NULL) // generates no code in release build
  // do lots of work
}
Run Code Online (Sandbox Code Playgroud)

c linker micro-optimization lto

6
推荐指数
1
解决办法
98
查看次数

在数组上使用delete和随后的.push()会影响性能/内存消耗吗?

问题

使用delete数组元素将其从数组中删除是我意识到从数组中删除元素以使.forEach()调用跳过索引的唯一方法.

问题

  • 例如,使用deleteon索引exampleArray[i]会导致后续exampleArray.push()增加数组对象的内存消耗吗?
  • 删除对象如何影响垃圾收集器?

  • 是否有更有效的方法来消除exampleArray元素?

前者的例子

var exampleArray = [];
var n = 500;

//Does this line imply a memory allocation?
exampleArray.length = n;

exampleArray.fill("Lorem Ipsum", 0);

exampleArray.forEach(function(cur, ind, arr) {
  if(ind % 4 === 0) {
    delete arr[ind]; //Actually deletes the object itself, index no longer exists
    //Length does not change, however. Does available memory?
  }
}, this);

n /= 4;

//Where, in memory, are …
Run Code Online (Sandbox Code Playgroud)

javascript arrays micro-optimization

6
推荐指数
1
解决办法
119
查看次数

阈值是绝对值

我有以下功能:

char f1( int a, unsigned b ) { return abs(a) <= b; }
Run Code Online (Sandbox Code Playgroud)

对于执行速度,我想重写如下:

char f2( int a, unsigned b ) { return (unsigned)(a+b) <= 2*b; } // redundant cast
Run Code Online (Sandbox Code Playgroud)

或者使用此签名,即使对于非负面也可能具有微妙含义b:

char f3( int a, int b )      { return (unsigned)(a+b) <= 2*b; }
Run Code Online (Sandbox Code Playgroud)

这两种替代方案都可以在一个平台上进行简单的测试,但我需要便携式.假设非负b且没有溢出风险,这是典型硬件和C编译器的有效优化吗?它对C++也有效吗?


注意:作为C++在gcc 4.8 x86_64上使用-O3,f1()使用6个机器指令并f2()使用4.指令f3()与那些相同f2().同样感兴趣的是:如果b以文字形式给出,则两个函数都编译为3条指令,这些指令直接映射到指定的操作f2().

c c++ micro-optimization undefined-behavior language-lawyer

6
推荐指数
1
解决办法
341
查看次数

x86汇编中的高效mod 3

DIV指令在现代处理器上很昂贵.有没有更快的方法来减少x86汇编中的64位整数mod 3?

assembly x86-64 micro-optimization

6
推荐指数
1
解决办法
777
查看次数

_mm256_lddqu_si256和_mm256_loadu_si256之间有什么区别

_mm256_lddqu_si256基于我在网上找到的一个例子,我一直在使用.后来我发现了_mm256_loadu_si256.英特尔内在函数指南仅指出lddqu版本在跨越缓存行边界时可能表现更好.可能有什么好处loadu?一般来说,这些功能有何不同?

x86 simd intrinsics avx micro-optimization

6
推荐指数
1
解决办法
903
查看次数

len(arr)和arr.shape [0]之间的Numpy性能差距

我发现这len(arr)几乎快了两倍arr.shape[0],我想知道为什么.

我使用的是Python 3.5.2,Numpy 1.14.2,IPython 6.3.1

以下代码演示了这一点:

arr = np.random.randint(1, 11, size=(3, 4, 5))

%timeit len(arr)
# 62.6 ns ± 0.239 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

%timeit arr.shape[0]
# 102 ns ± 0.163 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
Run Code Online (Sandbox Code Playgroud)

我还做了一些比较测试:

class Foo():
    def __init__(self):
        self.shape = (3, 4, 5)        

foo = Foo()

%timeit arr.shape
# 75.6 ns ± 0.107 ns per loop …
Run Code Online (Sandbox Code Playgroud)

python arrays performance numpy micro-optimization

6
推荐指数
1
解决办法
482
查看次数

为什么编译器不总是优化掉局部变量?

我试图了解是否删除局部中间变量可以导致更好的优化代码。考虑以下MWE,要特别注意这两个函数fg

struct A {
    double d;
};

struct B {
    double s;
};

struct C {
    A a;
    B b;
};

A geta();
B getb();

C f() {
    const A a = geta();
    const B b = getb();

    C c;
    c.a = a;
    c.b = b;
    return c;
}

C g() {
    C c;
    c.a = geta();
    c.b = getb();
    return c;
}
Run Code Online (Sandbox Code Playgroud)

fg呼叫geta()getb()来填充类的实例C,然后将其返回,但f使用两个本地中间变量来存储的返回值 …

c++ gcc micro-optimization compiler-optimization

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