繁体   English   中英

为什么嵌套for循环比展开相同代码要慢得多?

[英]Why is this nested for loop so much slower than unrolling the same code?

我正在使用ATtiny85和128x64px OLED构建一个小玩具控制台。 在我的初始构建中,我使用内置的shiftOut()digitalWrite()函数将显示数据移出到屏幕控制器。

这让我大约5fps,这有点令人失望。

我编写了自己的函数,使用直接端口操作来发送数据并且速度大幅提高~23fps,这也不错。 这是功能:

void shift_out_block(block)
{
    byte b;
    for (byte i = 0; i < 8; i++)  
    {
        b = pgm_read_byte(block+i);

        for (byte j=0 ; j < 8 ; j++)
        {
            if ( !!( b & (1 << j)) )
            {
                PORTB |= 1 << SDA;
            }
            else
            {
                PORTB &= ~(1 << SDA);
            }

            PORTB |= 1 << SCL; // HIGH
            PORTB &= ~(1 << SCL); // LOW
        }
    }
}

23fps还可以,但它不是30甚至60fps(如果它是24fps,我实际上已经把它留在了这里,但奇数......)。

我理解为什么删除库调用和操作端口直接改进了很多东西 - 库被编写为适用于各种不同的MCU。

我依稀记得循环解体是一个事情 ,所以我解开内for循环:

void shift_out_block()
{
    byte b;
    for (byte i = 0; i < 8; i++)  
    {
        b = pgm_read_byte(block+i);

        if ( !!( b & (1 << 0)) )
        {
            PORTB |= 1 << SDA;
        }
        else
        {
            PORTB &= ~(1 << SDA);
        }

        PORTB |= 1 << SCL; // HIGH
        PORTB &= ~(1 << SCL); // LOW

        if ( !!( b & (1 << 1)) )
        {
            PORTB |= 1 << SDA;
        }
        else
        {
            PORTB &= ~(1 << SDA);
        }

        PORTB |= 1 << SCL; // HIGH
        PORTB &= ~(1 << SCL); // LOW

        if ( !!( b & (1 << 2)) )
        {
            PORTB |= 1 << SDA;
        }
        else
        {
            PORTB &= ~(1 << SDA);
        }

        PORTB |= 1 << SCL; // HIGH
        PORTB &= ~(1 << SCL); // LOW

        if ( !!( b & (1 << 3)) )
        {
            PORTB |= 1 << SDA;
        }
        else
        {
            PORTB &= ~(1 << SDA);
        }

        PORTB |= 1 << SCL; // HIGH
        PORTB &= ~(1 << SCL); // LOW

        if ( !!( b & (1 << 4)) )
        {
            PORTB |= 1 << SDA;
        }
        else
        {
            PORTB &= ~(1 << SDA);
        }

        PORTB |= 1 << SCL; // HIGH
        PORTB &= ~(1 << SCL); // LOW

        if ( !!( b & (1 << 5)) )
        {
            PORTB |= 1 << SDA;
        }
        else
        {
            PORTB &= ~(1 << SDA);
        }

        PORTB |= 1 << SCL; // HIGH
        PORTB &= ~(1 << SCL); // LOW

        if ( !!( b & (1 << 6)) )
        {
            PORTB |= 1 << SDA;
        }
        else
        {
            PORTB &= ~(1 << SDA);
        }

        PORTB |= 1 << SCL; // HIGH
        PORTB &= ~(1 << SCL); // LOW

        if ( !!( b & (1 << 7)) )
        {
            PORTB |= 1 << SDA;
        }
        else
        {
            PORTB &= ~(1 << SDA);
        }

        PORTB |= 1 << SCL; // HIGH
        PORTB &= ~(1 << SCL); // LOW
    }
}

毫不费力,复制粘贴7次。 给我近75fps - 原始功能在~42ms执行,新的丑陋只需要~13ms。

出于兴趣,我将发送位部分作为一个单独的函数打破并调用了8次:

void shift_out_bit(bool bit)
{
    if ( bit )
    {
        PORTB |= 1 << SDA;
    }
    else
    {
        PORTB &= ~(1 << SDA);
    }

    PORTB |= 1 << SCL; // HIGH
    PORTB &= ~(1 << SCL); // LOW
}

void shift_out_block()
{
    byte b;
    for (byte i = 0; i < 8; i++)  
    {
        b = pgm_read_byte(block+i);

        shift_out_bit( !!( b & (1 << 0)) );
        shift_out_bit( !!( b & (1 << 1)) );
        shift_out_bit( !!( b & (1 << 2)) );
        shift_out_bit( !!( b & (1 << 3)) );
        shift_out_bit( !!( b & (1 << 4)) );
        shift_out_bit( !!( b & (1 << 5)) );
        shift_out_bit( !!( b & (1 << 6)) );
        shift_out_bit( !!( b & (1 << 7)) );
    }
}

〜22ms执行,或45.4545454545 fps,这甚至不是一个很好的数字。

我不是由任何发挥想象力的C程序员- Python是我平常出没的地方(我最初开始在Python / RPI这个项目,但很快就放弃了这一点!)。

为什么这种核心语言功能在这种情况下要慢得多? 随着我的项目变得更加复杂,我应该考虑哪些其他优化措施?

考虑在最内层循环内完成的“有效负载”操作:

  • 检查b中的特定位
  • 有条件的跳转来处理PORTB |= 1 << SDAPORTB &= ~(1 << SDA)
  • PORTB三个操作

这就是循环的所有展开版本; 没有别的需要做,甚至没有转移1向左j次,因为编译器计算常量表达式,而1 << 4变得简单16

另一方面,没有展开的循环必须做额外的事情来保持循环:

  • 增加j
  • 比较j到8
  • 转移1由左j位置
  • 无条件跳转到循环的开头

当循环展开时,CPU不再需要这些“非有效负载”指令,因此执行速度会提高。

为什么这种核心语言功能在这种情况下要慢得多?

许多现代编译器会根据优化设置自动为您展开循环。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM