क्यों एम्बेडेड सिस्टम डिबगिंग के लिए Printf () खराब है?


16

मुझे लगता है कि एक माइक्रोकंट्रोलर-आधारित परियोजना का उपयोग करके डिबग करने की कोशिश करना एक बुरी बात है printf()

मैं समझ सकता हूं कि आपके पास आउटपुट के लिए कोई पूर्वनिर्धारित जगह नहीं है, और यह मूल्यवान पिन का उपभोग कर सकता है। उसी समय मैंने देखा है कि लोग कस्टम DEBUG_PRINT()मैक्रो के साथ IDE टर्मिनल पर आउटपुट के लिए UART TX पिन का उपभोग करते हैं ।


12
तुमसे किसने कहा कि यह बुरा है? "आमतौर पर सबसे अच्छा नहीं" एक अयोग्य "बुरे" के समान नहीं है।
स्पीहरो पेफेनी

6
यह सब इस बारे में बात करता है कि कितना उपरि है, अगर आपको केवल "मैं यहां हूं" संदेश आउटपुट करने की आवश्यकता है, तो आपको UART को एक स्ट्रिंग भेजने के लिए केवल एक प्रिंटआउट की आवश्यकता नहीं है। इसके अलावा, UART को शुरू करने के लिए कोड शायद 100 बाइट्स कोड के अंतर्गत है। हेक्स मानों के एक जोड़े को आउटपुट करने की क्षमता को जोड़ने से यह सब इतना नहीं बढ़ेगा।
tcrosley

7
@ChetanBhargava - C हेडर फाइलें आमतौर पर निष्पादन योग्य में कोड नहीं जोड़ती हैं। उनमें घोषणाएँ होती हैं; यदि बाकी कोड घोषित की गई चीजों का उपयोग नहीं करता है, तो उन चीजों के लिए कोड लिंक नहीं किया जाता है। यदि आप उपयोग करते हैं printf, तो निश्चित रूप से, लागू करने के लिए आवश्यक सभी कोड printfनिष्पादन योग्य में लिंक हो जाते हैं। लेकिन ऐसा इसलिए है क्योंकि कोड ने इसका उपयोग किया है, हेडर के कारण नहीं।
पीट बेकर

