标签: micro-optimization

什么是更快的Python,"while"或"for xrange"

我们可以做数字迭代,如:

for i in xrange(10):
    print i,
Run Code Online (Sandbox Code Playgroud)

和C风格:

i = 0
while i < 10:
    print i,
    i = i + 1
Run Code Online (Sandbox Code Playgroud)

是的,我知道,第一个不容易出错,更像pythonic,但它是否足够快作为C风格的版本?

PS.我是来自C++星球,而且是Python上的新星.

python micro-optimization

5
推荐指数
2
解决办法
1万
查看次数

如何:使用C++内联汇编程序(在Visual Studio 2010下)

我正在编写一个性能关键,数字运算的C++项目,其中70%的时间用于200线核心模块.

我想使用内联汇编来优化内核,但我对此完全陌生.但是,我知道一些x86汇编语言,包括GCC和NASM使用的语言.

据我所知:

我必须将汇编程序指令放在_asm{}我想要的位置.

问题:

  • 我不知道从哪里开始.在我的内联汇编发挥作用时,哪个寄存器是什么?

c++ inline-assembly visual-studio-2010 micro-optimization visual-c++

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

关于循环速度的问题

我有以下两个循环:

#include <iostream>
#include <stdlib.h>
#include <time.h>

using namespace std;
int main(){

    int start=clock();
    for (int i=0;i<100;i++)
        cout<<i<<" "<<endl;
    cout<<clock()-start<<"\n"<<endl;
    cout<<"\n";

    int start1=clock();
    for (int j=0;j<100;++j)
        cout<<j<<" "<<endl;
    cout<<"\n";
    cout<<clock()-start1<<" \n "<<endl;

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

我跑了三次.在前两次运行中,第二次循环最快,但在第三次运行时,第一次循环最快.这是什么意思?哪个更好?这取决于具体情况吗?

c++ micro-optimization

5
推荐指数
2
解决办法
423
查看次数

高性能内存缓存的线程安全性

我有一个静态内存缓存,只能写入一小时(或更长)一次,并被许多线程以极高的速率读取.传统观点认为我遵循以下模式:

public static class MyCache
{
    private static IDictionary<int, string> _cache;
    private static ReaderWriterLockSlim _sharedLock;

    static MyCache()
    {
        _cache = new Dictionary<int, string>();
        _sharedLock = new ReaderWriterLockSlim();
    }

    public static string GetData(int key)
    {
        _sharedLock.EnterReadLock();
        try
        {
            string returnValue;
            _cache.TryGetValue(key, out returnValue);
            return returnValue;
        }
        finally
        {
            _sharedLock.ExitReadLock();
        }
    }

    public static void AddData(int key, string data)
    {
        _sharedLock.EnterWriteLock();
        try
        {
            if (!_cache.ContainsKey(key))
                _cache.Add(key, data);
        }
        finally
        {
            _sharedLock.ExitWriteLock();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

作为微优化的练习,如何在共享锁的相对费用中削减更多的滴答声?写作的 …

c# performance thread-safety micro-optimization

5
推荐指数
2
解决办法
7563
查看次数

如果需要创建密钥,如何正确增加某些数组键?

假设您需要创建某种类型的"顶部"并具有如下代码:

$matches=array();
foreach ($array as $v){
   $matches[processing($v)]++;  
}
Run Code Online (Sandbox Code Playgroud)

这将为Notice: Undefined index索引需要创建的案例输出a .

既然你知道你必须创建索引,那么解决这些案例的最佳方法是什么?

我根据具体情况使用了这些解决方案

  1. 抑制错误@$matches[$v]++;
    Pro:非常容易键入
    Con:慢
  2. 检查它是否设置为$matches[$v]=isset($matches[$v])?$matches[$v]++:1;
    Pro:更快
    Con:即使以速记形式也需要更长的时间来写,需要再使用$ match [$ v] 2次

还有其他方法吗?
寻找最快的执行时间,因为我使用此功能数千次或一些更懒的方式来输入仍然比@更快

编辑:

在一个简单的情况下,你也$matches[$v]++;可以使用array_count_values() (如Yoshi建议)

php optimization micro-optimization

5
推荐指数
1
解决办法
5428
查看次数

关于“每个程序员应该了解的内存”中包含的有关缓存和预取的示例之一

乌尔里希·德雷珀(Ulrich Drepper)在他的出色著作中提出了一个测试基准,我无法完全确定。

他正在谈论缓存和预取。他首先展示了一个测试,其中他正在访问每个16字节的元素数组(一个指针和一个64位整数,每个元素都有一个指向下一个的指针,但实际上这并不重要),并且对于每个元素,他递增它的值加一。

然后,他继续显示另一个测试,其中他正在访问同一数组,但是这次他将每个元素的值与下一个元素的值之和存储。

然后比较了这两个测试的数据,他显示,工作集小于L2D $的总大小(但大于L1D $的总大小),第二个测试的性能要优于第一个测试,他的动机是从下一个元素读取的内容充当“强制预取”,从而提高了性能。

现在,我不明白的是,当我们不仅要预取该行,而且实际上是从该行读取并在之后立即使用该数据时,该读取如何充当预取?该读取停顿不应该像在第一次测试中访问新元素时发生的那样停顿吗?实际上,在我看来,我认为第二个示例与第一个示例非常相似,唯一的区别是我们存储在上一个元素中,而不是最近的一个元素中(并且我们将两个元素相加而不是递增) 。

为了更准确地参考实际文本,在第22页右第三段中讨论了所涉及的测试,其相对图形为下一页的图3.13。

最后,我将在此处报告相关图表,并进行裁剪。第一个测试对应于蓝色的“ Inc”行,第二个测试对应于绿色的“ Addnext0”行。作为参考,红色的“跟随”行不执行写操作,而仅执行顺序读操作。

在此处输入图片说明

optimization caching cpu-architecture prefetch micro-optimization

5
推荐指数
0
解决办法
164
查看次数

通过值或C中的struct的多个参数

让我们假设这个结构:

typedef struct mytest_t {
    uint8_t field1;
    uint32_t field2;
    uint64_t field3;
    uint64_t field4;
    uint16_t field5;
    uint32_t field6;

} mytest_t;
Run Code Online (Sandbox Code Playgroud)

还有一些想要创建此结构的函数(有点像一个对象):

int something_with(uint8_t field1, uint32_t field2, uint64_t field3, uint16_t field5) {
    mytest_t *object = malloc(sizeof(mytest_t));

    object->field1 = field1;
    object->field2 = field2;
    object->field3 = field3;
    object->field4 = 0x12345678;
    object->field5 = field5;
    object->field6 = 42;

    dosomethingwith(object);
    return 0;
}

void initial() {
    something_with(123, 456, 789, 456);
}
Run Code Online (Sandbox Code Playgroud)

这些功能纯粹是出于我的情况。此函数就像一个帮助程序,在代码中有一个单一的点,在该点上,对象被填充然后转发到其他对象。

注意:这个例子很小,假设参数要长2到3倍。

为了避免将大量参数传递给函数,并使调用变得冗长且难以阅读,我考虑将一个预填充的mytest_t结构作为参数传递(假设需要的字段正确填充)。

将struct作为值或指针传递会更好吗?取消引用所有字段的成本是多少?既然所有内容都在堆栈中,那有什么区别吗?编译器可以某种方式对其进行优化吗?

void initial() {
    mytest_t source = {
        .field1 = 123, …
Run Code Online (Sandbox Code Playgroud)

c stack struct pointers micro-optimization

5
推荐指数
1
解决办法
170
查看次数

使用AVX2是否可以在字数组上实现LZCNT的更快处理?

我需要使用LZCNT对字数组进行反向扫描:16位。

在Intel最新一代处理器上,LZCNT的吞吐量是每个时钟1次执行。AMD Ryzen的吞吐量似乎是4。

我试图找到一种使用AVX2指令集的算法来更快。

我知道AVX-512具有VPLZCNTD为32位元素,所以如果我有AVX512CD我可以解压并使用它。

仅使用AVX2指令集,就可以比使用x86 asm LZCNT指令更快地编码算法。

x86 simd avx micro-optimization avx2

5
推荐指数
1
解决办法
196
查看次数

Skylake是否需要vzeroupper来使turbo时钟恢复到仅读取ZMM寄存器并写入ak掩码的512位指令后恢复?

编写ZMM寄存器可以使Skylake-X(或类似的)CPU无限期地处于最大涡流降低的状态。(SIMD指令可降低CPU频率动态确定恶意AVX-512指令在何处执行)推测Ice Lake是类似的。

解决方法:zmm16..31不是问题,据@ BeeOnRope的意见,我在报?是有用的,如果你的程序+库不包含SSE指令使用VZEROUPPER 所以这strlen的可以只使用vpxord xmm16,xmm16,xmm16vpcmpeqb,与zmm16)

如果您有硬件,如何进行测试:

@BeeOnRope发布测试代码在RWT线:更换vbroadcastsd zmm15, [zero_dp]vpcmpeqb k0, zmm0, [rdi]为“弄脏”指令,看看是否能运行后循环慢或快。


我假设执行任何512位uop都会暂时触发减少的turbo(同时关闭向量ALU uops的端口1,而512位uop实际上在后端),但问题是:CPU能否在其上恢复如果您vzeroupper仅在读取 ZMM寄存器后就从未使用过,您是否拥有?

(和/或以后的SSE或AVX指令是否会有过渡惩罚或错误的依赖关系?)

具体来说,这样的strlen使用insns vzeroupper在返回之前是否需要a ? (实际上,在任何实际的CPU上,和/或Intel记录的有关面向未来的最佳实践。)假定以后的指令可能包括非VEX SSE和/或VEX编码的AVX1 / 2,而不仅仅是GP整数,以防万一。这与使turbo减少的上256脏情况有关。

; check 64 bytes for zero, strlen building block.
    vpxor     xmm0,xmm0,xmm0    ; zmm0 = 0 using AVX1 implicit zero-extension
    vpcmpeqb  k0, zmm0, [rdi]   ; 512-bit load + ALU, not micro-fused
    ;kortestq k0,k0 / …
Run Code Online (Sandbox Code Playgroud)

x86 assembly intel micro-optimization avx512

5
推荐指数
1
解决办法
109
查看次数

在不使用乘法器的情况下,以2 ^ 8为基数加速大型模块化乘法

我目前正在将nacl库转换为risc-v。我已经有poly1305工作。我正在尝试使用risc-v核心指令集来执行此操作,因此我没有乘法器。Pol1305的算法正在使用ceil(m / 16)* 17 * 17 8位乘法,其中m是消息长度(以字节为单位)(两个2 ^ 130整数乘以2 ^ 8以2 ^ 130-5为基数) 。因此,我想使用快速乘法算法来保持快速。

目前,我有用于乘法的移位加法算法。但是,对于8位值,这需要63个周期,因为我需要避免分支(定时侧通道),因此涉及一些需要更多周期的屏蔽。

    andi  t2, t0, 1     //t0 is the multiplier
    sub   t2, zero, t2  //creating a mask
    and   t3, t1, t2    //applying the mask to the multiplicand
    add   a0, a0, t3    //doing the add
    srli  t0, t0, 1     //shifting the multiplier
    slli  t1, t1, 1     //shifting the multiplicand
Run Code Online (Sandbox Code Playgroud)

这给了我每次乘法63个周期的有效结果。问题在于,对于131字节的消息,程序的总执行时间为175219个周期。此时,将9 * 17 * 17 * 63 = 163863个周期用于乘法。我想改善。

assembly multiplication micro-optimization modular-arithmetic riscv

5
推荐指数
1
解决办法
458
查看次数