2015-01-08 6 views
6

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

मुझे एक ऐसी विधि मिली है जो काफी अच्छी तरह से प्रदर्शन करती है, और मैं समझने की कोशिश कर रहा हूं कि यह बेहतर प्रदर्शन क्यों प्रदान करता है।

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

कोड डी में है, लेकिन यह सी या सी ++ के समान है।

साझा चर:

shared(bool) _stream_empty = false;; 
shared(ulong) upper_bound = 0; 
shared(ulong) curr_index = 0; 

पार्स कोड:

//Lazily parse the buffer 
void construct_next_elem() { 

    while(1) { 
     // Spin to stop us from getting ahead of the reader thread 
     buffer_empty = curr_index >= upper_bound -1 && 
         _stream_empty; 
     if(curr_index >= upper_bound && !_stream_empty) { 
      continue; 
     } 
     // Parsing logic ..... 
    } 
} 

विधि 1: Malloc एक बफर इतना बड़ा अप सामने अनज़िप फ़ाइल धारण करने के लिए।

char[] buffer;     // Same as vector<char> in C++ 
buffer.length = buffer_length; // Same as vector reserve in C++ or malloc 

विधि 2: उपयोग एक गुमनाम स्मृति नक्शा एक बफर के रूप

MmFile buffer; 
buffer = new MmFile(null, 
        MmFile.Mode.readWrite, // PROT_READ || PROT_WRITE 
        buffer_length, 
        null);     // MAP_ANON || MAP_PRIVATE 

रीडर धागा:

ulong buffer_length = get_gzip_length(file_path); 
pipe = pipeProcess(["gunzip", "-c", file_path], 
            Redirect.stdout); 
stream = pipe.stdout(); 

static void stream_data() { 
    while(!l.stream.eof()) { 

     // Splice is a reference inside the buffer 
     char[] splice = buffer[upper_bound..upper_bound + READ_SIZE]; 
     ulong read = stream.rawRead(splice).length; 
     upper_bound += read; 
    } 
    // Clean up 
} 

void start_stream() { 
     auto t = task!stream_data(); 
     t.executeInNewThread(); 
     construct_next_elem(); 
} 

मैं विधि 1 से बाहर काफी बेहतर प्रदर्शन हो रही है, यहां तक ​​कि पर परिमाण

User time (seconds): 112.22 
System time (seconds): 38.56 
Percent of CPU this job got: 151% 
Elapsed (wall clock) time (h:mm:ss or m:ss): 1:39.40 
Average shared text size (kbytes): 0 
Average unshared data size (kbytes): 0 
Average stack size (kbytes): 0 
Average total size (kbytes): 0 
Maximum resident set size (kbytes): 3784992 
Average resident set size (kbytes): 0 
Major (requiring I/O) page faults: 0 
Minor (reclaiming a frame) page faults: 5463 
Voluntary context switches: 90707 
Involuntary context switches: 2838 
Swaps: 0 
File system inputs: 0 
File system outputs: 0 
Socket messages sent: 0 
Socket messages received: 0 
Signals delivered: 0 
Page size (bytes): 4096 
Exit status: 0 
का क्रम

बनाम

User time (seconds): 275.92 
System time (seconds): 73.92 
Percent of CPU this job got: 117% 
Elapsed (wall clock) time (h:mm:ss or m:ss): 4:58.73 
Average shared text size (kbytes): 0 
Average unshared data size (kbytes): 0 
Average stack size (kbytes): 0 
Average total size (kbytes): 0 
Maximum resident set size (kbytes): 3777336 
Average resident set size (kbytes): 0 
Major (requiring I/O) page faults: 0 
Minor (reclaiming a frame) page faults: 944779 
Voluntary context switches: 89305 
Involuntary context switches: 9836 
Swaps: 0 
File system inputs: 0 
File system outputs: 0 
Socket messages sent: 0 
Socket messages received: 0 
Signals delivered: 0 
Page size (bytes): 4096 
Exit status: 0 

हो रही विधि 2. साथ जिस तरह से अधिक पेज दोष

किसी की मदद कर सके मुझे क्यों वहाँ प्रदर्शन में इस तरह के एक बुनियादी कमी mmap का उपयोग कर पर प्रकाश डाला?

यदि कोई समस्या को पूरा करने के किसी भी बेहतर तरीके से जानता है, तो मैं खुशी से इसे सुनूंगा।

संपादित करें -----

बदली गई विधि 2 करने के लिए:

 char * buffer = cast(char*)mmap(cast(void*)null, 
          buffer_length, 
          PROT_READ | PROT_WRITE, 
          MAP_ANON | MAP_PRIVATE, 
          -1, 
          0); 