2
@ चेतनभार्गव आपको <stdio.h> को भी शामिल करने की आवश्यकता नहीं है, यदि आप अपनी खुद की सरल दिनचर्या को रोल करते हैं जैसे कि मैंने वर्णित स्ट्रिंग का उत्पादन किया है (UART में आउटपुट वर्ण जब तक आप '\
_

2
@tcrosley मुझे लगता है कि यह सलाह संभवत: यदि आपके पास एक अच्छा आधुनिक संकलक है, तो यदि आप बिना प्रारूप के स्ट्रिंग gcc के साधारण केस में प्रिंटफ का उपयोग करते हैं और अधिकांश अन्य इसे एक अधिक कुशल सरल कॉल के साथ प्रतिस्थापित करते हैं, जो आपके द्वारा बताए गए अनुसार बहुत अधिक होता है।
वैधता

जवाबों:


24

मैं प्रिंटफ () का उपयोग करने के कुछ नुकसानों के साथ आ सकता हूं। ध्यान रखें कि "एम्बेडेड सिस्टम" कुछ सौ बाइट्स प्रोग्राम मेमोरी के साथ पूर्ण-विकसित रैक-माउंट QNX RTOS- चालित सिस्टम के साथ गीगाबाइट्स रैम और नॉनवॉलेटाइल मेमोरी के टेराबाइट्स के साथ हो सकता है।

  • यह डेटा भेजने के लिए कुछ जगह की आवश्यकता है। हो सकता है कि आपके पास सिस्टम पर पहले से ही डिबग या प्रोग्रामिंग पोर्ट हो, शायद आप नहीं। यदि आप ऐसा नहीं करते (या आपके पास जो काम नहीं कर रहा है) यह बहुत उपयोगी नहीं है।

  • यह सभी संदर्भों में एक हल्का कार्य नहीं है। यह एक बड़ी बात हो सकती है अगर आपके पास केवल कुछ K की मेमोरी वाला माइक्रोकंट्रोलर हो, क्योंकि प्रिंटफ में लिंकिंग से 4K खुद-ब-खुद खा सकते हैं। यदि आपके पास 32K या 256K माइक्रोकंट्रोलर है, तो यह संभवतः एक मुद्दा नहीं है, यदि आपके पास एक बड़ा एम्बेडेड सिस्टम है तो अकेले रहने दें।

  • यह स्मृति आवंटन या व्यवधान से संबंधित कुछ प्रकार की समस्याओं को खोजने के लिए बहुत कम या कोई उपयोग नहीं है, और जब बयान शामिल किए जाते हैं या नहीं तो कार्यक्रम के व्यवहार को बदल सकते हैं।

  • यह समय के प्रति संवेदनशील सामान से निपटने के लिए बहुत बेकार है। आप एक लॉजिक एनालाइज़र और एक ऑसीलोस्कोप या एक प्रोटोकॉल एनालाइज़र, या एक सिम्युलेटर के साथ बेहतर होंगे।

  • यदि आपके पास एक बड़ा कार्यक्रम है और आपको कई बार फिर से संकलित करना है क्योंकि आप प्रिंटफ स्टेटमेंट को चारों ओर बदलते हैं और उन्हें बदलते हैं तो आप बहुत समय बर्बाद कर सकते हैं।

यह किसके लिए अच्छा है- यह पूर्वनिर्मित तरीके से डेटा को आउटपुट करने का एक त्वरित तरीका है जिसे हर C प्रोग्रामर जानता है कि कैसे उपयोग किया जाए- शून्य वक्र। यदि आपको कलमन फ़िल्टर के लिए एक मैट्रिक्स को थूकने की आवश्यकता है जिसे आप डिबगिंग कर रहे हैं, तो इसे एक प्रारूप में थूकना अच्छा हो सकता है जो MATLAB में पढ़ सकता है। निश्चित रूप से रैम स्थानों को डिबगर या एमुलेटर में एक बार देखने से बेहतर है। ।

मुझे नहीं लगता कि यह तरकश में एक बेकार तीर है, लेकिन इसे संयम से इस्तेमाल किया जाना चाहिए, साथ ही साथ जीडीबी या अन्य डीबगर्स, एमुलेटर, लॉजिक एनालिसर्स, ऑसिलोस्कोप, स्टेटिक कोड एनालिसिस टूल्स, कोड कवरेज टूल और इसी तरह।


3
अधिकांश printf()कार्यान्वयन थ्रेड-सेफ (यानी, नॉन-री-एंट्रेंट) नहीं हैं, जो एक सौदा हत्यारा नहीं है, लेकिन बहु-थ्रेडेड वातावरण में इसका उपयोग करते समय कुछ ध्यान में रखना है।
JRobert

1
@JRobert एक अच्छा बिंदु लाता है .. और यहां तक ​​कि एक ऑपरेटिंग सिस्टम के बिना एक वातावरण में, ISRs की बहुत उपयोगी प्रत्यक्ष डिबगिंग करना मुश्किल है। बेशक यदि आप ISR में प्रिंटफ () या फ्लोटिंग पॉइंट मैथ कर रहे हैं तो एप्रोच संभवत: बंद है।
स्परोहो फेफेनी

@Jobert मल्टी-थ्रेडेड वातावरण (हार्डवेयर सेटिंग में जहां लॉजिक एनालाइजर और ऑसिलोस्कोप का उपयोग व्यावहारिक नहीं है) में काम करने वाले सॉफ्टवेयर डेवलपर क्या डिबगिंग टूल हैं?
मिन्ह

1
अतीत में मैंने अपना स्वयं का धागा-सुरक्षित प्रिंटफ़ () लुढ़काया है; एक टर्मिनल पर बहुत संक्षिप्त डेटा बाहर थूकने के लिए नंगे पैर डालता है () या पुचर () समकक्ष; एक सरणी में बाइनरी डेटा संग्रहीत किया जाता है जिसे मैंने टेस्ट-रन के बाद डंप किया और व्याख्या की; एक ऑसिलेटोस्कोप के साथ समय मापने के लिए एक एलईडी को ब्लिंक करने के लिए या दालों को उत्पन्न करने के लिए I / O पोर्ट का उपयोग किया गया; डी / ए और वीओएम से मापा गया एक संख्या को थूक दें ... सूची आपकी कल्पना के समान है और आपके बजट के विपरीत है! :)
JRobert

19

कुछ अन्य ठीक जवाबों के अलावा, सीरियल बॉड दरों पर एक पोर्ट पर डेटा भेजने का कार्य आपके लूप समय के संबंध में एकदम धीमा हो सकता है, और आपके कार्यक्रम के कार्यों के शेष तरीके पर प्रभाव पड़ सकता है (जैसा कि किसी भी डिबग के रूप में हो सकता है) प्रक्रिया)।

