【问题标题】:Speedup copy between 2 arrays in a C loopC循环中2个数组之间的加速复制
【发布时间】:2016-05-06 14:41:46
【问题描述】:
  • 我需要将一些值从数组 A 复制到数组 B。
  • 要复制的项目数存储在 uint32_t r3 变量中。
  • 从 a 复制到 b 的值的每个索引都编码在 uint32_t next 变量中。
  • 每个索引不能超过 255(8 位),因此 4 个索引被编码到 uint32_t 变量 ip 中,并使用 OPCODE_GET_FOUR8bit 宏进行解码。

使用宏 STACK_GET(index) 从数组 A 读取数据,并使用宏 SETVALUE(index, value) 将数据写入数组 B。

我当前的复制循环是:

register uint32_t nloop = (r3+3)>>2; // efficient way to round r/4 upward
register idx = 0;
while (nloop) {
    uint32_t next = *ip++;
    OPCODE_GET_FOUR8bit(next, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4);

    if (r3) { SETVALUE(rwin+idx, STACK_GET(p1)); --r3;
        if (r3) { SETVALUE(rwin+idx+1, STACK_GET(p2)); --r3;
            if (r3) { SETVALUE(rwin+idx+2, STACK_GET(p3)); --r3;
                if (r3) { SETVALUE(rwin+idx+3, STACK_GET(p4)); --r3;
                }
            }
        }
    }
    --nloop; idx+=4;                    
}

这涉及循环内的 4 个 r3 递减和 4 个 if 语句(因为我事先知道使用 r3 复制的项目数,但循环一次编码 4 个索引)。

我想知道是否有办法加快这个性能关键循环。

【问题讨论】:

  • 只是评论,不是答案:不要四舍五入,只是截断 (r3>>2)。然后在不测试 r3 的情况下执行所有循环,因为您知道它将大于 0。然后,在循环之后,执行剩余的 3 个 r3 测试。这样,您将在每个循环中节省 4 个 if。也不要做--r3,只在每次迭代结束时做 r3-=4
  • 所有这些宏有什么作用?如果有任何事情甚至有点不重要,那么它们很可能是限速步骤。你能告诉我们为什么memcpy 不适合这个吗?
  • 例如,当 r3 为 2 时,nloop 为 1 并且 ip 将包含 2 个索引和 2 个垃圾编码,这就是为什么我需要在循环内递减并检查 r3 4 次,否则为 2垃圾会被复制。
  • memcpy 不适合,因为 p1,p2,p3,p4 可以是非连续索引。

标签: c arrays performance macros


【解决方案1】:

您显然知道上一次nloop 迭代的时间;所有之前的都不需要 ANY if 的。

[添加代码示例]

register idx = rwin;
while (r3 > 3) {
    uint32_t next = *ip++;
    OPCODE_GET_FOUR8bit(next, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4);

    SETVALUE(idx++, STACK_GET(p1));
    SETVALUE(idx++, STACK_GET(p2));
    SETVALUE(idx++, STACK_GET(p3));
    SETVALUE(idx++, STACK_GET(p4));
    r3 -= 4;
}
if (r3) {
    uint32_t next = *ip++;
    OPCODE_GET_FOUR8bit(next, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4);
    SETVALUE(idx++, STACK_GET(p1)); --r3;
    if (r3) {
        SETVALUE(idx++, STACK_GET(p2)); --r3;
        if (r3) {
            SETVALUE(idx++, STACK_GET(p3)); --r3;
        }
    }
}

【讨论】:

  • 要么“伟大的思想相似”,要么“傻瓜很少不同”。 ;)
  • @Roddy - 我在保存编辑时看​​到了您的评论 :)
【解决方案2】:

让我们假设您的宏不会影响性能(尽管我对此表示怀疑)。首先,用一个简单的循环处理“简单”的情况。没有条件。

register idx;

for (idx=rwin; r3 >= 4; r3 -=4)
{
    OPCODE_GET_FOUR8bit(*ip++, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4);

    SETVALUE(idx++, STACK_GET(p1));
    SETVALUE(idx++, STACK_GET(p2));
    SETVALUE(idx++, STACK_GET(p3));
    SETVALUE(idx++, STACK_GET(p4));
}

然后,对最后一个(最多三个)值使用“复杂”情况。 r3 现在只能是 0、1、2 或 3。如果它为零,我们就完成了。

 if (r3 >=1 ) 
   SETVALUE(idx++, STACK_GET(p1));
 if (r3 >= 2)
   SETVALUE(idx++, STACK_GET(p2));
 if (r3 >=3 ) 
   SETVALUE(idx++, STACK_GET(p3));

如果您需要进一步加速,在主循环中汇编和写入单个 32 位值可能比编写四个 8 位值更快。在不知道您的宏的作用的情况下,不可能为此建议代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    • 2019-07-30
    • 1970-01-01
    • 1970-01-01
    • 2022-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多