अब एक सरल MmFile का उपयोग करने पर एक 3x प्रदर्शन वृद्धि हो रही है। मैं यह समझने की कोशिश कर रहा हूं कि प्रदर्शन में इतनी तेज भिन्नता क्या हो सकती है कि यह अनिवार्य रूप से केवल mmap के आसपास एक रैपर क्या है। सिर्फ एक सीधी चार * mmap बनाम Mmfile प्रयोग करने के लिए

Perf संख्या, जिस तरह से जिस तरह से कम पेज दोष:

User time (seconds): 109.99 
System time (seconds): 36.11 
Percent of CPU this job got: 151% 
Elapsed (wall clock) time (h:mm:ss or m:ss): 1:36.20 
Average shared text size (kbytes): 0 
Average unshared data size (kbytes): 0 
Average stack size (kbytes): 0 
Average total size (kbytes): 0 
Maximum resident set size (kbytes): 3777896 
Average resident set size (kbytes): 0 
Major (requiring I/O) page faults: 0 
Minor (reclaiming a frame) page faults: 2771 
Voluntary context switches: 90827 
Involuntary context switches: 2999 
Swaps: 0 
File system inputs: 0 
File system outputs: 0 
Socket messages sent: 0 
Socket messages received: 0 
Signals delivered: 0 
Page size (bytes): 4096 
Exit status: 0 
+1

ठीक है, कुछ भी अप्रत्याशित नहीं है। 'mmap() 'फ़ाइल को स्कंक द्वारा' खंड में 'दोषपूर्ण' होने का कारण बनता है। I/O की मात्रा दोनों मामलों में समान है, लेकिन यह mmap() मामले में कम वांछनीय क्षणों पर किया जाता है। – wildplasser

+0

और mmap opIndex (अधिभारित विधि) का उपयोग करता है, इसके बजाय आप 'buffer = mmap [];' –

+0

वाइल्डप्लेसर करके सीधे पहुंच के लिए शून्य [] को खींच सकते हैं, मैं इसे एक्सेस करने से पहले सीधे पाइप से एमएमएपी पर लिख रहा हूं। तो मैं उन्हें लिखने से पहले लोड करने के लिए पेजों पर इंतजार कर रहा हूं बनाम उन्हें मॉलोक के साथ आगे बढ़ा रहा हूं? मैं उनसे पढ़ने से पहले एक पाइप से एमएमएपी को सीधे लिख रहा हूं, इसलिए मुझे लगता है कि उन पृष्ठों को थोड़ी देर के लिए कैश किया जाएगा। – sprw121

उत्तर

0

आप pagefaults और धीमी गति से-चढ़ाव हो रही है क्योंकि mmap डिफ़ॉल्ट रूप से है सिर्फ तुम एक बार पेज लोड हो रहा है इसे एक्सेस करने का प्रयास करें।

अन्य पर पढ़ें जानता है कि आप अनुक्रमिक रूप से पढ़ रहे हैं, इसलिए इससे पहले कि आप उनसे पूछे जाने से पहले पृष्ठों को प्राप्त कर सकें।

madvise कॉल पर एक नज़र डालें - यह कर्नेल को सिग्नल करने का इरादा है कि आप mmap'ed फ़ाइल तक पहुंचने का इरादा रखते हैं, और आप mmap स्मृति के विभिन्न हिस्सों के लिए अलग-अलग रणनीतियों को सेट करने की अनुमति देते हैं - के लिए उदाहरण आप एक सूचकांक ब्लॉक आप स्मृति [MADV_WILLNEED] में रखना चाहते हैं, लेकिन सामग्री बेतरतीब ढंग से एक्सेस किया था और मांग पर [MADV_RANDOM] है, या आप एक अनुक्रमिक स्कैन [MADV_SEQUENTIAL]

हालांकि ओएस में हालांकि स्मृति पाशन कर रहे हैं आपके द्वारा सेट की जा रही रणनीति को अनदेखा करने के लिए पूरी तरह से मुफ्त है, इसलिए वाईएमएमडब्ल्यू

+0

आप शायद [madvise (2)] (http://man7.org/linux/man-pages/man2/madvise.2.html) नहीं 'posix_fadvise' –

+0

... सुधार के लिए धन्यवाद, हाँ' पागलपन का उपयोग करें '- मुझे जवाब लिखने से पहले मेरे स्रोत कोड को देखना चाहिए था :) – Soren

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