รับประสิทธิภาพที่รวดเร็วจาก STM32 MCU


11

ฉันกำลังทำงานกับชุดค้นพบ STM32F303VC และฉันก็สับสนกับประสิทธิภาพของมันเล็กน้อย เพื่อทำความคุ้นเคยกับระบบฉันได้เขียนโปรแกรมง่าย ๆ เพียงเพื่อทดสอบความเร็วบิตของ MCU นี้ รหัสสามารถแยกย่อยได้ดังนี้:

  1. นาฬิกา HSI (8 MHz) เปิดอยู่;
  2. PLL เริ่มต้นด้วยกับ prescaler ที่ 16 เพื่อให้ได้ HSI / 2 * 16 = 64 MHz
  3. PLL ถูกกำหนดให้เป็น SYSCLK;
  4. SYSCLK ถูกตรวจสอบบน MCO pin (PA8) และหนึ่งในพิน (PE10) จะถูกสลับในลูปไม่สิ้นสุด

ซอร์สโค้ดสำหรับโปรแกรมนี้แสดงอยู่ด้านล่าง:

#include "stm32f3xx.h"

int main(void)
{
      // Initialize the HSI:
      RCC->CR |= RCC_CR_HSION;
      while(!(RCC->CR&RCC_CR_HSIRDY));

      // Initialize the LSI:
      // RCC->CSR |= RCC_CSR_LSION;
      // while(!(RCC->CSR & RCC_CSR_LSIRDY));

      // PLL configuration:
      RCC->CFGR &= ~RCC_CFGR_PLLSRC;     // HSI / 2 selected as the PLL input clock.
      RCC->CFGR |= RCC_CFGR_PLLMUL16;   // HSI / 2 * 16 = 64 MHz
      RCC->CR |= RCC_CR_PLLON;          // Enable PLL
      while(!(RCC->CR&RCC_CR_PLLRDY));  // Wait until PLL is ready

      // Flash configuration:
      FLASH->ACR |= FLASH_ACR_PRFTBE;
      FLASH->ACR |= FLASH_ACR_LATENCY_1;

      // Main clock output (MCO):
      RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
      GPIOA->MODER |= GPIO_MODER_MODER8_1;
      GPIOA->OTYPER &= ~GPIO_OTYPER_OT_8;
      GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR8;
      GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8;
      GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL0;

      // Output on the MCO pin:
      //RCC->CFGR |= RCC_CFGR_MCO_HSI;
      //RCC->CFGR |= RCC_CFGR_MCO_LSI;
      //RCC->CFGR |= RCC_CFGR_MCO_PLL;
      RCC->CFGR |= RCC_CFGR_MCO_SYSCLK;

      // PLL as the system clock
      RCC->CFGR &= ~RCC_CFGR_SW;    // Clear the SW bits
      RCC->CFGR |= RCC_CFGR_SW_PLL; //Select PLL as the system clock
      while ((RCC->CFGR & RCC_CFGR_SWS_PLL) != RCC_CFGR_SWS_PLL); //Wait until PLL is used

      // Bit-bang monitoring:
      RCC->AHBENR |= RCC_AHBENR_GPIOEEN;
      GPIOE->MODER |= GPIO_MODER_MODER10_0;
      GPIOE->OTYPER &= ~GPIO_OTYPER_OT_10;
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR10;
      GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR10;

      while(1)
      {
          GPIOE->BSRRL |= GPIO_BSRR_BS_10;
          GPIOE->BRR |= GPIO_BRR_BR_10;

      }
}

โค้ดถูกคอมไพล์ด้วย CoIDE V2 พร้อมกับ GNU ARM Embedded Toolchain โดยใช้การเพิ่มประสิทธิภาพ -O1 สัญญาณบนหมุด PA8 (MCO) และ PE10 ที่ตรวจสอบด้วยออสซิลโลสโคปมีลักษณะดังนี้: ป้อนคำอธิบายรูปภาพที่นี่

