2012-07-06 19 views
11

मैं जानना चाहता हूं कि मेरे एप्लिकेशन आंतरिकों की निगरानी करने का एक अच्छा तरीका है, आदर्श रूप से मौजूदा पुस्तकालय के रूप में।कुशल सी ++ रनटाइम आंकड़े कैसे लागू करें

मेरा आवेदन भारी बहुप्रचारित है, और धागे और बाहरी दुनिया के बीच संवाद करने के लिए एक संदेश प्रणाली का उपयोग करता है। मेरा लक्ष्य यह निगरानी करना है कि किस प्रकार के संदेश भेजे जाते हैं, जिस पर आवृत्ति, आदि

अन्य सामान्य आंकड़ों में भी अन्य आंकड़े भी हो सकते हैं, जैसे हर मिनट कितने धागे पैदा होते हैं, कितना नया/हटाना कहा जाता है , या आवेदन के अधिक विशिष्ट पहलुओं; जो तुम कहो।

Google क्रोम के लिए आपके "आंतरिक पृष्ठ" जैसे net या क्रोम: // ट्रेसिंग जैसे कुछ शानदार होगा, लेकिन कमांड लाइन फैशन में।

यदि ऐसी लाइब्रेरी है जो मेरे ऐप की विशिष्टताओं के लिए पर्याप्त सामान्य है, तो यह बहुत अच्छा होगा।
अन्यथा मैं नौकरी करने वाली छोटी कक्षा को लागू करने के लिए तैयार हूं, लेकिन मुझे नहीं पता कि कहां से शुरू करना है। मुझे लगता है कि सबसे महत्वपूर्ण बात यह है कि कोड को ज्यादा हस्तक्षेप नहीं करना चाहिए, ताकि प्रदर्शन प्रभावित न हों।

क्या आपके पास इस मामले पर कुछ पॉइंटर्स हैं?

संपादित करें: अपने आवेदन लिनक्स पर चलता है, एक एम्बेडेड वातावरण में, उदासी वेलग्रिंड :(द्वारा समर्थित नहीं

+0

gprof समर्थित किया जाएगा? जीसीसी संकलक पर -जीपी? – pyCthon

+0

हाँ, यह एक चीज है जो हमारे पास है। यद्यपि मेरी समस्या एक ऐसे कार्यक्रम के लिए होगी जो बहुत लंबे समय तक चल रही है (एक सेवा), इसलिए आंकड़े रनटाइम में पहुंच योग्य होना चाहिए :-) – Gui13

+1

बहुत बुरा आप एक और टैग, "एम्बेडेड" नहीं जोड़ सके। –

उत्तर

3

मैं सुझाव है कि अपने कोड में, आप काउंटरों कि वृद्धि हो बनाए रखने के काउंटर static वर्ग के सदस्यों हो सकता है। या वैश्विक। आप अपने काउंटर परिभाषित करने के लिए एक वर्ग का उपयोग करते हैं, तो आप निर्माता एक नाम के साथ एक भी भंडार के साथ अपने काउंटर रजिस्टर, आपको क्वेरी करने और भंडार परामर्श करके अपने काउंटर रीसेट कर सकते हैं हो सकता है। तो फिर।

struct Counter { 
    unsigned long c_; 
    unsigned long operator++() { return ++c_; } 
    operator unsigned long() const { return c_; } 
    void reset() { unsigned long c = c_; ATOMIC_DECREMENT(c_, c); } 
    Counter (std::string name); 
}; 

struct CounterAtomic : public Counter { 
    unsigned long operator++() { return ATOMIC_INCREMENT(c_, 1); } 
    CounterAtomic (std::string name) : Counter(name) {} 
}; 

ATOMIC_INCREMENT वृद्धि के लिए एक मंच विशिष्ट तंत्र होगा परमाणु काउंटर। इस उद्देश्य के लिए जीसीसी एक अंतर्निहित __sync_add_and_fetch प्रदान करता है। ATOMIC_DECREMENT समान है, जीसीसी निर्मित __sync_sub_and_fetch के साथ।

struct CounterRepository { 
    typedef std::map<std::string, Counter *> MapType; 
    mutable Mutex lock_; 
    MapType map_; 
    void add (std::string n, Counter &c) { 
     ScopedLock<Mutex> sl(lock_); 
     if (map_.find(n) != map_.end()) throw n; 
     map_[n] = &c; 
    } 
    Counter & get (std::string n) const { 
     ScopedLock<Mutex> sl(lock_); 
     MapType::const_iterator i = map_.find(n); 
     if (i == map_.end()) throw n; 
     return *(i->second); 
    } 
}; 