जैसा कि अन्य लोग आपको बता रहे हैं, इस तकनीक का उपयोग करने के बारे में कुछ भी "बुरा" नहीं है, लेकिन यह कई अन्य डिबग तकनीकों की तरह है, इसकी सीमाएं हैं। जब तक आप जानते हैं और इन सीमाओं से निपट सकते हैं, तब तक यह आपके कोड को सही करने में मदद करने के लिए एक अत्यंत सुविधाजनक खर्च हो सकता है।

एंबेडेड सिस्टम में एक निश्चित अपारदर्शिता होती है, जो सामान्य रूप से, डिबगिंग को एक मुद्दा बना देती है।


8
+1 के लिए "एम्बेडेड सिस्टम में एक निश्चित अपारदर्शिता है"। हालांकि मुझे डर है कि यह कथन केवल उन लोगों द्वारा समझ में आ सकता है जिनके पास एम्बेडेड के साथ काम करने का अच्छा अनुभव है, यह स्थिति का अच्छा, संक्षिप्त सारांश बनाता है। यह वास्तव में "एम्बेडेड" की परिभाषा के करीब है।
njahnke

5

दो मुख्य समस्याएं हैं जिन्हें आप printfमाइक्रोकंट्रोलर पर उपयोग करने की कोशिश करेंगे ।

सबसे पहले, यह आउटपुट को सही पोर्ट पर पाइप करने के लिए दर्द हो सकता है। हर बार नहीं। लेकिन कुछ प्लेटफॉर्म दूसरों की तुलना में अधिक कठिन हैं। कॉन्फ़िगरेशन फ़ाइलों में से कुछ को खराब तरीके से प्रलेखित किया जा सकता है और बहुत सारे प्रयोग आवश्यक हो सकते हैं।

दूसरी है स्मृति। एक पूर्ण विकसित printfपुस्तकालय BIG हो सकता है। कभी-कभी आपको सभी प्रारूप निर्दिष्टकर्ताओं की आवश्यकता नहीं होती है, हालांकि और विशेष संस्करण उपलब्ध हो सकते हैं। उदाहरण के लिए, stdio.h AVR द्वारा प्रदान की गई तीन अलग printf-अलग आकार और कार्यक्षमता है।

चूंकि सभी उल्लिखित सुविधाओं का पूर्ण कार्यान्वयन काफी बड़ा हो जाता है, इसलिए vfprintf()लिंकर विकल्पों का उपयोग करके तीन अलग-अलग स्वादों का चयन किया जा सकता है। डिफ़ॉल्ट vfprintf()फ़्लोटिंग रूपांतरण को छोड़कर सभी उल्लिखित कार्यक्षमता को लागू करता है। का एक न्यूनतम संस्करण vfprintf()उपलब्ध है जो केवल बहुत ही मूल पूर्णांक और स्ट्रिंग रूपांतरण सुविधाओं को लागू करता है, लेकिन #रूपांतरण झंडे का उपयोग करके केवल अतिरिक्त विकल्प को निर्दिष्ट किया जा सकता है (इन झंडों को प्रारूप विनिर्देश से सही ढंग से पार्स किया गया है, लेकिन फिर इसे अनदेखा किया गया है)।

मेरे पास एक उदाहरण था जहां कोई पुस्तकालय उपलब्ध नहीं था और मेरे पास न्यूनतम मेमोरी थी। इसलिए मेरे पास कस्टम मैक्रो का उपयोग करने के अलावा कोई विकल्प नहीं था। लेकिन printfवास्तव में आपकी आवश्यकताओं में से एक का उपयोग करना या न करना एक है।


क्या डाउनवॉटर यह बता सकता है कि मेरे उत्तर में क्या गलत है ताकि मैं भविष्य की परियोजनाओं में अपनी गलती से बच सकूं?
एम्बेडेड।

4

Spehro Pefhany "टाइमिंग-सेंसिटिव स्टफ" के बारे में जो कह रहा था उसे जोड़ने के लिए: आइए एक उदाहरण लेते हैं। मान लीजिए कि आपके पास एक जाइरोस्कोप है जिससे आपका एम्बेडेड सिस्टम प्रति सेकंड 1,000 माप ले रहा है। आप इन मापों को डीबग करना चाहते हैं, इसलिए आपको उन्हें प्रिंट करने की आवश्यकता है। समस्या: इन्हें प्रिंट करने से सिस्टम 1,000 माप प्रति सेकंड पढ़ने में व्यस्त हो जाता है, जिससे जीरोस्कोप का बफर ओवरफ्लो हो जाता है, जिसके कारण भ्रष्ट डेटा को पढ़ा (और मुद्रित) किया जाता है। और इसलिए, डेटा को प्रिंट करके, आपने डेटा को दूषित कर दिया है, जिससे आपको लगता है कि डेटा को पढ़ने में एक बग है जब शायद वहाँ वास्तव में नहीं है। एक तथाकथित हाइजेनबग।