SYSCLK ดูเหมือนจะได้รับการกำหนดค่าอย่างถูกต้องเนื่องจาก MCO (เส้นโค้งสีส้ม) แสดงความผันผวนเกือบ 64 MHz (พิจารณาจากระยะขอบผิดพลาดของนาฬิกาภายใน) ส่วนที่แปลกสำหรับฉันคือพฤติกรรมของ PE10 (เส้นโค้งสีน้ำเงิน) ในอนันต์ขณะที่ (1) ลูปจะใช้เวลา 4 + 4 + 5 = 13 รอบนาฬิกาเพื่อดำเนินการขั้นตอนพื้นฐาน 3 ขั้นตอน (เช่นบิตเซ็ต / บิตรีเซ็ต / ส่งคืน) มันยิ่งแย่ลงในระดับการปรับให้เหมาะสมอื่น ๆ (เช่น -O2, -O3, ar -Os): เพิ่มรอบสัญญาณนาฬิกาจำนวนมากลงในส่วนที่ต่ำของสัญญาณนั่นคือระหว่างขอบที่ลดลงและเพิ่มขึ้นของ PE10 เพื่อแก้ไขสถานการณ์นี้)

พฤติกรรมนี้คาดหวังจาก MCU นี้หรือไม่ ฉันคิดว่างานง่าย ๆ เพียงตั้งค่าและรีเซ็ตบิตควรเร็วขึ้น 2-4 เท่า มีวิธีเร่งความเร็วของสิ่งต่างๆหรือไม่?


คุณได้ลองกับ MCU อื่นเพื่อเปรียบเทียบหรือไม่
Marko Buršič

3
คุณพยายามทำอะไรให้สำเร็จ หากคุณต้องการผลลัพธ์ที่ออกมาอย่างรวดเร็วคุณควรใช้ตัวจับเวลา หากคุณต้องการเชื่อมต่อกับโปรโตคอลอนุกรมที่รวดเร็วคุณควรใช้อุปกรณ์ต่อพ่วงที่เกี่ยวข้อง
Jonas Schäfer

2
เริ่มต้นที่ยอดเยี่ยมกับชุด !!
Scott Seidman

คุณต้องไม่ | = ลงทะเบียน BSRR หรือ BRR เนื่องจากเขียนเท่านั้น
P__J__

คำตอบ:


25

คำถามที่นี่คือจริง ๆ : รหัสเครื่องที่คุณสร้างจากโปรแกรม C คืออะไรและแตกต่างจากที่คุณคาดหวังอย่างไร

หากคุณไม่สามารถเข้าถึงรหัสต้นฉบับได้นี่เป็นการฝึกหัดทางวิศวกรรมย้อนกลับ (โดยพื้นฐานแล้วมีบางอย่างที่เริ่มต้นด้วย:) radare2 -A arm image.bin; aaa; VVแต่คุณได้รับรหัสเพื่อให้ง่ายขึ้น

ก่อนอื่นให้รวบรวมด้วยการ-gตั้งค่าสถานะที่เพิ่มลงในCFLAGS(สถานที่เดียวกันกับที่คุณระบุ-O1) จากนั้นดูแอสเซมบลีที่สร้างขึ้น:

arm-none-eabi-objdump -S yourprog.elf

โปรดสังเกตว่าแน่นอนว่าทั้งชื่อของobjdumpไบนารีและไฟล์ ELF ระดับกลางของคุณอาจแตกต่างกัน

โดยปกติคุณสามารถข้ามส่วนที่ GCC เรียกใช้แอสเซมเบลอร์และดูไฟล์ประกอบได้ เพียงเพิ่ม-Sไปยังบรรทัดคำสั่ง GCC - แต่โดยปกติจะเป็นการทำลายงานสร้างของคุณดังนั้นคุณอาจทำมันนอก IDE ของคุณ