CounterRepository counterRepository; 

Counter::Counter (std::string name) { 
    counterRepository.add(name, *this); 
} 

क्या आप जानते हैं एक ही काउंटर से अधिक धागा द्वारा बढ़ा दी जाएगा, तो CounterAtomic का उपयोग करें। काउंटर के लिए जो थ्रेड के लिए विशिष्ट हैं, केवल Counter का उपयोग करें।

+0

यह एक अच्छी शुरुआत आईएमओ है, जो वाल्ग्रिंड सुझाव से बेहतर है क्योंकि यह 'उल्लंघन का उल्लंघन करेगा ..' आवश्यकता का उल्लंघन करेगा। क्या इस हिरण पोंछने का पता मल्टी-थ्रेडेड पहलू है, incrementing/काउंटरों जरूरी परमाणु नहीं रीसेट करने ... मैं धागे की निजी चर में इनमें से कुछ को बनाए रखने के बारे में सोचते हैं ... – nhed

+0

@nhed: मुझे ओपी के मीट्रिक टन के बारे में याद दिलाने के लिए धन्यवाद आवश्यकताओं। मैंने परमाणु परिचालन के साथ जवाब अद्यतन किया। – jxh

+0

यह एक शानदार जवाब है। मैं उस चीज़ को आजमाउंगा और देखता हूं कि यह कैसा चल रहा है। '__sync _ * _ और_fetch' के लिए भी धन्यवाद, मुझे इसके बारे में पता नहीं था और मैंने कुछ म्यूटेक्स का उपयोग किया था! – Gui13

0

valgrind/callgrind पर एक नज़र डालें।

इसका उपयोग प्रोफाइलिंग के लिए किया जा सकता है, जो मैं समझता हूं कि आप जो खोज रहे हैं। मुझे नहीं लगता कि यह रनटाइम पर काम करता है, लेकिन यह आपकी प्रक्रिया समाप्त होने के बाद उत्पन्न हो सकता है।

+0

@ Gui13: क्या आप संकलन-समय के आंकड़ों की तलाश में हैं, जैसे वाल्ग्रिंड प्रदान कर सकता है? या आप रन-टाइम आंकड़ों की तलाश में हैं, जैसे उपयोगकर्ता ने पॉप-अप बतख पर कितनी बार क्लिक किया था? –

+0

अफसोस की बात है, मेरा ऐप एक एम्बेडेड प्लेटफॉर्म पर चलता है जो वालग्रिंड द्वारा समर्थित नहीं है। – Gui13

3

मैं इकट्ठा करता हूं कि आप रन-टाइम आंकड़ों को इकट्ठा करने की कोशिश कर रहे हैं - जैसे कि आपने कितने बाइट भेजे हैं, आप कब तक चल रहे हैं, और कितनी बार उपयोगकर्ता ने एक विशेष कार्य सक्रिय किया है।

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

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

मुख्य धागा उपयोगकर्ता अनुरोध पर इस RequestProgress संदेश भेजता है (जैसे जब वे S कुंजी दबाते हैं), या एक समय अंतराल पर। यदि एक समय अंतराल मैं क्या कर रहा हूं, तो मैं आम तौर पर एक और नया "दिल की धड़कन" धागा लागू करूंगा। यह सब थ्रेड Sleep() निर्दिष्ट समय के लिए है, फिर मुख्य थ्रेड पर Heartbeat संदेश भेजें। बदले में मुख्य धागा इस Heartbeat संदेश पर RequestProgress संदेश भेजकर प्रत्येक कार्यकर्ता धागे को आंकड़ों से एकत्रित किया जाता है।

आंकड़ों को इकट्ठा करने का कार्य ऐसा लगता है कि यह काफी सरल होना चाहिए। तो इतनी जटिल व्यवस्था क्यों? जवाब दो गुना है।

सबसे पहले, कार्यकर्ता धागे का काम करना है, और उपयोग आंकड़ों की गणना करना यह नहीं है। अपने मुख्य उद्देश्य के लिए दूसरी जिम्मेदारी ऑर्थोगनल को लेने के लिए इन धागे को दोबारा करने की कोशिश करना एक गोल छेद में एक वर्ग चरम को जाम करने की कोशिश करने जैसा है। वे ऐसा करने के लिए नहीं बनाए गए थे, इसलिए कोड लिखे जाने का विरोध करेगा।

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

1

