相关疑难解决方法(0)

C循环优化有助于最终分配

因此,对于我在计算机系统课程中的最终作业,我们需要优化这些forloops,使其比原始版本更快.使用我们的linux服务器,基本等级不到7秒,完整等级不到5秒.我在这里的代码大约需要5.6秒.我想我可能需要以某种方式使用指针来使它更快,但我不是很确定.任何人都可以提供我的任何提示或选项吗?非常感谢!

QUICKEDIT:文件必须保持50行或更少,我忽略了教师所包含的那些注释行.

#include <stdio.h>
#include <stdlib.h>

// You are only allowed to make changes to this code as specified by the comments in it.

// The code you submit must have these two values.
#define N_TIMES     600000
#define ARRAY_SIZE   10000

int main(void)
{
    double  *array = calloc(ARRAY_SIZE, sizeof(double));
    double  sum = 0;
    int     i;

    // You can add variables between this comment ...
    register double sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0, sum5 = 0, …
Run Code Online (Sandbox Code Playgroud)

c optimization loops compiler-optimization debug-mode

8
推荐指数
2
解决办法
5650
查看次数

仅遍历第一个和最后一个元素

给定N元素,仅处理第一个(0)和最后一个(N-1)元素.

但是,如果N = 1只处理单个元素一次.

使用一个或两次运行的循环,可以避免重复循环体.如果有一种可读的方法,那么它对源代码大小有好处.如果循环体很大,它也可能对机器代码大小有好处,并且编译器最终不会复制它.


我试过递增N-1但是当N=1(永远循环)时它不起作用.有没有技巧(反向循环fi)来解决这个问题?

for (i = 0 ; i < N ; i += (N - 1))
Run Code Online (Sandbox Code Playgroud)

编辑:

我原来的问题涉及x,y,z方向的三个嵌套循环,这就是为什么我不能只处理elem [0])和elem [N-1].现在我有以下内容

#define forEachLglBound(i_,j_,k_)                                   \
        for(Int i_ = 0;i_ < NPX;i_+=((NPX>1) ? (NPX-1) : 1))        \
            for(Int j_ = 0;j_ < NPY;j_+=((NPY>1) ? (NPY-1) : 1))    \
                for(Int k_ = 0;k_ < NPZ;k_+=((NPZ>1) ? (NPZ-1) : 1))
Run Code Online (Sandbox Code Playgroud)

c loops for-loop

8
推荐指数
1
解决办法
537
查看次数

充分利用kaby湖上的管道

(此处跟进代码复习问题,包含此循环上下文的更多详细信息.)


环境:

  • Windows 7 x64
  • VS 2017社区
  • 在Intel i7700k(kaby lake)上定位x64代码

我没有写很多汇编程序代码,当我这么做时,它要么足够短,要么足够简单,以至于我不必担心压缩它的最大数量.我的更复杂的代码通常用C编写,我让编译器的优化器担心延迟,代码对齐等.

但是在我目前的项目中,MSVC的优化器在关键路径中的代码上做得非常糟糕.所以...

我还没有找到一个好的工具,可以对x64汇编代码进行静态或运行时分析,以便消除停顿,改善延迟等等.我所拥有的只是VS分析器,它告诉我(大致)哪些指令花了最多的时间.墙上的时钟告诉我最近的变化是否使事情变得更好或更糟.

作为替代方案,我一直在通过Agner的文档进行操作,希望能从我的代码中挤出一些更多的信息.问题是,在你理解了所有这些工作之前,很难理解他的任何工作.但它的一部分是有意义的,我正在尝试应用我学到的东西.

记住这一点,这里是我最内层循环的核心(不足为奇)是VS剖析器说我花费的时间:

nottop:

vpminub ymm2, ymm2, ymm3 ; reset out of range values
vpsubb  ymm2, ymm2, ymm0 ; take a step

top:
vptest  ymm2, ymm1       ; check for out of range values
jnz nottop

