मिमीप () बनाम रीडिंग ब्लॉक


184

मैं एक ऐसे प्रोग्राम पर काम कर रहा हूं, जो ऐसी फाइलों का प्रसंस्करण करेगा जो संभवतः 100GB या उससे अधिक आकार का हो सकता है। फ़ाइलों में चर लंबाई रिकॉर्ड के सेट होते हैं। मुझे एक पहला कार्यान्वयन मिला है और चल रहा है और अब मैं प्रदर्शन में सुधार की ओर देख रहा हूं, विशेष रूप से I / O को अधिक कुशलता से करने के बाद से इनपुट फ़ाइल कई बार स्कैन की जाती है।

क्या mmap()C ++ की fstreamलाइब्रेरी के माध्यम से ब्लॉकों में बनाम रीडिंग का उपयोग करने के लिए अंगूठे का एक नियम है ? मैं क्या करना चाहूंगा डिस्क से बड़े ब्लॉकों को एक बफर में पढ़ा जाता है, बफर से पूरा रिकॉर्ड संसाधित करता है, और फिर अधिक पढ़ें।

mmap()कोड के बाद से संभवतः बहुत मुश्किल भरा काम होता सकता है mmap'घ ब्लॉक झूठ की जरूरत पर पेज सीमाओं (मेरी समझ) आकार और रिकॉर्ड कर सकता संभवतः भर की तरह पेज सीमाओं। fstreamएस के साथ , मैं सिर्फ एक रिकॉर्ड शुरू करने और फिर से पढ़ना शुरू कर सकता हूं, क्योंकि हम पृष्ठ आकार की सीमाओं पर पढ़ने वाले ब्लॉक तक सीमित नहीं हैं।

मैं वास्तव में पहले पूर्ण कार्यान्वयन को लिखे बिना इन दोनों विकल्पों के बीच कैसे निर्णय ले सकता हूं? अंगूठे के किसी भी नियम (जैसे, mmap()2x तेजी है) या सरल परीक्षण?


1
यह एक दिलचस्प पढ़ा है: medium.com/@sasha_f/... प्रयोगों में mmap()2-6 बार, syscalls का उपयोग कर जैसे की तुलना में तेजी है read()
mplattner

जवाबों:


208

मैं लिनक्स पर एमएमएपी / अंतिम प्रदर्शन को पढ़ने के लिए अंतिम शब्द खोजने की कोशिश कर रहा था और मैं लिनक्स कर्नेल मेलिंग सूची पर एक अच्छी पोस्ट ( लिंक ) के पार आया । यह 2000 से है, इसलिए आईओ और तब से कर्नेल में आभासी स्मृति में कई सुधार किया गया है, लेकिन यह अच्छी तरह से कारण है कि बताते हैं mmapया readतेज़ या धीमे हो सकता है।

  • एक कॉल की mmapतुलना में अधिक ओवरहेड होता है read(जिस तरह epollसे अधिक ओवरहेड होता है poll, जिसमें ओवरहेड की तुलना में अधिक होता है read)। वर्चुअल मेमोरी मैपिंग बदलना कुछ प्रोसेसरों पर समान कारणों से काफी महंगा ऑपरेशन है, जो विभिन्न प्रक्रियाओं के बीच स्विच करना महंगा है।
  • IO सिस्टम पहले से ही डिस्क कैश का उपयोग कर सकता है, इसलिए यदि आप कोई फ़ाइल पढ़ते हैं, तो आप कैश को मारेंगे या यह याद रखेंगे कि आप किस विधि का उपयोग करते हैं।

तथापि,

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

मीमैप / रीड की चर्चा मुझे दो अन्य प्रदर्शन चर्चाओं की याद दिलाती है:

  • कुछ जावा प्रोग्रामर यह जानकर चौंक गए कि I / O को अवरुद्ध करने की तुलना में अक्सर नॉनब्लॉकिंग I / O को धीमा कर दिया जाता है, जो कि सही अर्थ बनाता है यदि आप जानते हैं कि Nonblocking I / O को अधिक syscalls बनाने की आवश्यकता है।

  • कुछ अन्य नेटवर्क प्रोग्रामर यह जानकर हैरान रह गए कि epollअक्सर धीमी गति से होता है poll, जो सही अर्थों में समझ में आता है अगर आपको पता है कि प्रबंधन के epollलिए अधिक सिस्मॉल बनाने की आवश्यकता होती है।

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