साझा स्मृति उपयोग करते हैं करने के लिए भेजने के साथ सिर्फ इतना है कि आप उपलब्ध हैं)। अपनी सरणी परिभाषा में स्मृति के कच्चे ब्लॉक को कास्ट करके वहां अस्थिर हस्ताक्षर किए गए 32- या 64-बिट पूर्णांक (यानी आप अपने प्लेटफ़ॉर्म पर परमाणु रूप से वृद्धि कर सकते हैं) की एक निश्चित लंबाई सरणी रखें। ध्यान दें कि अस्थिरता आपको परमाणु नहीं बनाती है; यह संकलक अनुकूलन को रोकता है जो आपके आंकड़े मानों को मिटा सकता है। जीसीसी के __sync_add_and_fetch() या नए सी ++ 11 परमाणु <> प्रकारों जैसे इंट्रिनिक्स का उपयोग करें।

फिर आप एक छोटा प्रोग्राम लिख सकते हैं जो साझा स्मृति के उसी ब्लॉक से जुड़ा होता है और एक या सभी आंकड़ों को प्रिंट कर सकता है। यह छोटे आंकड़े पाठक कार्यक्रम और आपको मुख्य कार्यक्रम को एक सामान्य हेडर फ़ाइल साझा करना होगा जो सरणी में प्रत्येक स्टेट की स्थिति को लागू करता है।

यहां स्पष्ट दोष यह है कि आप निश्चित संख्या में काउंटर के साथ फंस गए हैं। लेकिन प्रदर्शन के अनुसार, हरा करना मुश्किल है। प्रभाव आपके कार्यक्रम में विभिन्न बिंदुओं पर एक पूर्णांक की परमाणु वृद्धि है।

1

एम्बेडेड सिस्टम में, एक आम तकनीक "लॉग" के लिए स्मृति के ब्लॉक को आरक्षित करना और गोलाकार कतार की तरह व्यवहार करना है। कुछ कोड लिखें जो स्मृति के इस ब्लॉक को पढ़ सकते हैं; जो रन-टाइम के दौरान "स्नैपशॉट्स" लेने में मदद करेगा।

"डीबग लॉगिंग" के लिए वेब पर खोजें। कुछ स्रोत को चालू करना चाहिए जिसका उपयोग आप खेलने के लिए कर सकते हैं। ज्यादातर दुकानों में मैं आमतौर पर अपना खुद का रोल करता हूं।

क्या आपके पास अतिरिक्त गैर-अस्थिर स्मृति होनी चाहिए, आप एक क्षेत्र आरक्षित कर सकते हैं और उस पर लिख सकते हैं। यदि फाइल सिस्टम सिस्टम का समर्थन करने के लिए पर्याप्त है तो इसमें फाइलें भी शामिल होंगी।

सबसे खराब मामला, डीबग (धारावाहिक) बंदरगाह पर डेटा लिखें।

वास्तविक, वास्तविक समय, माप के लिए, हम आम तौर पर जीपीआईओ/टेस्ट पॉइंट और जीपीआईओ/टेस्ट पॉइंट में आउटपुट दालों से जुड़े एक ऑसिलोस्कोप का उपयोग करते हैं।

0

यह एक अच्छा जवाब है, @ जॉन डिबलिंग! मेरे पास एक प्रणाली काफी समान थी। हालांकि, मेरा "स्टेट" थ्रेड प्रति सेकंड 10 गुना श्रमिकों से पूछताछ कर रहा था और जब भी "स्टेट" थ्रेड डेटा के लिए पूछता है, तब भी यह कार्यकर्ता धागे के प्रदर्शन को प्रभावित करता है, इस डेटा (काउंटर इत्यादि) तक पहुंचने वाला एक महत्वपूर्ण अनुभाग है और यह इसका मतलब है कि इस डेटा को पुनर्प्राप्त करने के समय कार्यकर्ता थ्रेड अवरुद्ध है। यह पता चला कि मजदूरों के भारी भार के तहत, इस 10 हर्ट्ज स्टेट पूछताछ ने श्रमिकों के समग्र प्रदर्शन को प्रभावित किया।

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

0

आप std :: परमाणु इस्तेमाल कर सकते हैं आप सी ++ 11 पर हैं <>

#include <atomic> 

class GlobalStatistics { 
public: 

    static GlobalStatistics &get() { 
     static GlobalStatistics instance; 
     return instance; 
    } 

    void incrTotalBytesProcessed(unsigned int incrBy) { 
     totalBytesProcessed += incrBy; 
    } 

    long long getTotalBytesProcessed() const { return totalBytesProcessed; } 


private: 

    std::atomic_llong totalBytesProcessed; 

    GlobalStatistics() { } 
    GlobalStatistics(const GlobalStatistics &) = delete; 
    void operator=(const GlobalStatistics &) = delete; 
}; 

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^