जबरदस्त हंसी! क्या "हेइज़ेनबग" वास्तव में एक तकनीकी शब्द है? मुझे लगता है कि यह कणों की स्थिति और हेइज़ेनबर्ग के सिद्धांत की माप के साथ करना है ...
Zeta.Investigator

3

Printf () के साथ डिबगिंग नहीं करने का बड़ा कारण यह है कि यह आमतौर पर अक्षम, अपर्याप्त और अनावश्यक है।

अक्षम: प्रिंटफ () और परिजन एक छोटे से माइक्रोकंट्रोलर पर उपलब्ध होने के सापेक्ष बहुत सारे फ्लैश और रैम का उपयोग करते हैं, लेकिन वास्तविक डिबगिंग में बड़ी अक्षमता है। जो बदला जा रहा है उसे बदलने के लिए लक्ष्य को पुनः प्राप्त करने और पुन: सक्रिय करने की आवश्यकता होती है, जो प्रक्रिया को धीमा कर देती है। यह एक UART का उपयोग करता है जिसे आप अन्यथा उपयोगी कार्य करने के लिए उपयोग कर सकते हैं।

अपर्याप्त: केवल इतना ही विवरण है कि आप किसी सीरियल लिंक पर आउटपुट कर सकते हैं। यदि प्रोग्राम हैंग हो जाता है, तो आपको ठीक-ठीक पता नहीं है कि, बस अंतिम आउटपुट जो पूरा हुआ।

अनावश्यक: कई माइक्रोकंट्रोलर दूरस्थ रूप से डिबग किए जा सकते हैं। JTAG या मालिकाना प्रोटोकॉल का उपयोग प्रोसेसर को रोकने के लिए, रजिस्टरों और रैम पर झांकने के लिए किया जा सकता है, और यहां तक ​​कि बिना recompile किए चल रहे प्रोसेसर की स्थिति को बदल सकता है। यही कारण है कि डिबगर्स आमतौर पर प्रिंट स्टेटमेंट की तुलना में डिबगिंग का एक बेहतर तरीका है, यहां तक ​​कि पीसी पर भी अंतरिक्ष और शक्ति के टन के साथ।

यह दुर्भाग्यपूर्ण है कि न्यूड्यूड्स के लिए सबसे आम माइक्रोकंट्रोलर प्लेटफॉर्म Arduino में डिबगर नहीं है। AVR दूरस्थ डिबगिंग का समर्थन करता है, लेकिन Atmel का डीबगवाइयर प्रोटोकॉल मालिकाना और अनिर्दिष्ट है। आप GDB के साथ डिबग करने के लिए एक आधिकारिक देव बोर्ड का उपयोग कर सकते हैं, लेकिन यदि आपके पास ऐसा है कि आप शायद Arduino के बारे में बहुत चिंतित नहीं हैं।


क्या आप लॉग पॉइंट के साथ खेलने के लिए फंक्शन पॉइंटर्स का उपयोग नहीं कर सकते, और लचीलेपन का एक पूरा गुच्छा जोड़ सकते हैं?
स्कॉट सीडमैन

3

प्रिंटफ () अपने आप काम नहीं करता है। यह कई अन्य कार्यों को कॉल करता है, और यदि आपके पास बहुत कम स्टैक स्थान है, तो आप इसे अपनी स्टैक सीमा के करीब मुद्दों को डिबग करने के लिए उपयोग करने में सक्षम नहीं हो सकते हैं। संकलक और माइक्रोकंट्रोलर के आधार पर प्रारूप स्ट्रिंग को फ्लैश से संदर्भित करने के बजाय मेमोरी में भी रखा जा सकता है। यदि आप अपने कोड को प्रिंटफ स्टेटमेंट के साथ जोड़ते हैं तो यह काफी बढ़ सकता है। यह Arduino वातावरण में एक बड़ी समस्या है - शुरुआती या सैकड़ों प्रिंटफ बयानों का उपयोग करते हुए अचानक प्रतीत होने वाली यादृच्छिक समस्याओं में चल रहे हैं क्योंकि वे अपने ढेर के साथ अपने ढेर को ओवरराइट कर रहे हैं।


