2011-08-02 10 views
8

का उपयोग करके डिबगिंग लाइब्रेरी मैं यह देखने के लिए लिख रहा हूं कि आपने कभी भी उस विचार के कार्यान्वयन के बारे में देखा है या सुना है जिसे मैं वर्णन करना चाहता हूं।printf() स्ट्रिंग टेबल "डीकोडर रिंग"

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

अक्सर, डिबग बयान कुछ इस प्रकार दिखाई निम्नलिखित:

myDebugLibraryPrintf("Inside loop, processing item %d out of %d.\n", i, numItems); 
बेशक

, जब इस पाठ में विस्तार किया गया है, स्ट्रिंग मुद्रित की तरह "अंदर पाश कुछ, 10 \ से बाहर प्रसंस्करण आइटम 5 एन ", कुल ~ 42 बाइट्स या तो। इस कथन द्वारा मुद्रित 9 0% से अधिक डेटा स्थैतिक, शाब्दिक - संकलित समय पर ज्ञात है। बेशक, संकलन समय पर केवल "5" और "10" ज्ञात नहीं हैं।

मैं जो करना चाहता हूं वह केवल उन दो पूर्णांक (42 के बजाय 8 बाइट्स) भेजने में सक्षम हो सकता है। एक बार मुझे वह डेटा प्राप्त हो जाने के बाद, मेरे पास कुछ प्रकार की "डिकोडर रिंग" होगी जो मुझे प्राप्त डेटा को "पुन: स्थापित" करने और मेरे स्थान पर पूर्ण डीबग संदेश प्रिंट करने देती है।

मैं स्वचालित रूप से (बिल्ड प्रक्रिया के हिस्से के रूप में) "डिकोडर रिंग" उत्पन्न करता हूं, प्रत्येक myDebugLibraryPrintf() कथन समय पर एक अद्वितीय आईडी देता है, और एक तालिका उत्पन्न करता है जो उन अद्वितीय आईडी को मूल स्वरूप तारों पर मानचित्रित करता है । फिर, किसी भी समय myDebugLibraryPrintf() को लक्ष्य पर बुलाया जाता है, यह अद्वितीय आईडी और "%d", "%f", आदि प्रारूप प्रारूप में दिखाई देने वाले varargs मानों को प्रसारित करता है, लेकिन प्रारूप स्ट्रिंग स्वयं प्रसारित नहीं होती है। (शायद मैं अभी "%s" आइटमों को अभी अस्वीकार कर दूंगा ...) मेरे स्थान पर वापस, हमारे पास एक प्रोग्राम होगा जो तालिका में अद्वितीय आईडी देखता है, उचित प्रारूप स्ट्रिंग पाता है, और मूल डीबग को पुनर्निर्माण के लिए इसका उपयोग करता है संदेश।

मुझे लगता है कि किसी के पास शायद यह विचार था और मुझे लगता है कि समुदाय में किसी ने ऐसा कुछ देखा होगा (या यहां तक ​​कि एक ओपन-सोर्स लाइब्रेरी के बारे में भी पता है)।

प्रतिबंध:

  • स्पष्ट करने के लिए, मैं ++ यहां सी/सी के साथ काम कर रहा हूँ, और मैं printf की एक 100% -Complete प्रतिस्थापन कार्यान्वयन में कोई दिलचस्पी नहीं है() - गैर तरह बातें शाब्दिक प्रारूप तार, %s (स्ट्रिंग) प्रारूप विनिर्देशक, या %*.*d के साथ varargs सूची में चौड़ाई या परिशुद्धता डालने जैसे अधिक उन्नत प्रारूप विनिर्देशकों को समर्थित होने की आवश्यकता नहीं है।

  • मैं चाहता हूं कि निर्माण प्रक्रिया के हिस्से के रूप में स्ट्रिंग तालिका स्वचालित रूप से जेनरेट की जाए ताकि डीबग जोड़ने से पारंपरिक printf() जोड़ने से कोई और काम न हो। यदि न्यूनतम प्रयास की आवश्यकता से अधिक कोई भी आवश्यक है, तो मेरी परियोजना पर कोई भी इसका उपयोग नहीं करेगा।

  • स्ट्रिंग तालिका उत्पन्न करने के लिए निर्माण प्रक्रिया के हिस्से के रूप में अतिरिक्त कार्य करना काफी अधिक माना जाता है। सौभाग्य से, मेरे पास इस स्रोत का उपयोग करने में रुचि रखने वाले सभी स्रोत कोड का नियंत्रण है, और मेरे पास निर्माण प्रक्रिया के भीतर बहुत लचीलापन है।

