שְׁאֵלָה:
האם לולאה אינסופית בתוך לולאה () תופיע מהר יותר?
Peter Bloomfield
2014-02-21 21:36:19 UTC
view on stackexchange narkive permalink

כשאתה כותב סקיצה טיפוסית, אתה בדרך כלל סומך על ש- loop () נקרא שוב ושוב כל עוד הארדואינו פועל. מעבר פנימה והחוצה מהפונקציה loop () חייב להציג תקורה קטנה.

כדי להימנע מכך, ככל הנראה תוכל ליצור לולאה אינסופית משלך, כך:

  void loop () {while (true) {// do stuff ...}}  

האם זו דרך קיימא לשיפור הביצועים? האם זה יגרום לבעיות אחרות אם loop () לעולם לא יחזור?

שתיים תשובות:
#1
+18
Cybergibbons
2014-02-21 22:43:46 UTC
view on stackexchange narkive permalink

החלק של הקוד בליבת ATmega שעושה הגדרה () ולולאה () הוא למטה:

  #include <Arduino.h>int main (void) {init (); # אם הוגדר (USBCON) USBDevice.attach (); הגדרת # endif (); עבור (;;) {לולאה (); אם (serialEventRun) serialEventRun (); } להחזיר 0;}  

די פשוט, אבל יש תקורה של serialEventRun (); שם.

בואו נשווה שתי שרטוטים פשוטים:

  התקנת חלל () {} uint8_t נדיף x; loop loop () {x = 1;}  

ו

  הגדרת חלל () {} נדיף uint8_t x; loop loop () {while (true) {x = 1; }}  

ה- x והנדיפים הם רק כדי להבטיח שהוא לא ייעלם.

ב- ASM המיוצר, אתה מקבל תוצאות שונות: Comparison of two

אתה יכול לראות את הזמן (נכון) פשוט מבצע rjmp (קפיצה יחסית) אחורה כמה הוראות, ואילו לולאה () מבצעת חיסור, השוואה ושיחה. זהו 4 הוראות לעומת הוראות 1.

כדי ליצור ASM כנ"ל, עליך להשתמש בכלי שנקרא avr-objdump. זה כלול עם avr-gcc. המיקום משתנה בהתאם למערכת ההפעלה כך שהכי קל לחפש אותו לפי השם.

avr-objdump יכול לפעול על קבצי .hex, אך אלה חסרים את המקור ואת התגובות המקוריות. אם רק בנית קוד, יהיה לך קובץ .elf המכיל נתונים אלה. שוב, המיקום של קבצים אלה משתנה לפי מערכת ההפעלה - הדרך הקלה ביותר לאתר אותם היא להפעיל אוסף מילולית בהעדפות ולראות היכן מאוחסנים קבצי הפלט.

הפעל את הפקודה באופן הבא:

avr-objdump -S output.elf> asm.txt

ובחן את הפלט בעורך טקסט.

בסדר, אך אין סיבה להתקשר לפונקציה serialEventRun ()? לשם מה זה?
זה חלק מהפונקציונליות המשמשת HardwareSerial, לא בטוח מדוע היא לא מוציאה כאשר אין צורך בסידורי.
יעזור להסביר בקצרה כיצד יצרת את פלט ה- ASM כדי שאנשים יוכלו לבדוק את עצמם.
@Cybergibbons זה אף פעם לא הוצא כי זה חלק מ- main.c סטנדרטי המשמש את Arduino IDE. עם זאת זה לא אומר שספריית HardwareSerial כלולה לשרטוט שלך; למעשה זה לא נכלל אם אתה לא משתמש בו (לכן יש `אם (serialEventRun)` בפונקציה `main ()`. אם אתה לא משתמש בספריית HardwareSerial אז 'serialEventRun' יהיה אפס, ומכאן שום שיחה .
עם זאת ספריית HardwareSerial תכלול ככל הנראה (מישהו יכול לאשר זאת?) אם אתה משתמש בכמה פונקציות של ארדואינו כמו 'Serial.print ()'. במצב זה, מה יכול לקרות אם הלולאה () שלך תיפתח לנצח ובכך לעולם לא תקרא 'serialEventRun ()'? אני חושש שסידורי אולי לא יעבוד במקרה הזה.
כן, זה חלק מה- main.c כפי שצוטט, אבל הייתי מצפה שהוא יהיה ממוטב אם לא נדרש ולכן אני חושב שהיבטים של Serial כלולים תמיד. לעתים קרובות אני כותב קוד שלעולם לא יחזור מ- loop () ולא שם לב לבעיות בנושא Serial.
@Cybergibbons, `serialEventRun ()` קורא ל- 'serialEvent ()' עבור היציאות הטוריות השונות. כברירת מחדל, כל אלה הם [נהלים ריקים] (https://github.com/arduino/Arduino/blob/master/hardware/arduino/cores/arduino/HardwareSerial.cpp), אך המשתמשים יכולים [לבטל אותם] ] (http://arduino.cc/en/Tutorial/SerialEvent) לעשות משהו שימושי אם תרצה בכך. אם אתה לא עוקף את זה, אין צורך לקרוא לזה.
#2
+6
asheeshr
2014-02-22 14:11:34 UTC
view on stackexchange narkive permalink

התשובה של Cybergibbons מתארת ​​יפה מאוד את יצירת קוד ההרכבה ואת ההבדלים בין שתי הטכניקות. זו נועדה להיות תשובה משלימה המתבוננת בנושא במונחים של הבדלים מעשיים כלומר, מה ההבדל שתשתי הגישה מבחינת זמן הביצוע . p>


וריאציות קוד

ערכתי ניתוח שכלל את הווריאציות הבאות:

  • לולאה בסיסית ) (שמוטבע על הידור)
  • loop loop () לא מוטמע (באמצעות __attribute__ ((noinline)) )
  • לולאה עם תוך (1) (שמתבצע אופטימיזציה)
  • לולאה עם לא אופטימיזציה> בעוד (1) (על ידי הוספת __asm__ __volatile __ (""); . זו הוראות nop המונעות אופטימיזציה של הלולאה מבלי לגרום לתקורות נוספות של משתנה נדיף )
  • לולאה בטל (קוד) לא מוטבעת () עם אופטימיזציה בזמן (1 )
  • בטל לא מוטבע לולאה () עם לא מותאם תוך (1 )

הסקיצות יכולות להיות מעוקבות d כאן.

ניסוי

הריצתי כל אחד מהשרטוטים האלה למשך 30 שניות, ובכך צברתי 300 נקודות נתונים כל אחד. התקיימה שיחת עיכוב 100 אלפיות שנייה בכל לולאה (שבלעדיה דברים רעים קורים).

תוצאות

לאחר מכן חישבתי את זמני הביצוע הממוצעים של כל לולאה, גרעתי 100 אלפיות השנייה מכל אחת מהן ואז זממתי את התוצאות.

http://raw2.github.com/AsheeshR/Arduino-Loop-Analysis/master/Figures/timeplot.png

מסקנה

  • שאינו מותאם תוך לולאה (1) בתוך loop loop = מהיר יותר מ loop loop = אופטימיזציה של מהדר .
  • הפרש הזמן בין הקוד הלא מותאם לקוד ברירת המחדל המותאם לארדואינו אינו משמעותי למעשה . יהיה לך טוב יותר להתקבץ ידנית באמצעות avr-gcc ולהשתמש בדגלים אופטימיזציה משלך ולא תלוי ב- IDE של Arduino כדי לעזור לך בזה (אם אתה זקוק לאופטימיזציה של מיקרו שניות).

הערה: לערכי הזמן בפועל אין משמעות כאן, ההבדל ביניהם הוא. זמן הביצוע של ~ 90 מיקרו שניות כולל קריאה ל Serial.println , micros ו- Delay .

הערה 2: זה נעשה באמצעות ה- Arduino IDE ודגלי המהדר המוגדרים כברירת מחדל שהוא מספק. sub>

NOTE3: ניתוח חזק (עלילה וחישובים) נעשה באמצעות R.

עבודה טובה. לגרף יש אלפיות השנייה ולא מיקרו שניות אבל לא נושא ענק.
@Cybergibbons זה די לא סביר מכיוון שכל המדידות הן במיקרו-שניות ואני לא שיניתי סולמות בכל מקום :)


שאלה ותשובה זו תורגמה אוטומטית מהשפה האנגלית.התוכן המקורי זמין ב- stackexchange, ואנו מודים לו על רישיון cc by-sa 3.0 עליו הוא מופץ.
Loading...