; Outer loop that does some math, does a "vpsubb ymm2, ymm2, ymm0",
; and eventually jumps back to top
Run Code Online (Sandbox Code Playgroud)

是的,这几乎是一个依赖链的教科书示例:这个紧密的小循环中的每个指令都取决于前一个操作的结果.这意味着没有并行性,这意味着我没有充分利用处理器.

受Agner的"优化汇编程序"文档的启发,我想出了一种方法(希望)允许我一次做2个操作,所以我可以有一个管道更新ymm2和另一个更新(比如说)ymm8.

虽然这是一个非平凡的变化,所以在我开始撕掉所有东西之前,我想知道它是否可能有所帮助.看看Agner的kaby lake(我的目标)的"指令表",我看到:

        uops
        each
        port    Latency
pminub …
Run Code Online (Sandbox Code Playgroud)

performance assembly x86-64 micro-optimization avx2

8
推荐指数
1
解决办法
275
查看次数

从/向xmm/ymm寄存器加载/存储通用寄存器的最佳方法

从SIMD寄存器加载和存储生成目的寄存器的最佳方法是什么?到目前为止,我一直在使用堆栈作为临时.例如,

mov [rsp + 0x00], r8
mov [rsp + 0x08], r9
mov [rsp + 0x10], r10
mov [rsp + 0x18], r11
vmovdqa ymm0, [rsp] ; stack is properly aligned first.
Run Code Online (Sandbox Code Playgroud)

我认为没有任何指令可以直接(或另一个方向)执行此操作,因为它意味着具有五个操作数的指令.但是,上面的代码对我来说似乎很愚蠢.有没有更好的方法呢?我只能想到一个替代方案,使用pinsrd相关说明.但它似乎没有任何好转.

动机是,有时候在AVX2中做一些事情会更快,而其他用于通用的注册事项.例如,在一小段代码中,有四个64位无符号整数,我将需要四个xor,两个mulx来自BMI2.这将是更快的做xorvpxor,但是,mulx没有一个AVX2等同.由于包装和拆包过程,任何vpxor对比4 的增益xor都会丢失.

x86 assembly simd sse2 avx2

7
推荐指数
1
解决办法
783
查看次数

如何强制NASM将[1 + rax*2]编码为disp32 + index*2而不是disp8 + base + index?

为了有效地做x = x*10 + 1,它可能是最佳使用

lea   eax, [rax + rax*4]   ; x*=5
lea   eax, [1 + rax*2]     ; x = x*2 + 1
Run Code Online (Sandbox Code Playgroud)