धन्यवाद!

+2

क्या आप प्रस्तावित नहीं किए हों डेटा संपीड़न का एक सरल रूप है। आप शायद अपने आप को बहुत समय और प्रयास बचा सकते हैं, और अभी भी लाभ के 90 +% प्राप्त कर सकते हैं, बस अपने प्रोग्राम के डीबग आउटपुट को लिंक पर भेजने से पहले gzip के माध्यम से फ़िल्टर करके, और दूसरी तरफ गनज़िप के माध्यम से इसे फ़िल्टर करके। gzip/gunzip स्वचालित रूप से प्रतीक तालिकाओं का निर्माण करेगा और आपके प्रोग्राम के आउटपुट को बाधित किए बिना मैन्युअल टोकनिंग योजना के तरीके के बिना आपके लिए संपीड़न करेगा। –

+0

क्या यह सी या सी ++ है? (टैग संपादक असहमत प्रतीत होते हैं) – AShelly

+0

@ जेरेमी फ्राइज़नर: सहकर्मियों के साथ मेरी चर्चाओं में, संपीड़न एक विकल्प के रूप में भी आया है, और ऐसा लगता है कि यह एक अच्छा विकल्प हो सकता है - हालांकि, ऐसा लगता है कि यह एक खिंचाव जैसा लगता है। इससे तुलनात्मक लाभ मिलता है। उदाहरण में मैंने दिया, मैं 8 बाइट्स में 42 बाइट्स लायक जानकारी प्रभावी ढंग से भेजने में सक्षम था - 80% की एक स्पेस बचत। क्या इस तरह के डेटा पर वास्तव में 80% की स्पेस बचत हासिल कर सकते हैं? (मुझे पता लगाने के लिए एक प्रयोग करने की ज़रूरत है।) बेशक, अगर gzip एक ही बचत प्राप्त नहीं कर पाता है, तो भी मैं कम जटिलता के नाम पर सापेक्ष अक्षमता को स्वीकार करने के इच्छुक हो सकता हूं। – jeremytrimble

उत्तर

3

मैंने केवल इस विचार को स्ट्रिंग के प्री-डिफ़ाइंड सेट के साथ लागू किया है। कोड debug_print(INSIDE_LOOP_MSG_ID, i, n) जैसा दिखेगा।जब डेवलपर नए संदेश जोड़ना चाहते थे तो उन्हें एक नया हेडर फ़ाइल में नया टेक्स्ट रखना होगा और इसे एक नया आईडी देना होगा।

मुझे लगता है कि एक सामान्य दिखने प्रिंट बयान से मक्खी पर यह पैदा करने का विचार एक दिलचस्प चुनौती है। मैं किसी भी मौजूदा कार्यान्वयन में नहीं आया है।

एक विचार है जो एक hash value at compile time में पहली स्ट्रिंग तर्क बदल जाता है किसी मैक्रो/टेम्पलेट हो सकता है। तो डेवलपर debug_print("test %d",i) लिखता है, जो debug_port_send(0x1d3s, i) पर संकलित हो जाता है। प्राप्त करने वाले पक्ष पर उपयोग के लिए तारों और हैंश निकालने के लिए एक पोस्ट प्रोसेसिंग स्क्रिप्ट लिखना सरल होना चाहिए। (हैश टकराव को हल करने का सबसे आसान तरीका त्रुटि संदेश देना होगा और उपयोगकर्ता को थोड़ा सा शब्द बदलने के लिए मजबूर करना होगा)।

