Bagian dari kode pada inti ATmega yang melakukan setup () dan loop () adalah sebagai berikut:
#include <Arduino.h>
int main(void)
{
init();
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
Cukup sederhana, tetapi ada overhead serialEventRun (); di sana.
Mari kita bandingkan dua sketsa sederhana:
void setup()
{
}
volatile uint8_t x;
void loop()
{
x = 1;
}
dan
void setup()
{
}
volatile uint8_t x;
void loop()
{
while(true)
{
x = 1;
}
}
X dan volatile hanya untuk memastikan tidak dioptimalkan.
Di ASM yang diproduksi, Anda mendapatkan hasil yang berbeda:
Anda dapat melihat while (true) hanya melakukan rjmp (lompatan relatif) kembali beberapa instruksi, sedangkan loop () melakukan pengurangan, perbandingan, dan panggilan. Ini adalah 4 instruksi vs 1 instruksi.
Untuk menghasilkan ASM seperti di atas, Anda perlu menggunakan alat yang disebut avr-objdump. Ini termasuk dengan avr-gcc. Lokasi bervariasi tergantung pada OS sehingga paling mudah untuk mencarinya dengan nama.
avr-objdump dapat beroperasi pada file .hex, tetapi ini tidak memiliki sumber asli dan komentar. Jika Anda baru saja membuat kode, Anda akan memiliki file .elf yang memang berisi data ini. Sekali lagi, lokasi file-file ini bervariasi menurut OS - cara termudah untuk menemukannya adalah dengan mengaktifkan kompilasi verbose dalam preferensi dan melihat di mana file output disimpan.
Jalankan perintah sebagai berikut:
avr-objdump -S output.elf> asm.txt
Dan periksa hasilnya dalam editor teks.
main.c
digunakan oleh Arduino IDE. Namun itu tidak berarti bahwa pustaka HardwareSerial disertakan ke sketsa Anda; sebenarnya itu tidak termasuk jika Anda tidak menggunakannya (itu sebabnya adaif (serialEventRun)
dalammain()
fungsi. Jika Anda tidak menggunakan perpustakaan HardwareSerial makaserialEventRun
akan menjadi nol, maka tidak ada panggilan.Jawaban Cybergibbons menggambarkan dengan cukup baik pembuatan kode perakitan dan perbedaan di antara kedua teknik. Ini dimaksudkan sebagai jawaban yang melengkapi melihat masalah dalam hal perbedaan praktis , yaitu berapa banyak perbedaan yang akan dibuat oleh kedua pendekatan dalam hal waktu eksekusi .
Variasi Kode
Saya melakukan analisis yang melibatkan variasi berikut:
void loop()
(yang dimasukkan pada kompilasi)void loop()
(menggunakan__attribute__ ((noinline))
)while(1)
(yang dioptimalkan)while(1)
(dengan menambahkan__asm__ __volatile__("");
. Ini adalahnop
instruksi yang mencegah optimalisasi loop tanpa menghasilkan overheadvolatile
variabel tambahan)void loop()
dengan dioptimalkanwhile(1)
void loop()
dengan tidak-dioptimalkanwhile(1)
Sketsa dapat ditemukan di sini .
Percobaan
Saya menjalankan masing-masing sketsa ini selama 30 detik, sehingga masing-masing mengumpulkan 300 titik data . Ada
delay
panggilan 100 milidetik di setiap loop (tanpanya hal buruk terjadi ).Hasil
Saya kemudian menghitung rata-rata waktu eksekusi dari setiap loop, mengurangi 100 milidetik dari masing-masing dan kemudian merencanakan hasilnya.
http://raw2.github.com/AsheeshR/Arduino-Loop-Analysis/master/Figures/timeplot.png
Kesimpulan
while(1)
Loop yang tidak dioptimalkanvoid loop
lebih cepat daripada kompiler yang dioptimalkanvoid loop
.avr-gcc
dan menggunakan flag optimasi Anda sendiri daripada bergantung pada Arduino IDE untuk membantu Anda dengan itu (jika Anda memerlukan optimasi mikrodetik).CATATAN: Nilai waktu aktual tidak signifikan di sini, perbedaannya adalah. ~ 90 mikrodetik waktu eksekusi mencakup panggilan ke
Serial.println
,micros
dandelay
.CATATAN2: Ini dilakukan dengan menggunakan Arduino IDE dan flag-flag compiler default yang disediakannya .
CATATAN3: Analisis (plot dan perhitungan) dilakukan dengan menggunakan R.
sumber