3组件LEA在现代Intel CPU上具有更高的延迟,例如3个周期而不是Sandybridge系列的1个,因此disp32 + index*2disp8 + base + index*1SnB系列更快,即我们关心优化的大多数主流x86 CPU.(这主要仅适用于LEA,而不适用于加载/存储,因为LEA运行在ALU执行单元上,而不是大多数现代x86 CPU中的AGU.)AMD CPU具有3个组件的LEA较慢或scale > 1(http://agner.org/optimize /)

但NASM和YASM将通过使用[1 + rax + rax*1]第二个LEA 来优化代码大小,第二个LEA只需要disp8而不是disp32.(寻址模式始终具有基址寄存器或disp32).

即他们总是分裂reg*2base+index,因为对于代码大小来说,这永远不会更糟.

我可以强制使用disp32 lea eax, [dword 1 + rax*2],但这并不能阻止NASM或YASM分割寻址模式.在NASM手动似乎并没有记录的方式来使用strict关键字上规模的因素,并[1 + …

x86 assembly nasm machine-code micro-optimization

7
推荐指数
1
解决办法
248
查看次数

程序集8086 - 在没有MUL和DIV指令的情况下实现任何乘法和除法

我想知道是否有办法在不使用MUL或DIV指令的情况下执行任何乘法或除法,因为它们需要大量的CPU周期.我可以为此目标利用SHL或SHR指令吗?如何实现汇编代码?

assembly multiplication division cpu-usage

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

为什么x86汇编中的64位被分红?

为什么idivx86汇编指令EDX:EAX被给定寄存器除(64位)而其他数学运算(包括乘法)只能在单个输入和输出寄存器上运行?

乘法:

mov eax, 3
imul eax, 5
Run Code Online (Sandbox Code Playgroud)

师:

mov edx, 0
mov eax, 15
mov ebx, 5
idiv ebx
Run Code Online (Sandbox Code Playgroud)

我知道这EDX用于存储余数,但为什么没有单独的指令用于此行为?这对我来说似乎不一致.

x86 assembly

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

gcc内联汇编 - 操作数类型不匹配"add",试图创建无分支代码

我正在尝试做一些代码优化来消除分支,原始的c代码是

if( a < b ) 
   k = (k<<1) + 1;
else
   k = (k<<1)
Run Code Online (Sandbox Code Playgroud)

我打算用下面的汇编代码替换它

mov a, %rax 
mov b, %rbx
mov k, %rcx
xor %rdx %rdx
shl 1, %rcx
cmp %rax, %rax
setb %rdx
add %rdx,%rcx
mov %rcx, k 
Run Code Online (Sandbox Code Playgroud)

所以我写了内联汇编代码,如打击,

#define next(a, b, k)\
 __asm__("shl $0x1, %0; \
         xor %%rbx, %%rbx; \
         cmp %1, %2; \
         setb %%rbx; \
         addl  %%rbx,%0;":"+c"(k) :"g"(a),"g"(b))
Run Code Online (Sandbox Code Playgroud)

当我编译下面的代码时,我得到了错误:

operand type mismatch for `add'
operand type mismatch for `setb'
Run Code Online (Sandbox Code Playgroud)

我该如何解决?

c performance x86 assembly inline-assembly

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

XOR AL,AL + MOVZX EAX,AL优于XOR EAX,EAX的任何优势?

我有一些在Release版本中编译的未知C++代码,因此它已经过优化.我正在努力的一点是:

xor     al, al
add     esp, 8
cmp     byte ptr [ebp+userinput], 31h
movzx   eax, al
Run Code Online (Sandbox Code Playgroud)

这是我的理解:

xor     al, al    ; set eax to 0x??????00 (clear last byte)
add     esp, 8    ; for some unclear reason, set the stack pointer higher
cmp     byte ptr [ebp+userinput], 31h ; set zero flag if user input was "1"
movzx   eax, al   ; set eax to AL and extend with zeros, so eax = 0x000000??
Run Code Online (Sandbox Code Playgroud)

我不关心第2行和第3行.由于流水线的原因,它们可能按此顺序存在,而恕我直言与EAX无关.

但是,我不明白为什么我会首先清除AL,以便稍后清除EAX的其余部分.结果将恕我直言EAX = 0,所以这也可能

xor eax, eax
Run Code Online (Sandbox Code Playgroud)

代替.这段代码的优势或"优化"是什么? …

c++ x86 assembly

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

将值从C程序传递到汇编语言

我想使用链接汇编方法而不是C中的内联汇编方法将值从C程序传递到汇编.下面是正在处理的汇编程序(GCD).

;gcdasm.nasm
bits 64
section .text
global gcdasm
gcdasm:
    push rbp
    mov rbp, rsp
    mov rax, [rbp+4]        ;load rax with x
    mov rbx, [rbp+8]        ;load rbx with y
top:
    cmp rax, rbx            ;x(rax) has to be larger than y(rbx)
    je exit                 ;if x=y then exit and return value y
    jb xchange              ;if x<y then swap x and y
modulo:
    cqo                     ;RDX:RAX sign extend
    div rbx                 ;div rdx:rax with rbx
    cmp rdx, 0              ;check remider if its 0
    je exit                 ;if …
Run Code Online (Sandbox Code Playgroud)

c linux assembly x86-64 nasm

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