संपादित करें:
तो मैं ऊपर के लिंक पर संकलन समय हैश के साथ इस की कोशिश की।

#define QQuot_(x) #x 
#define QQuote(x) QQuot_(x) 
#define Debug_Print(s, v) (Send(CONSTHASH(QQuote(__LINE__)##s), *((long*)&(v)))) 

void Send(long hash, long value) 
{ 
    printf("Sending %x %x\n", hash, value); //replace with COMMS 
} 


int main() 
{ 
    int i = 1; 
    float f= 3.14f; 
    Debug_Print("This is a test %d", i); 
    i++; 
    Debug_Print("This is a test %d", i); 
    Debug_Print("This was test %f", f); 
} 

थोड़ी अधिक चतुरता के साथ आप कई तर्कों का समर्थन कर सकते हैं। विच्छेदन की जांच से पता चलता है कि सभी हैंश वास्तव में संकलन समय पर गणना की जाती हैं। आउटपुट की अपेक्षा की जाती है, समान तारों से कोई टकराव नहीं होता है। (This page की पुष्टि करता है हेक्स 3.14 के लिए सही है):

Sending 94b7555c 1 
Sending 62fce13e 2 
Sending 506e9a0c 4048f5c3 

तुम सब अब जरूरत है कि कोड है जो Debug_Print से तार निष्कर्षों पर चलाया जा सकता एक पाठ-प्रसंस्करण स्क्रिप्ट है, हैश की गणना करता है और एक मेज अपने भरता है रिसीवर पक्ष रेसीवर को Send कॉल से हैश वैल्यू मिलता है, जो उस स्ट्रिंग को देखता है जो उसके साथ जाता है, और एक सामान्य प्रिंटफ कॉल पर तर्क के साथ पास करता है।

समस्या सिर्फ मैं देख रहा हूँ कि संकलन समय हैश में नेस्टेड मैक्रो confusing my refactoring plug-in and killing my IDE responsiveness हो रहा है। एड-इन को अक्षम करने से उस समस्या को हटा दिया गया।

+2