(इस सवाल पर necro'ing के लिए खेद है, लेकिन मैं एक उत्तर की तलाश में था और यह प्रश्न Google परिणामों के शीर्ष पर आता रहा)


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

अपशॉट यह है कि, मेरे (आधुनिक इंटेल, लगभग 2018) हार्डवेयर पर, बड़े-से-पेज-आकार (4 KiB) रीड्स की mmapतुलना में कम ओवरहेड readहै। अब यह बहुत सच है कि यदि आप डेटा को बहुत कम और बेतरतीब ढंग से एक्सेस करना चाहते हैं, mmapतो वास्तव में, वास्तव में अच्छा है - लेकिन कांसेप्ट आवश्यक नहीं है: फिर mmapभी क्रमिक पहुंच के लिए सबसे अच्छा हो सकता है।
BeeOnRope

1
@BeeOnRope: आप 2000 के दशक से हार्डवेयर और सॉफ्टवेयर के आधार पर सलाह पर संदेह कर सकते हैं, लेकिन मैं बेंचमार्क से भी अधिक उलझन में हूं जो एक पद्धति और डेटा प्रदान नहीं करता है। यदि आप एक ऐसा मामला बनाना चाहते हैं जो mmapतेज हो, तो मैं सारणीबद्ध परिणामों के साथ नंगे न्यूनतम संपूर्ण परीक्षण तंत्र (स्रोत कोड) और प्रोसेसर मॉडल संख्या को देखने की उम्मीद करूंगा।
डायट्रिच एप

@BeeOnRope: यह भी ध्यान रखें कि जब आप इस तरह से मेमोरी सिस्टम के बिट्स का परीक्षण कर रहे हैं, तो माइक्रोबेनचर्च बेहद भ्रामक हो सकते हैं क्योंकि एक TLB फ्लश आपके कार्यक्रम के बाकी हिस्सों के प्रदर्शन को नकारात्मक रूप से प्रभावित कर सकता है, और यह प्रभाव दिखाई देगा यदि आप केवल मिमीप को ही मापते हैं।
डायट्रिच एप

2
@DietrichEpp - हाँ, मैं अच्छी तरह से TLB प्रभावों से वाकिफ हूँ। ध्यान दें कि mmapअसामान्य परिस्थितियों (लेकिन munmapहो सकता है) को छोड़कर टीएलबी को फ्लश न करें । मेरे परीक्षणों में एक वास्तविक दुनिया के उपयोग के मामले में चल रहे "आवेदन में" (सहित munmap) और " दोनों " भी शामिल थे । बेशक मेरा आवेदन आपके आवेदन के समान नहीं है, इसलिए लोगों को स्थानीय स्तर पर परीक्षण करना चाहिए। यह भी स्पष्ट नहीं है कि mmapएक माइक्रो-बेंचमार्क द्वारा इष्ट है: read()यह भी एक बड़ा बढ़ावा मिलता है क्योंकि उपयोगकर्ता-साइड गंतव्य बफर आम तौर पर एल 1 में रहता है, जो एक बड़े अनुप्रयोग में नहीं हो सकता है। तो हाँ, "यह जटिल है"।
मधुमक्खी पालन

47

मुख्य प्रदर्शन लागत डिस्क i / o होने जा रही है। "mmap ()" istream की तुलना में निश्चित रूप से तेज है, लेकिन अंतर ध्यान देने योग्य नहीं हो सकता है क्योंकि डिस्क i / o आपके रन-टाइम पर हावी होगी।

मैंने बेन कोलिन्स के कोड के टुकड़े (ऊपर / नीचे देखें) को परखने के लिए कोशिश की कि "एमएमएपी () रास्ता तेज़ है" और कोई औसत दर्जे का अंतर नहीं मिला। उनके जवाब पर मेरी टिप्पणी देखें।

मैं निश्चित रूप से प्रत्येक रिकॉर्ड को बदले में अलग से mmap'ing की अनुशंसा नहीं करूंगा जब तक कि आपके "रिकॉर्ड" विशाल न हों - यह बहुत धीमी गति से होगा, प्रत्येक रिकॉर्ड के लिए 2 सिस्टम कॉल की आवश्यकता होगी और संभवतः डिस्क-मेमोरी कैश से पृष्ठ को खोना होगा ...। ।

आपके मामले में मुझे लगता है कि mmap (), istream और निम्न-स्तरीय ओपन () / रीड () कॉल सभी एक ही होंगे। मैं इन मामलों में एमएमएपी () की सिफारिश करूंगा:

  1. फ़ाइल के भीतर यादृच्छिक अभिगम (अनुक्रमिक नहीं) है, और
  2. पूरी बात स्मृति में आराम से फिट होती है या फ़ाइल के भीतर स्थानीयता-संदर्भ होता है ताकि कुछ पृष्ठों को मैप किया जा सके और अन्य पृष्ठों को मैप किया जा सके। इस तरह ऑपरेटिंग सिस्टम अधिकतम लाभ के लिए उपलब्ध रैम का उपयोग करता है।
  3. या यदि एक ही फ़ाइल पर कई प्रक्रियाएँ पढ़ / काम कर रही हैं, तो mmap () शानदार है क्योंकि सभी प्रक्रियाएँ एक ही भौतिक पृष्ठों को साझा करती हैं।

(btw - मुझे mmap () / MapViewOfFile ()) से प्यार है।


रैंडम एक्सेस के बारे में अच्छी बात: यह मेरी धारणा को चलाने वाली चीजों में से एक हो सकती है।
बेन कॉलिन्स

1
मैं यह नहीं कहूंगा कि फ़ाइल को आराम से मेमोरी में फिट करना है, केवल एड्रेस स्पेस में। इसलिए 64 बिट सिस्टम पर, बड़ी फ़ाइलों को मैप न करने का कोई कारण नहीं होना चाहिए। ओएस जानता है कि उसे कैसे संभालना है; यह वही तर्क है जो स्वैपिंग के लिए उपयोग किया जाता है, लेकिन इस मामले में डिस्क पर अतिरिक्त स्वैप स्थान की आवश्यकता नहीं होती है।
MvG

@ एमवीजी: क्या आप डिस्क आई / ओ के बारे में बात समझते हैं? यदि फ़ाइल एड्रेस स्पेस में फिट हो जाती है, लेकिन मेमोरी नहीं है और आपके पास रैंडम एक्सेस है, तो आपको हर रिकॉर्ड एक्सेस की आवश्यकता हो सकती है, जिसमें एक डिस्क हेड मूव और एक SSD पेज ऑपरेशन की आवश्यकता होती है, जो प्रदर्शन के लिए एक आपदा होगी।
टिम कूपर

3
डिस्क i / o पहलू एक्सेस विधि से स्वतंत्र होना चाहिए। यदि आपके पास वास्तव में बड़ी-से-रैम फ़ाइलों तक यादृच्छिक पहुंच है, तो mmap और seek + read दोनों गंभीर रूप से डिस्क-बाउंड हैं। अन्यथा दोनों को कैश से फायदा होगा। मैं या तो दिशा में एक मजबूत तर्क के रूप में स्मृति आकार की तुलना में फ़ाइल का आकार नहीं देखता हूं। फ़ाइल का आकार बनाम पता स्थान, दूसरी ओर, एक बहुत मजबूत तर्क है, विशेष रूप से वास्तव में यादृच्छिक अभिगम के लिए।
22

मेरे मूल जवाब में यह बिंदु था और यह है: "पूरी बात स्मृति में आराम से फिट होती है या फ़ाइल के भीतर स्थानीयता-संदर्भ है"। तो दूसरा बिंदु यह बताता है कि आप क्या कह रहे हैं।
टिम कूपर

43

मिमीप तेजी से रास्ता है । आप अपने आप को यह साबित करने के लिए एक साधारण बेंचमार्क लिख सकते हैं:

char data[0x1000];
std::ifstream in("file.bin");

while (in)
{
  in.read(data, 0x1000);
  // do something with data
}

बनाम:

const int file_size=something;
const int page_size=0x1000;
int off=0;
void *data;

int fd = open("filename.bin", O_RDONLY);

while (off < file_size)
{
  data = mmap(NULL, page_size, PROT_READ, 0, fd, off);
  // do stuff with data
  munmap(data, page_size);
  off += page_size;
}

स्पष्ट रूप से, मैं विवरण छोड़ रहा हूं (जैसे कि यह निर्धारित करने के लिए कि जब आप इस घटना में फ़ाइल के अंत तक पहुँचते हैं कि आपकी फ़ाइल एक से अधिक नहीं है page_size, उदाहरण के लिए), लेकिन यह वास्तव में इससे अधिक जटिल नहीं होना चाहिए ।

यदि आप कर सकते हैं, तो आप अपने डेटा को कई फाइलों में तोड़ने की कोशिश कर सकते हैं जो कि एमएमएपी () - एड के बजाय पूरे भाग में (बहुत सरल) हो सकते हैं।

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

अद्यतन : मुझे यह भी कहना चाहिए कि यह बेंचमार्क विंडोज में काफी अलग दिखाई देगा क्योंकि Microsoft ने एक निफ्टी फ़ाइल कैश लागू किया है जो कि आप सबसे पहले मिमीप के साथ क्या करेंगे। यानी, अक्सर-एक्सेस की गई फ़ाइलों के लिए, आप बस std :: ifstream.read () कर सकते हैं और यह mmap के समान तेज़ होगा, क्योंकि फ़ाइल कैश आपके लिए पहले ही मेमोरी-मैपिंग कर चुका होगा, और यह पारदर्शी है।

अंतिम अद्यतन : देखो, लोग: ओएस और मानक पुस्तकालयों और डिस्क और मेमोरी पदानुक्रमों के विभिन्न प्लेटफ़ॉर्म संयोजनों के पार, मैं निश्चित रूप से यह नहीं कह सकता कि सिस्टम कॉल mmap, जिसे ब्लैक बॉक्स के रूप में देखा जाता है, हमेशा हमेशा काफी तेज होगा की तुलना में read। यह मेरा इरादा बिल्कुल नहीं था, भले ही मेरे शब्दों को इस तरह से समझा जाए। अंततः, मेरा कहना यह था कि मेमोरी-मैप्ड i / o आम तौर पर बाइट-आधारित i / o से अधिक तेज है; यह अभी भी सच है । यदि आपको प्रयोगात्मक रूप से पता चलता है कि दोनों के बीच कोई अंतर नहीं है, तो केवल एक ही स्पष्टीकरण जो मुझे उचित लगता है, वह यह है कि आपका प्लेटफ़ॉर्म एक तरह से कवर के तहत मेमोरी-मैपिंग को लागू करता है जो कॉल के प्रदर्शन के लिए फायदेमंद हैread। पूरी तरह से निश्चित है कि आप पोर्टेबल तरीके से मेमोरी-मैप्ड i / o का उपयोग कर रहे हैं mmap। यदि आप पोर्टेबिलिटी के बारे में परवाह नहीं करते हैं और आप अपने लक्ष्य प्लेटफार्मों की विशेष विशेषताओं पर भरोसा कर सकते हैं, तो उपयोग करना readबिना किसी प्रदर्शन को मापने के लिए उपयुक्त हो सकता है।

उत्तर सूची साफ करने के लिए संपादित करें: @jbl:

स्लाइडिंग विंडो mmap दिलचस्प लगता है। क्या आप इसके बारे में थोड़ा और कह सकते हैं?

ज़रूर - मैं गिट के लिए एक सी ++ लाइब्रेरी लिख रहा था (एक लीबिटीज ++, अगर आप करेंगे), और मैं इस तरह की समस्या में भाग गया: मुझे बड़ी (बहुत बड़ी) फाइलें खोलने में सक्षम होना चाहिए और प्रदर्शन में कुल कुत्ता नहीं होना चाहिए। (जैसा कि इसके साथ होगा std::fstream)।

Boost::Iostreamsपहले से ही एक मैप्ड_फाइल स्रोत है, लेकिन समस्या यह थी कि यह mmapपूरी फाइलों को पिंग कर रहा था , जो आपको 2 ^ (शब्द का आकार) तक सीमित करता है। 32-बिट मशीनों पर, 4GB पर्याप्त बड़ा नहीं है। .packGit में ऐसी फाइलें होने की उम्मीद करना अनुचित नहीं है जो इससे बहुत बड़ी हो जाती हैं, इसलिए मुझे नियमित फ़ाइल i / o का सहारा लिए बिना चंक्स में फाइल को पढ़ने की आवश्यकता थी। के कवर के तहत Boost::Iostreams, मैं एक स्रोत, कम या ज्यादा के बीच बातचीत का एक दूसरा पहलू है जो लागू किया std::streambufऔर std::istream। तुम भी एक समान दृष्टिकोण की कोशिश कर सकता है एक विरासत std::filebufमें mapped_filebufऔर इसी तरह, विरासत std::fstreamमें मिला है a mapped_fstream। यह दोनों के बीच की बातचीत है जो सही होना मुश्किल है। Boost::Iostreams आपके लिए कुछ काम किया है, और यह फिल्टर और चेन के लिए हुक भी प्रदान करता है, इसलिए मैंने सोचा कि इस तरह से इसे लागू करना अधिक उपयोगी होगा।


3
पुन: Windows पर mmaped फ़ाइल कैश। सटीक रूप से: जब फ़ाइल बफ़रिंग सक्षम किया जाता है, तो कर्नेल मेमोरी उस फ़ाइल को मैप करती है जिसे आप आंतरिक रूप से पढ़ रहे हैं, उस बफ़र में पढ़ता है और इसे आपकी प्रक्रिया में वापस कॉपी करता है। यह ऐसा है जैसे आप एक अतिरिक्त कॉपी स्टेप को छोड़कर स्मृति को स्वयं मैप करते हैं।
क्रिस स्मिथ

6
मैं स्वीकृत उत्तर से असहमत हूं, लेकिन मेरा मानना ​​है कि यह उत्तर गलत है। मैंने आपके सुझाव का पालन किया और 64 बिट लिनक्स मशीन पर आपके कोड की कोशिश की, और एमएमएपी () एसटीएल कार्यान्वयन से तेज नहीं था। इसके अलावा, सैद्धांतिक रूप से मैं 'एमएएमएपी ()' के किसी भी तेज (या धीमा) होने की उम्मीद नहीं करूंगा।
टिम कूपर

3
@ समय कूपर: आपको ब्याज का यह धागा ( markmail.org/message/… ) मिल सकता है । दो चीज़ों पर ध्यान दें: mmap को लिनक्स में ठीक से अनुकूलित नहीं किया गया है, और सर्वश्रेष्ठ परिणाम प्राप्त करने के लिए एक को अपने परीक्षण में मैडविज़ का भी उपयोग करना होगा।
बेन कॉलिन्स

9
प्रिय बेन: मैंने वह लिंक पढ़ा है। यदि लिनक्स पर 'mmap ()' तेज नहीं है, और MapViewOfFile () विंडोज पर तेज नहीं है, तो क्या आप यह दावा कर सकते हैं कि "mmap रास्ता तेज है"? इसके अलावा, सैद्धांतिक कारणों से मेरा मानना ​​है कि मिमीप () क्रमिक रीड्स के लिए तेज नहीं है - क्या आपके पास इसके विपरीत कोई स्पष्टीकरण है?
तैमूर कूपर

11
बेन, क्यों mmap()एक समय में एक पृष्ठ फ़ाइल को परेशान ? यदि size_tफ़ाइल के आकार (64-बिट सिस्टम पर बहुत संभावना) को धारण करने के लिए पर्याप्त है, तो बस mmap()एक कॉल में पूरी फ़ाइल।
स्टीव एम्मर्सन ने

39

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

मैमप जादू की तरह लगता है

इस मामले में जहां फ़ाइल पहले से ही पूरी तरह से कैश किया गया है ले रहा है 1 आधार रेखा के रूप में 2 , mmapकी तरह काफी लग सकता है जादू :

  1. mmap केवल संपूर्ण फ़ाइल को मैप करने के लिए (संभावित) 1 सिस्टम कॉल की आवश्यकता होती है, जिसके बाद किसी और सिस्टम कॉल की आवश्यकता नहीं होती है।
  2. mmap कर्नेल से उपयोगकर्ता-स्थान पर फ़ाइल डेटा की प्रतिलिपि की आवश्यकता नहीं है।
  3. mmapआपको फ़ाइल को "मेमोरी के रूप में" एक्सेस करने की अनुमति देता है, जिसमें आप मेमोरी के खिलाफ जो भी उन्नत चालें कर सकते हैं, जैसे कि कंपाइलर ऑटो-वैरिफिकेशन, सिमड इंट्रिंसिक्स, प्रीफेटिंग, अनुकूलित-इन-मेमोरी पार्सिंग रूटीन, ओपनएमपी आदि शामिल हैं।

उस स्थिति में जब फ़ाइल पहले से ही कैश में है, इसे हरा पाना असंभव है: आप सीधे कर्नेल पेज कैश को मेमोरी के रूप में एक्सेस करते हैं और यह उससे तेज नहीं हो सकता है।

खैर, यह कर सकते हैं।

वास्तव में जादू नहीं है क्योंकि ...

mmap अभी भी प्रति पृष्ठ काम करता है

एक प्राथमिक छिपी हुई लागत mmapबनाम read(2)(जो वास्तव में पढ़ने वाले ब्लॉकों के लिए तुलनीय ओएस-स्तरीय syscall है ) यह है कि mmapआपको उपयोगकर्ता-अंतरिक्ष में प्रत्येक 4K पृष्ठ के लिए "कुछ काम" करने की आवश्यकता होगी, भले ही यह छिपा हो। पृष्ठ-दोष तंत्र।

एक उदाहरण के लिए एक विशिष्ट कार्यान्वयन जो mmapपूरी फ़ाइल को केवल 100 जीबी फ़ाइल को पढ़ने के लिए 100 जीबी / 4K = 25 मिलियन दोष में गलत करने की आवश्यकता होगी। अब, ये मामूली दोष होंगे , लेकिन 25 बिलियन पृष्ठ के दोष अभी भी सुपर फास्ट नहीं होंगे। एक मामूली गलती की कीमत शायद सबसे अच्छे मामले में नैनो के 100 के दशक में है।

एमएमएपी टीएलबी प्रदर्शन पर बहुत निर्भर करता है

अब, आप इसे यह बताने के MAP_POPULATEलिए पास कर सकते हैं mmapकि लौटने से पहले सभी पेज टेबल सेट कर लें, इसलिए इसे एक्सेस करते समय कोई पेज दोष नहीं होना चाहिए। अब, यह थोड़ी सी समस्या है कि यह पूरी फ़ाइल को RAM में भी पढ़ता है, जो कि यदि आप 100GB फ़ाइल को मैप करने का प्रयास करते हैं, तो आपको झटका देना होगा - लेकिन आइए अब 3 के लिए इसे अनदेखा करें । कर्नेल को इन पृष्ठ तालिकाओं (कर्नेल समय के रूप में दिखाता है) को सेट करने के लिए प्रति पृष्ठ कार्य करने की आवश्यकता है । यह mmapदृष्टिकोण में एक प्रमुख लागत होने के नाते समाप्त होता है , और यह फ़ाइल आकार के लिए आनुपातिक है (यानी, यह फ़ाइल आकार बढ़ने के कारण अपेक्षाकृत कम महत्वपूर्ण नहीं है) 4

अंत में, यहां तक ​​कि उपयोगकर्ता-स्पेस में भी इस तरह की मैपिंग बिल्कुल मुफ्त नहीं है (बड़े मेमोरी बफ़र्स की तुलना में फ़ाइल-आधारित नहीं है mmap) - यहां तक ​​कि पेज टेबल सेट होने के बाद भी, नए पेज पर प्रत्येक एक्सेस हो रहा है, वैचारिक रूप से, टीएलबी की याद आती है। चूँकि mmapकिसी फ़ाइल का अर्थ है पृष्ठ कैश और उसके 4K पृष्ठों का उपयोग करना, तो आप फिर से 100GB फ़ाइल के लिए इस लागत को 25 मिलियन गुना कर सकते हैं।

अब, इन टीएलबी मिसेस की वास्तविक लागत आपके हार्डवेयर के कम से कम निम्नलिखित पहलुओं पर बहुत अधिक निर्भर करती है: (क) आपके पास कितने 4K टीएलबी हैं और शेष अनुवाद कैशिंग काम करता है (ख) कितना अच्छा हार्डवेयर प्रीफैच करता है TLB के साथ - उदाहरण के लिए, क्या पृष्ठ चलना ट्रिगर कर सकता है? (c) पेज वॉकिंग हार्डवेयर कितना तेज़ और कितना समानांतर है। आधुनिक हाई-एंड x86 इंटेल प्रोसेसर पर, पेज वॉकिंग हार्डवेयर सामान्य रूप से बहुत मजबूत होता है: कम से कम 2 समानांतर पृष्ठ वॉकर होते हैं, एक पेज वॉक निरंतर निष्पादन के साथ समवर्ती रूप से हो सकता है, और हार्डवेयर प्रीफ़ेटिंग एक पेज वॉक को ट्रिगर कर सकता है। इसलिए एक स्ट्रीमिंग रीड लोड पर टीएलबी प्रभाव काफी कम है - और ऐसा लोड अक्सर पृष्ठ आकार की परवाह किए बिना समान रूप से प्रदर्शन करेगा। अन्य हार्डवेयर आमतौर पर बहुत बदतर है, हालांकि!

read () इन नुकसानों से बचा जाता है

read()Syscall है, जो आम तौर पर क्या underlies "ब्लॉक पढ़ा" प्रकार कॉल C, C ++ में, उदाहरण के लिए की पेशकश की और अन्य भाषाओं एक प्राथमिक नुकसान है कि हर किसी की अच्छी तरह से वाकिफ हैं:

  • read()एन बाइट्स के प्रत्येक कॉल को कर्नेल से उपयोगकर्ता स्थान पर एन बाइट्स को कॉपी करना होगा।

दूसरी ओर, यह ऊपर की अधिकांश लागतों से बचता है - आपको उपयोगकर्ता स्थान में 25 मिलियन 4K पृष्ठों में मैप करने की आवश्यकता नहीं है। आप आमतौर पर mallocयूजर स्पेस में सिंगल बफर छोटे बफर, और अपने सभी readकॉल के लिए बार-बार उपयोग कर सकते हैं। कर्नेल की तरफ, 4K पेज या TLB के साथ लगभग कोई समस्या नहीं है क्योंकि सभी RAM में आमतौर पर कुछ बहुत बड़े पेज (जैसे x86 पर 1 जीबी पेज) का उपयोग करके रैखिक रूप से मैप किया जाता है, इसलिए पेज कैश में अंतर्निहित पेज कवर होते हैं बहुत ही कुशलता से कर्नेल स्पेस में।

तो मूल रूप से आपके पास यह निर्धारित करने के लिए निम्नलिखित तुलना है कि एक बड़ी फ़ाइल के एक एकल रीड के लिए तेज़ क्या है:

क्या mmapउपयोग के द्वारा निहित कर्नेल से उपयोगकर्ता स्थान पर फ़ाइल सामग्री की प्रतिलिपि बनाने के प्रति-बाइट कार्य की तुलना में दृष्टिकोण से अधिक प्रति-पृष्ठ कार्य निहित है read()?

कई प्रणालियों पर, वे वास्तव में लगभग संतुलित होते हैं। ध्यान दें कि हार्डवेयर और ओएस स्टैक की पूरी तरह से अलग विशेषताओं के साथ प्रत्येक एक तराजू।

विशेष रूप से, mmapदृष्टिकोण अपेक्षाकृत तेज हो जाता है जब:

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

... जबकि read()दृष्टिकोण अपेक्षाकृत तेज हो जाता है जब:

  • read()Syscall अच्छा प्रतिलिपि प्रदर्शन है। जैसे, copy_to_userकर्नेल की तरफ अच्छा प्रदर्शन।
  • कर्नेल में हार्डवेयर समर्थन के साथ केवल कुछ बड़े पृष्ठों का उपयोग करके, मेमोरी को मैप करने का एक कुशल (उपयोगकर्ता के सापेक्ष) तरीका है।
  • कर्नेल में तेज syscalls और syscalls के चारों ओर कर्नेल TLB प्रविष्टियाँ रखने का एक तरीका है।

हार्डवेयर कारकों से ऊपर अलग-अलग हो बेतहाशा भी एक ही परिवार में, विभिन्न प्लेटफार्मों भर में (जैसे, 86 पीढ़ियों और विशेष रूप से बाजार खंडों के भीतर) और निश्चित रूप से आर्किटेक्चर भर में (जैसे, एआरएम 86 बनाम पीपीसी बनाम)।

ओएस कारक दोनों पक्षों पर विभिन्न सुधारों के साथ-साथ एक दृष्टिकोण या दूसरे के लिए सापेक्ष गति में बड़े उछाल के कारण बदलते रहते हैं। एक हालिया सूची में शामिल हैं:

  • ऊपर वर्णित गलती-आस-पास का जोड़, जो वास्तव में mmapमामले के बिना मदद करता है MAP_POPULATE
  • तेजी से पथ के copy_to_userतरीकों को जोड़ना arch/x86/lib/copy_user_64.S, उदाहरण के लिए, REP MOVQजब यह तेज होता है, जो वास्तव में read()मामले में मदद करता है।

स्पेक्टर और मेल्टडाउन के बाद अपडेट करें

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

यह सभी read()आधारित विधियों की तुलना में आधारित विधियों के लिए एक सापेक्ष नुकसान है mmap, क्योंकि read()विधियों को प्रत्येक "बफर आकार" के डेटा के लिए एक सिस्टम कॉल करना होगा। आप इस लागत को बढ़ाने के लिए बफर आकार में मनमाने ढंग से वृद्धि नहीं कर सकते हैं क्योंकि आमतौर पर बड़े बफर का उपयोग करने से आप L1 के आकार से अधिक खराब हो जाते हैं और इसलिए लगातार कैश मिसेज पीड़ित हैं।

दूसरी ओर, mmapआप MAP_POPULATEकेवल एक ही सिस्टम कॉल की कीमत पर, मेमोरी के एक बड़े क्षेत्र में और कुशलता से इसे एक्सेस कर सकते हैं।


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

2 ... क्योंकि यदि फ़ाइल कैश नहीं की जाती है, तो आपका व्यवहार IO चिंताओं पर पूरी तरह से हावी होने वाला है, जिसमें अंतर्निहित हार्डवेयर में आपकी पहुंच पैटर्न के प्रति सहानुभूति कितनी है - और इस तरह की पहुंच सुनिश्चित करने में आपका पूरा प्रयास उतना ही सहानुभूतिपूर्ण होना चाहिए जितना कि संभव है, उदाहरण के लिए madviseया fadviseकॉल के उपयोग के माध्यम से (और जो भी अनुप्रयोग स्तर में परिवर्तन आप पहुंच पैटर्न में सुधार कर सकते हैं)।

3 आप इसके चारों ओर मिल सकते हैं, उदाहरण के लिए, mmapछोटे आकार की खिड़कियों में क्रमिक रूप से आईएनजी द्वारा , 100 एमबी।

4 वास्तव में, यह MAP_POPULATEदृष्टिकोण को बदल देता है (कम से कम कुछ हार्डवेयर / ओएस संयोजन) केवल इसका उपयोग न करने की तुलना में थोड़ा तेज, शायद इसलिए कि कर्नेल गलती का उपयोग कर रहा है - इसलिए मामूली दोषों की वास्तविक संख्या 16 के एक कारक से कम हो जाती है या ऐसा।


4
इस जटिल मुद्दे पर अधिक सूक्ष्म उत्तर देने के लिए धन्यवाद। ज्यादातर लोगों को यह स्पष्ट प्रतीत होता है कि एमएएमपी तेज है, जब वास्तव में यह अक्सर ऐसा नहीं होता है। मेरे प्रयोगों में, इन-मेमोरी इंडेक्स के साथ बड़े 100GB डेटाबेस को बेतरतीब ढंग से एक्सेस करना, प्रेड () के साथ तेजी से निकला, भले ही मैं लाखों एक्सेस में से प्रत्येक के लिए एक मॉलकॉन्ग कर रहा था। और ऐसा लगता है जैसे उद्योग में लोगों की एक ही कमी देखी गई है
केटानो सॉयर

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

मुझे लगता है कि आप कहाँ कहते हैं "... लेकिन 25 बिलियन पेज के दोष अभी भी सुपर फास्ट नहीं होने जा रहे हैं ..." इसे पढ़ना चाहिए "... लेकिन 25 मिलियन पेज के दोष अभी भी सुपर फास्ट नहीं होने जा रहे हैं ..." । मैं 100% सकारात्मक नहीं हूं, इसलिए मैं सीधे संपादन नहीं कर रहा हूं।
टन वैन डेन हेउवेल

7

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

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

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

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

यह सब Windows के तहत CreateFileMapping () और MapViewOfFile () (और GetSystemInfo () के लिए System_INFO.dwAllocationGranularity --- नहीं SYSTEM_INFO.dwPageSize का उपयोग करके भी ठीक काम करता है।


मैं बस googled और dwAllocationGranularity के बारे में इस छोटे स्निपेट को पाया - मैं dwPageSize का उपयोग कर रहा था और सब कुछ टूट रहा था। धन्यवाद!
6

4

मिमीप तेज़ होना चाहिए, लेकिन मुझे नहीं पता कि कितना है। यह आपके कोड पर बहुत निर्भर करता है। यदि आप mmap का उपयोग करते हैं, तो पूरी फ़ाइल को एक साथ mmap करना सबसे अच्छा है, इससे आपको जीवन बहुत आसान हो जाएगा। एक संभावित समस्या यह है कि यदि आपकी फ़ाइल 4GB से बड़ी है (या व्यवहार में सीमा कम है, तो अक्सर 2GB) आपको 64GB वास्तुकला की आवश्यकता होगी। इसलिए यदि आप 32 वातावरण का उपयोग कर रहे हैं, तो आप शायद इसका उपयोग नहीं करना चाहते हैं।

यह कहने के बाद, प्रदर्शन में सुधार के लिए एक बेहतर मार्ग हो सकता है। आपने कहा कि इनपुट फ़ाइल कई बार स्कैन की जाती है , यदि आप इसे एक पास में पढ़ सकते हैं और फिर इसके साथ किया जा सकता है, तो संभवतः यह बहुत तेज़ हो सकता है।


3

शायद आपको फ़ाइलों को पूर्व-संसाधित करना चाहिए, इसलिए प्रत्येक रिकॉर्ड एक अलग फ़ाइल में है (या कम से कम प्रत्येक फ़ाइल एक एमएमएपी-सक्षम आकार है)।

अगले रिकॉर्ड पर जाने से पहले आप प्रत्येक रिकॉर्ड के लिए सभी प्रोसेसिंग चरण भी कर सकते हैं? शायद कि कुछ IO उपरि से बचना होगा?


3

मैं सहमत हूं कि mmap'd फ़ाइल I / O तेजी से होने वाली है, लेकिन जब आपका कोड कोड बेंच रहा हो, तो क्या काउंटर का उदाहरण कुछ हद तक अनुकूलित नहीं होना चाहिए ?

बेन कोलिन्स ने लिखा है:

char data[0x1000];
std::ifstream in("file.bin");

while (in)
{
    in.read(data, 0x1000);
    // do something with data 
}

मैं यह भी सुझाव देना चाहूंगा:

char data[0x1000];
std::ifstream iifle( "file.bin");
std::istream  in( ifile.rdbuf() );

while( in )
{
    in.read( data, 0x1000);
    // do something with data
}

और इसके अलावा, आप बफर साइज़ को वर्चुअल मेमोरी के एक पेज के आकार का बनाने की कोशिश कर सकते हैं, अगर 0x1000 आपकी मशीन पर वर्चुअल मेमोरी के एक पेज का आकार नहीं है ... IMHO mmap'd फ़ाइल I / O अभी भी है जीतता है, लेकिन इससे चीजों को करीब लाना चाहिए।


2

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


1
सबसे अधिक संभावना है कि आप कर्नेल की तुलना में अपने एप्लिकेशन-विशिष्ट डेटा को कैशिंग करने का एक बेहतर काम कर सकते हैं, जो पृष्ठ आकार के चंक्स पर बहुत ही अंधाधुंध तरीके से संचालित होता है (उदाहरण के लिए, यह केवल एक सरल छद्म-LRU योजना का उपयोग करता है जो यह तय करने के लिए कि कौन से पृष्ठ निकालने के लिए हैं ) - जबकि आप सही कैचिंग ग्रैन्युलैरिटी के बारे में बहुत कुछ जान सकते हैं और भविष्य के एक्सेस पैटर्न के बारे में भी अच्छी जानकारी रखते हैं। mmapकैशिंग के लिए वास्तविक लाभ यह है कि आप बस मौजूदा पेज कैश का फिर से उपयोग करते हैं जो पहले से ही होने वाला है, इसलिए आपको वह मेमोरी मुफ्त में मिलती है, और इसे प्रक्रियाओं में भी साझा किया जा सकता है।
BeeOnRope

2

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


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

यह पूरी तरह से काम करता है जब आपके पास एक स्थिर और स्पष्ट रूप से परिभाषित ट्री लेआउट होता है। फिर आप हर बार अपनी प्रासंगिक संरचना में सब कुछ डाल सकते हैं और हर बार "एमएमएपी स्टार्ट एड्रेस" की भरपाई करके आंतरिक फ़ाइल पॉइंटर्स का पालन कर सकते हैं। यह
इनोडेस

1

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


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

1

मुझे लगता है कि mmap के बारे में सबसे बड़ी बात अतुल्यकालिक पढ़ने के लिए संभावित है:

    addr1 = NULL;
    while( size_left > 0 ) {
        r = min(MMAP_SIZE, size_left);
        addr2 = mmap(NULL, r,
            PROT_READ, MAP_FLAGS,
            0, pos);
        if (addr1 != NULL)
        {
            /* process mmap from prev cycle */
            feed_data(ctx, addr1, MMAP_SIZE);
            munmap(addr1, MMAP_SIZE);
        }
        addr1 = addr2;
        size_left -= r;
        pos += r;
    }
    feed_data(ctx, addr1, r);
    munmap(addr1, r);

समस्या यह है कि मुझे संकेत देने के लिए सही MAP_FLAGS नहीं मिल रहा है कि यह स्मृति फ़ाइल asap से सिंक की जानी चाहिए। मुझे आशा है कि MAP_POPULATE mmap के लिए सही संकेत देता है (यानी यह कॉल से लौटने से पहले सभी सामग्रियों को लोड करने की कोशिश नहीं करेगा, लेकिन ऐसा async में feed_data के साथ करेगा)। इस ध्वज के साथ कम से कम यह बेहतर परिणाम देता है यहां तक ​​कि मैनुअल भी कहता है कि यह 2.6.23 के बाद से MAP_PRIVATE के बिना कुछ भी नहीं करता है।


1
आप ध्वज के posix_madviseसाथWILLNEED ध्वज को संकेत देने के लिए चाहते हैं ।
शैडो रेंजर

@ShadowRanger, उचित लगता है। हालाँकि मैं स्पष्ट रूप से posix_madviseयह बताने के लिए मैन पेज को अपडेट करूंगा कि यह async कॉल है। mlockउन लोगों के लिए भी संदर्भ लेना अच्छा होगा , जो बिना किसी संपूर्ण मेमोरी क्षेत्र को प्रतीक्षा करना चाहते हैं, जो पेज दोष के बिना उपलब्ध हो जाते हैं।
ony
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.