2
हालांकि मैं फीडबैक की सराहना करता हूं जो डाउनवोट स्वयं प्रदान करता है, यह मेरे लिए और दूसरों के लिए अधिक उपयोगी होगा यदि वे असहमत हैं जो इस उत्तर के साथ समस्याओं को समझाते हैं। हम यहाँ सभी को जानने और ज्ञान साझा करने के लिए हैं, अपने को साझा करने पर विचार करें।
एडम डेविस

3

यहां तक ​​कि अगर किसी को लॉगिंग कंसोल के रूप में डेटा को थूकना है, तो printfफ़ंक्शन आमतौर पर ऐसा करने का एक बहुत अच्छा तरीका नहीं है, क्योंकि इसे पारित प्रारूप स्ट्रिंग की जांच करने और इसे रनटाइम पर पार्स करने की आवश्यकता है; यहां तक ​​कि अगर कोड कभी भी किसी प्रारूप प्रारूप को छोड़कर अन्य का उपयोग नहीं करता है %04X, तो नियंत्रक को आम तौर पर उन सभी कोड को शामिल करने की आवश्यकता होगी जो मनमाने प्रारूप के तार को पार्स करने के लिए आवश्यक होंगे। सटीक नियंत्रक जिस पर उपयोग कर रहा है, उसके आधार पर, कोड का उपयोग करना कुछ अधिक कुशल हो सकता है जैसे:

void log_string(const char *st)
{
  int ch;
  do
  {
    ch = *st++;
    if (ch==0) break;
    log_char(ch);
  } while(1);
}
void log_hexdigit(unsigned char d)
{
  d&=15;
  if (d > 9) d+=7;
  log_char(d+'0');
}
void log_hexbyte(unsigned char b)
{ log_hexdigit(b >> 4); log_hexdigit(b); }
void log_hexi16(uint16_t s)
{ log_hexbyte(s >> 8); log_hexbyte(s); }
void log_hexi32(uint32_t i)
{ log_hexbyte(i >> 24); log_hexbyte(i >> 16); log_hexbyte(i >> 8); log_hexbyte(i); }
void log_hexi32p(uint32_t *p) // On a platform where pointers are less than 32 bits
{ log_hexi32(*p); }

कुछ PIC माइक्रोकंट्रोलर्स पर, log_hexi32(l)संभवतः 9 निर्देश ले सकते हैं और 17 ले सकते हैं (यदि lदूसरे बैंक में है), जबकि log_hexi32p(&l)ले जाएगा 2. log_hexi32pफ़ंक्शन स्वयं को लगभग 14 निर्देशों को लंबा लिखा जा सकता है, इसलिए यह स्वयं के लिए भुगतान करेगा यदि दो बार कहा जाता है ।


2

एक बिंदु जिसका अन्य उत्तरों में से किसी ने भी उल्लेख नहीं किया है: एक बुनियादी माइक्रो (IE में केवल मुख्य () लूप है और शायद ISR के एक जोड़े को किसी भी समय चल रहा है, न कि एक बहु-थ्रेडेड ओएस) अगर यह दुर्घटनाग्रस्त हो जाता है / रुक जाता है / हो जाता है एक लूप में फंस गया, आपका प्रिंट फ़ंक्शन बस नहीं होगा

इसके अलावा, लोगों ने कहा है कि "प्रिंटफ का उपयोग न करें" या "stdio.h बहुत अधिक जगह लेता है", लेकिन बहुत अधिक विकल्प नहीं दिए गए हैं - एम्बेडेड.काइल सरलीकृत विकल्पों का उल्लेख करता है, और यह बिल्कुल वैसा ही है जैसा आपको शायद होना चाहिए एक बुनियादी एम्बेडेड प्रणाली पर पाठ्यक्रम की बात के रूप में कर रहा है। UART के कुछ पात्रों को स्क्वीट करने की एक बुनियादी दिनचर्या कोड की कुछ बाइट्स हो सकती है।


यदि आपका प्रिंटफ़ नहीं होता है, तो आपने अपने कोडिस समस्याग्रस्त के बारे में बहुत कुछ सीखा है।
स्कॉट सीडमैन

मान लें कि आपके पास केवल एक प्रिंटफ है जो हो सकता है, हां। लेकिन बीच में आने वाले समय में सैकड़ों बार आग लग सकती है, इसे UART से बाहर निकालने के लिए एक प्रिंटफ () कॉल लगता है
John U
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.