मैं '__FILE__' और' __LINE__' के आधार पर अद्वितीय आईडी बनाने के बारे में सोच रहा था जिस पर printf() को कॉल किया गया था। चूंकि मेरे पास ब्याज के सभी स्रोत कोड हैं, इसलिए प्रत्येक स्रोत फ़ाइल (या तो स्वचालित रूप से या स्पष्ट रूप से) के लिए एक अलग संख्या असाइन करना मुश्किल नहीं होगा और फिर 'अद्वितीय आईडी = (fileId < <14) | lineNum', लेकिन आपके हैशिंग विचार वास्तव में मुझे 16-बिट अद्वितीय आईडी से दूर जाने दे सकते हैं, खासकर अगर मैं हैश कुंजी के हिस्से के रूप में फ़ाइल और लाइन शामिल करता हूं और [gperf] का उपयोग करता हूं (http://www.gnu.org/s/gperf /) हैश फ़ंक्शन उत्पन्न करने के लिए। – jeremytrimble

+0

मैं स्ट्रिंग टेबल में अनुक्रमण के लिए लंबे नाम स्थिरांक को परिभाषित करता हूं। तो अगर स्ट्रिंग "% d से बाहर अंदर पाश, प्रसंस्करण आइटम% d। \ N" है मैं एक पहचानकर्ता Inside_loop_processing_item_d_out_of_d का प्रयोग करेंगे (= एक स्ट्रिंग तालिका में इंडेक्स) यह आप एक बहुत की अनुमति देता है पठनीय डीबग कथन और साथ ही, मैक्रोज़/संकलन समय हैशिंग पर जाने से बचें। उम्मीद है कि, अधिकांश प्रिंट स्टेटमेंट्स के लिए आप प्रतीक लंबाई पर सीमाएं नहीं मारेंगे। प्रतीक तालिका मैन्युअल रूप से निर्माण की आवश्यकता होगी। – ritesh

+0

क्या यह बाधा # 2 का उल्लंघन नहीं करता है? "पारंपरिक printf() को जोड़ने से कोई और काम नहीं।" – AShelly

1

मैं कुछ है कि एआरएम मंच पर कुछ इसी तरह पूरा करता देखा है। मेरा मानना ​​है कि इसे "Embedded Trace Macrocell" कहा जाता है। मैक्रोज़ की एक श्रृंखला ईटीएम रजिस्टरों में दो रजिस्टर लिखने के लिए TRACE_POWER_SYSTEM_VOLTAGE_REGULATOR_TRIGGER(inputX); जैसे बयान का अनुवाद करती है। ध्यान दें कि यह केवल 16 बिट, 32 बिट और 64 बिट पूर्णांक को तर्क के रूप में स्वीकार करता है।

हम एआरएम उपकरणों का उपयोग इन (टाइमस्टैंप) बफ़र्स को निकालने के लिए कर सकते हैं। फिर हम प्रवंचना पहले (इंडेक्स) में परिवर्तित करने का एक पूर्व संकलित सा लागू रजिस्टर कोई आउटपुट फ़ाइल है कि इस तरह दिखता है में लिखें:

तो
timestamp | POWER SYSTEM | VOLTAGE REGULATOR TRIGGER | 0x2380FF23 

कोड तर्क के डेटा प्रकार निर्धारित करने के लिए जांच की गयी है, हमें परेशान करने की ज़रूरत नहीं है। इसे "वास्तविक समय" टाइमस्टैम्प (पावरअप के बाद से एमएस के बजाय), और ट्रेस स्टेटमेंट की फ़ाइल और लाइन संख्याओं के साथ भी एनोटेट किया जा सकता है।

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

ध्यान दें कि ट्रेस का विश्लेषण करते समय यह बेहद महत्वपूर्ण है कि आप केवल 'डीकोड' फ़ाइल का उपयोग करते हैं जो डिवाइस पर चल रहे कोड के विशेष संस्करण से मेल खाता है।

+0

यह भी एक उपयोगी विचार है - मैं जो कल्पना कर रहा था वह काफी नहीं था, लेकिन फिर भी दिलचस्प है। यह ईटीएम चीज मुझे [http://www.mc.com/products/software/tatl/]("Trace विश्लेषण उपकरण और लाइब्रेरी ") की याद दिलाती है (" TATL "- ज़ेल्डा से कोई संबंध नहीं) मैंने उपयोग किया है अतीत में पीपीसी, लेकिन हैरवेयर समर्थन (हमेशा ठंडा) के माध्यम से तेजी से। आपने अपनी अंतिम वाक्य में एक महत्वपूर्ण रखरखाव समस्या को छुआ - इस से निपटने के लिए मैं स्ट्रिंग टेबल के विभिन्न संस्करणों को किसी प्रकार के (क्रिप्टोग्राफिक) हस्ताक्षर के माध्यम से ट्रैक करने और एम्बेडेड लक्ष्य रिपोर्ट तालिका के हस्ताक्षर के बारे में सोच रहा था बूटअप पर प्रयोग कर रहा है। – jeremytrimble

0

मैं अंतर्राष्ट्रीयकरण के प्रयोजन के लिए स्ट्रिंग शाब्दिक निकालने के लिए कई उपकरण को याद करने लगते हैं। जीएनयू तार सीधे निष्पादन योग्य से स्ट्रिंग निकाल सकते हैं। यह कार्य के हिस्से के साथ मदद करनी चाहिए।

0

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

मुझे आशा है कि नमूना psaudo-कोड विचार स्पष्ट करने में मदद करेगा:

/* target code */ 
#define PRINT(format,...) send(__FILE__,__LINE__,__VA_ARGS__) 
... 

/* host code (c++) */ 
void PrintComm(istream& in) 
{ 
    string fileName; 
    int line,nParams; 
    int* params; 
    in>>fileName>>line>>nParams; 
    if (nParams>0) 
    { 
     params = new int[nParams]; 
     for (int i=0; i<nParams; ++i) 
      in>>params[i]; 
    } 
    const char* format = FindFormat(fileName,line); 
    ... 
    delete[] params; 
}