ฉันประกอบชุดโค้ดของคุณในเวอร์ชันที่แพตช์เล็กน้อย :

arm-none-eabi-gcc 
    -O1 ## your optimization level
    -S  ## stop after generating assembly, i.e. don't run `as`
    -I/path/to/CMSIS/ST/STM32F3xx/ -I/path/to/CMSIS/include
     test.c

และได้รับต่อไปนี้ (ตอนที่ตัดตอนมา, รหัสเต็มภายใต้ลิงค์ด้านบน):

.L5:
    ldr r2, [r3, #24]
    orr r2, r2, #1024
    str r2, [r3, #24]
    ldr r2, [r3, #40]
    orr r2, r2, #1024
    str r2, [r3, #40]
    b   .L5

ซึ่งเป็นลูป (สังเกตการกระโดดแบบไม่มีเงื่อนไขไปที่. L5 ที่ท้ายและเลเบล. L5 ที่จุดเริ่มต้น)

สิ่งที่เราเห็นที่นี่คือเรา

  • ก่อนldr(โหลดรีจิสเตอร์) รีจิสเตอร์r2ด้วยค่าที่ตำแหน่งหน่วยความจำที่เก็บในr3+24 ไบต์ BSRRขี้เกียจเกินไปที่จะเงยหน้าขึ้นมองว่ามีโอกาสมากที่สถานที่ตั้งของ
  • จากนั้นทะเบียนมีอย่างต่อเนื่องซึ่งจะสอดคล้องกับการตั้งค่าบิตที่ 10 ในการลงทะเบียนนั้นและเขียนผลให้ตัวเองORr21024 == (1<<10)r2
  • จากนั้นstr(จัดเก็บ) ผลลัพธ์ในตำแหน่งหน่วยความจำที่เราอ่านจากในขั้นตอนแรก
  • แล้วทำซ้ำเช่นเดียวกันสำหรับสถานที่ตั้งของหน่วยความจำที่แตกต่างกันออกจาก lazyness: ส่วนใหญ่มีแนวโน้มBRR's อยู่
  • ในที่สุดb(สาขา) กลับไปที่ขั้นตอนแรก

ดังนั้นเราจึงมี 7 คำแนะนำไม่ใช่สามเริ่มต้นด้วย เฉพาะbที่เกิดขึ้นครั้งเดียวและทำให้มีโอกาสมากสิ่งที่เกิดเป็นเลขคี่รอบ (เรามี 13 ทั้งหมดดังนั้นที่ไหนสักแห่งนับวงจรแปลกต้องมาจาก) เนื่องจากตัวเลขคี่ต่ำกว่า 13 ทั้งหมดคือ 1, 3, 5, 7, 9, 11 และเราสามารถแยกตัวเลขใด ๆ ที่มีขนาดใหญ่กว่า 13-6 (สมมติว่า CPU ไม่สามารถดำเนินการคำสั่งในรอบน้อยกว่าหนึ่งรอบ) เรารู้ ที่bใช้เวลา 1, 3, 5 หรือ 7 รอบของ CPU

ฉันเป็นคนที่เราเป็นอย่างนั้นฉันดูเอกสารคำแนะนำของ ARM และดูว่าพวกเขาใช้เวลากับ M3 เท่าไร :

  • ldr ใช้เวลา 2 รอบ (ในกรณีส่วนใหญ่)
  • orr ใช้เวลา 1 รอบ
  • str ใช้เวลา 2 รอบ
  • bใช้เวลา 2 ถึง 4 รอบ เรารู้ว่ามันต้องเป็นเลขคี่, ดังนั้นต้องใช้ 3, ตรงนี้

นั่นคือทั้งหมดที่สอดคล้องกับการสังเกตของคุณ:

13=2(cldr+corr+cstr)+cb=2(2+1+2)+3=25+3

ในฐานะที่เป็นแสดงให้เห็นว่าการคำนวณข้างต้นมีแทบจะเป็นวิธีการทำห่วงใด ๆ ของคุณได้เร็วขึ้น - ขาเอาท์พุทบนตัวประมวลผล ARM มักจะหน่วยความจำที่แมปไม่ได้ลงทะเบียน CPU หลักดังนั้นคุณจะต้องไปผ่านปกติโหลด - แก้ไข - ร้านประจำถ้า คุณต้องการทำอะไรกับสิ่งเหล่านั้น

สิ่งที่คุณสามารถของหลักสูตรจะไม่ได้อ่าน ( |=โดยปริยายมีการอ่าน) มูลค่าขาของทุกวงซ้ำ แต่เพียงแค่เขียนค่าของตัวแปรท้องถิ่นไปซึ่งคุณเพียงแค่สลับทุกย้ำห่วง

โปรดสังเกตว่าฉันรู้สึกว่าคุณอาจคุ้นเคยกับ 8bit micros และจะพยายามอ่านค่า 8 บิตเท่านั้นเก็บไว้ในตัวแปรโลคอล 8 บิตในท้องถิ่นและเขียนมันในบิต 8 บิต อย่า ARM เป็นสถาปัตยกรรม 32 บิตและการแยกคำ 32 บิต 8 บิตอาจใช้คำแนะนำเพิ่มเติม หากคุณทำได้เพียงแค่อ่านทั้งคำ 32 บิตปรับเปลี่ยนสิ่งที่คุณต้องการแล้วเขียนมันกลับคืนมา แน่นอนว่าเป็นไปได้หรือไม่นั้นขึ้นอยู่กับสิ่งที่คุณกำลังเขียนเช่นรูปแบบและฟังก์ชันการทำงานของ GPIO ที่แมปหน่วยความจำของคุณ ดูที่แผ่นข้อมูล / คู่มือผู้ใช้ STM32F3 สำหรับข้อมูลเกี่ยวกับสิ่งที่เก็บไว้ใน 32 บิตที่มีบิตที่คุณต้องการสลับ


ตอนนี้ผมพยายามที่จะทำซ้ำปัญหาของคุณด้วย "ต่ำ" ระยะเวลาที่ได้รับอีกต่อไป แต่ผมก็อาจไม่ได้ - ลักษณะห่วงตรงเดียวกันด้วย-O3เช่นเดียวกับ-O1กับรุ่นคอมไพเลอร์ของฉัน คุณจะต้องทำเอง! บางทีคุณอาจกำลังใช้ GCC รุ่นเก่ากับการสนับสนุน ARM ที่ไม่มีประสิทธิภาพ


4
จะไม่เพียงเก็บ ( =แทน|=) อย่างที่คุณพูดว่าเป็นความเร็วที่ OP กำลังมองหา? เหตุผลที่ ARM มีการลงทะเบียน BRR และ BSRR แยกต่างหากคือไม่จำเป็นต้องอ่าน - แก้ไข - เขียน ในกรณีนี้ค่าคงที่สามารถเก็บไว้ในรีจิสเตอร์นอกลูปดังนั้นลูปภายในจะเป็น 2 str's และสาขาดังนั้น 2 +2 +3 = 7 รอบสำหรับรอบทั้งหมด?
Timo

ขอบคุณ นั่นทำให้สิ่งต่าง ๆ กระจัดกระจายไปหมด มันเป็นความคิดที่เร่งรีบที่จะยืนยันว่าต้องการเพียง 3 รอบนาฬิกา - 6-7 รอบเป็นสิ่งที่ฉันหวังไว้ -O3ข้อผิดพลาดดูเหมือนจะหายไปหลังจากการทำความสะอาดและสร้างใหม่การแก้ปัญหา อย่างไรก็ตามรหัสชุดประกอบของฉันดูเหมือนจะมีคำสั่ง UTXH เพิ่มเติมอยู่ภายใน: .L5: ldrh r3, [r2, #24] uxth r3, r3 orr r3, r3, #1024 strh r3, [r2, #24] @ movhi ldr r3, [r2, #40] orr r3, r3, #1024 str r3, [r2, #40] b .L5
KR

1
uxthเป็นเพราะGPIO->BSRRLมี (ถูกต้อง) กำหนดเป็น 16 บิตลงทะเบียนในส่วนหัวของคุณ ใช้เวอร์ชันล่าสุดของส่วนหัวจากไลบรารีSTM32CubeF3ที่ไม่มี BSRRL และ BSRRH แต่BSRRลงทะเบียน32 บิตเดียว @Marcus เห็นได้ชัดว่ามีส่วนหัวที่ถูกต้องเพื่อให้รหัสของเขาเข้าถึง 32 บิตเต็มแทนที่จะโหลด halfword และขยายมัน
berendi - ประท้วง

ทำไมการโหลดหนึ่งไบต์ต้องทำตามคำแนะนำพิเศษ? สถาปัตยกรรม ARM นั้นมีLDRBและSTRBอ่าน / เขียนเป็นไบต์ในคำสั่งเดียวไม่ใช่หรือ?
psmears

1
แกน M3 สามารถรองรับแถบบิต (ไม่แน่ใจว่าการใช้งานเฉพาะนี้จะเกิดขึ้น) โดยที่พื้นที่ 1 MB ของพื้นที่หน่วยความจำส่วนต่อพ่วงถูกกำหนดให้เป็นพื้นที่ 32 MB แต่ละบิตมีที่อยู่คำที่ไม่ต่อเนื่อง (ใช้ 0 บิตเท่านั้น) ยังคงช้ากว่าโหลด / ร้านค้าอย่างแน่นอน
Sean Houlihane

8

BSRRและBRRลงทะเบียนสำหรับการตั้งค่าและการตั้งค่าบิตแต่ละพอร์ต:

GPIO พอร์ต bit set / register register (GPIOx_BSRR)

...

(x = A..H) บิต 15: 0

BSy: พอร์ต x set bit y (y = 0..15)

บิตเหล่านี้เป็นแบบเขียนอย่างเดียว การอ่านไปยังบิตเหล่านี้ส่งคืนค่า 0x0000

0: ไม่มีการดำเนินการบน ODRx บิตที่สอดคล้องกัน

1: ตั้งค่าบิต ODRx ที่เกี่ยวข้อง

อย่างที่คุณเห็นการอ่านการลงทะเบียนเหล่านี้จะให้ 0 เสมอดังนั้นรหัสของคุณคืออะไร

GPIOE->BSRRL |= GPIO_BSRR_BS_10;
GPIOE->BRR |= GPIO_BRR_BR_10;

ได้อย่างมีประสิทธิภาพไม่เป็นGPIOE->BRR = 0 | GPIO_BRR_BR_10แต่เพิ่มประสิทธิภาพไม่ทราบว่าเพื่อให้มันสร้างลำดับของLDR, ORR, STRคำแนะนำแทนร้านค้าคนเดียว

คุณสามารถหลีกเลี่ยงการดำเนินการอ่าน - แก้ไข - เขียนที่มีราคาแพงเพียงแค่เขียน

GPIOE->BSRRL = GPIO_BSRR_BS_10;
GPIOE->BRR = GPIO_BRR_BR_10;

คุณอาจได้รับการปรับปรุงเพิ่มเติมโดยจัดแนวลูปไปยังที่อยู่ที่แบ่งให้เท่ากันโดย 8 ลองวางหนึ่งหรือasm("nop");คำแนะนำโหมดก่อนwhile(1)ลูป


1

หากต้องการเพิ่มสิ่งที่ถูกกล่าวถึงที่นี่: แน่นอนกับ Cortex-M แต่ค่อนข้างมากโปรเซสเซอร์ใด ๆ (ด้วยไพพ์ไลน์, แคช, การทำนายสาขาหรือคุณสมบัติอื่น ๆ ) มันเป็นเรื่องง่ายที่จะใช้ลูปที่ง่ายที่สุด:

top:
   subs r0,#1
   bne top

เรียกใช้หลายล้านครั้งตามที่คุณต้องการ แต่สามารถให้ประสิทธิภาพของการวนรอบนั้นแตกต่างกันอย่างมากเพียงแค่สองคำสั่งให้เพิ่ม nops ตรงกลางหากคุณต้องการ มันไม่สำคัญ

การเปลี่ยนการจัดเรียงของลูปสามารถเปลี่ยนแปลงประสิทธิภาพการทำงานได้อย่างมากโดยเฉพาะอย่างยิ่งกับลูปขนาดเล็กแบบนั้นถ้าใช้สองบรรทัดดึงหนึ่งบรรทัดคุณกินค่าใช้จ่ายเพิ่มเติมนั้นบนไมโครคอนโทรลเลอร์เช่นนี้ที่แฟลชช้ากว่า CPU 2 หรือ 3 จากนั้นโดยการเพิ่มเวลานาฬิกาอัตราส่วนจะยิ่งแย่ลง 3 หรือ 4 หรือ 5 มากกว่าการเพิ่มการดึงข้อมูลพิเศษ

คุณอาจจะไม่มีแคช แต่ถ้าคุณมีมันช่วยได้ในบางกรณี แต่มันทำให้คนอื่นเจ็บและ / หรือไม่สร้างความแตกต่าง การคาดคะเนสาขาซึ่งคุณอาจจะหรืออาจไม่มีที่นี่ (อาจจะไม่) สามารถมองเห็นได้ไกลเท่าที่ออกแบบไว้ในท่อดังนั้นแม้ว่าคุณจะเปลี่ยนลูปเป็นแบรนช์ออกและมีสาขาที่ไม่มีเงื่อนไขในตอนท้าย การใช้งาน) สิ่งที่ทำให้คุณประหยัดได้คือนาฬิกาหลาย ๆ อัน (ขนาดของท่อจากที่มันจะดึงไปที่ความลึกของการคาดการณ์) ในการดึงครั้งต่อไปและ / หรือมันไม่ทำการดึงล่วงหน้าในกรณี

โดยการเปลี่ยนการจัดตำแหน่งด้วยความเคารพในการดึงข้อมูลและแคชบรรทัดคุณสามารถส่งผลกระทบต่อการทำนายสาขาหรือไม่ช่วยให้คุณหรือไม่และที่สามารถเห็นได้ในประสิทธิภาพโดยรวมแม้ว่าคุณจะทดสอบเพียงสองคำสั่งหรือสองคนที่มี nops .

มันค่อนข้างเล็กน้อยที่จะทำสิ่งนี้และเมื่อคุณเข้าใจแล้วนำโค้ดที่รวบรวมมาหรือแม้แต่ชุดประกอบที่เขียนด้วยมือคุณจะเห็นว่าประสิทธิภาพการทำงานอาจแตกต่างกันอย่างมากเนื่องจากปัจจัยเหล่านี้เพิ่มหรือบันทึกสองสามร้อยเปอร์เซ็นต์ หนึ่งบรรทัดของรหัส C หนึ่งที่อยู่ในระดับต่ำ

หลังจากเรียนรู้ที่จะใช้การลงทะเบียน BSRR ให้ลองเรียกใช้รหัสของคุณจาก RAM (คัดลอกและกระโดด) แทนการใช้แฟลชที่ควรเพิ่มประสิทธิภาพในการดำเนินการทันที 2 ถึง 3 เท่าโดยไม่ต้องทำอะไรเลย


0

พฤติกรรมนี้คาดหวังจาก MCU นี้หรือไม่

มันเป็นพฤติกรรมของรหัสของคุณ

  1. คุณควรเขียนลงทะเบียน BRR / BSRR ไม่ใช่อ่าน - แก้ไข - เขียนเหมือนตอนนี้

  2. นอกจากนี้คุณยังมีค่าใช้จ่ายวนรอบ เพื่อประสิทธิภาพสูงสุดให้ทำซ้ำการดำเนินการ BRR / BSRR ซ้ำแล้วซ้ำอีก→คัดลอกและวางในลูปหลาย ๆ ครั้งเพื่อให้คุณผ่านรอบการตั้งค่า / รีเซ็ตจำนวนมากก่อนที่จะวนรอบหนึ่งครั้ง

แก้ไข: การทดสอบอย่างรวดเร็วภายใต้ IAR

การอ่านที่เขียนถึง BRR / BSRR นั้นใช้ 6 คำสั่งภายใต้การเพิ่มประสิทธิภาพปานกลางและ 3 คำแนะนำภายใต้การเพิ่มประสิทธิภาพสูงสุด การพลิกดู RMW'ng ใช้เวลา 10 คำสั่ง / 6 คำแนะนำ

ห่วงค่าใช้จ่ายเพิ่มเติม


ด้วยการเปลี่ยน|=ไป=เป็นเฟสเซ็ต / รีเซ็ตบิตเดียวจะใช้เวลา 9 รอบนาฬิกา ( ลิงก์ ) รหัสแอสเซมบลียาว 3 คำแนะนำ:.L5 strh r1, [r3, #24] @ movhi str r2, [r3, #40] b .L5
KR

1
อย่าปลดลูปด้วยตนเอง ที่จริงไม่เคยเป็นความคิดที่ดี โดยเฉพาะอย่างยิ่งในกรณีนี้มันเป็นหายนะ: มันทำให้รูปคลื่นไม่ใช่ระยะ นอกจากนี้การมีรหัสเดียวกันหลายครั้งในแฟลชก็ไม่จำเป็นต้องเร็วขึ้น สิ่งนี้อาจใช้ไม่ได้ที่นี่ (อาจเป็นได้!) แต่การคลายการวนซ้ำเป็นสิ่งที่หลายคนคิดว่าช่วยได้คอมไพเลอร์ ( gcc -funroll-loops) สามารถทำได้ดีมากและเมื่อถูกทารุณกรรม (เช่นที่นี่) มีผลตรงกันข้ามกับสิ่งที่คุณต้องการ
Marcus Müller

การวนซ้ำไม่สิ้นสุดไม่สามารถควบคุมได้อย่างมีประสิทธิภาพเพื่อรักษาพฤติกรรมการกำหนดเวลาที่สอดคล้องกัน
Marcus Müller

1
@ MarcusMüller: บางครั้งลูปที่ไม่มีที่สิ้นสุดสามารถคลี่คลายได้อย่างเป็นประโยชน์ในขณะที่รักษาเวลาที่สอดคล้องกันหากมีจุดใด ๆ ในการวนซ้ำของลูปที่คำสั่งจะไม่มีผลที่มองเห็นได้ ตัวอย่างเช่นหากsomePortLatchควบคุมพอร์ตที่ตั้งค่าบิตต่ำกว่า 4 บิตไว้สำหรับเอาท์พุทอาจเป็นไปได้ที่จะคลี่while(1) { SomePortLatch ^= (ctr++); }โค้ดที่แสดงผล 15 ค่าจากนั้นวนกลับมาเพื่อเริ่มในเวลาที่จะส่งออกค่าเดียวกันสองครั้งในแถว
supercat

Supercat จริง นอกจากนี้เอฟเฟกต์เช่นเวลาของส่วนต่อประสานหน่วยความจำ ฯลฯ อาจทำให้ไม่สามารถเปิดใช้งาน "บางส่วน" ได้ คำแถลงของฉันกว้างเกินไป แต่ฉันรู้สึกว่าคำแนะนำของ Danny นั้นยิ่งใหญ่กว่าและอันตรายมาก
Marcus Müller
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.