c - क्या कंपाइलर्स को ऑप्टिमाइज़-आउट रीयललोक की अनुमति है?




gcc clang (4)

मैं एक ऐसी स्थिति में आया था, जहां realloc कॉल को बाहर अनुकूलित करने के लिए अनावश्यक कॉल करना उपयोगी होगा। हालाँकि, ऐसा लगता है कि न तो कोई godbolt और न ही इस तरह का ( godbolt )। - हालांकि मुझे malloc लिए कई कॉल के साथ अनुकूलन दिखाई दे रहा है।

उदाहरण:

void *myfunc() {
    void *data;
    data = malloc(100);
    data = realloc(data, 200);
    return data;
}

मुझे उम्मीद है कि यह निम्नलिखित की तरह कुछ के लिए अनुकूलित किया जाएगा:

void *myfunc() {
    return malloc(200);
}

क्लैग क्यों नहीं है और न ही इसे बाहर अनुकूलन कर रहा है? - क्या उन्हें ऐसा करने की अनुमति नहीं है?


क्या उन्हें ऐसा करने की अनुमति नहीं है?

हो सकता है, लेकिन इस मामले में नहीं किया गया अनुकूलन कोने के कार्यात्मक अंतर के कारण हो सकता है।

यदि आवंटन योग्य मेमोरी के 150 बाइट्स बने रहें,
data = malloc(100); data = realloc(data, 200); 100 बाइट्स (और लीक) और 50 शेष के साथ NULL लौटाता है।

data = malloc(200); 0 बाइट्स (कोई भी लीक नहीं हुआ) और 150 शेष के साथ NULL लौटाता है।

इस संकीर्ण मामले में विभिन्न कार्यक्षमता अनुकूलन को रोक सकती है।

क्या कंपाइलर्स को ऑप्टिमाइज़-आउट रीयललोक की अनुमति है?

शायद - मुझे उम्मीद है कि इसकी अनुमति होगी। फिर भी यह निर्धारित करने के लिए संकलक को बढ़ाने के प्रभाव के लायक नहीं हो सकता है कि वह कब कर सकता है।

सफल malloc(n); ... realloc(p, 2*n) malloc(n); ... realloc(p, 2*n) मॉलोक से भिन्न होता है malloc(2*n); जब ... हो सकता है कि कुछ मेमोरी सेट की गई हो।

यह सुनिश्चित करने के लिए कि संकलक के डिज़ाइन से परे हो सकता है ... , भले ही खाली कोड, किसी भी मेमोरी को सेट नहीं किया था।


एक कंपाइलर जो अपने स्वयं के समाहित संस्करणों को बंडल करता है Malloc / calloc / free / realloc वैध रूप से संकेतित अनुकूलन कर सकता है यदि लेखकों को लगता है कि ऐसा करने का प्रयास करने लायक था। एक कंपाइलर जो बाहरी रूप से आपूर्ति किए गए कार्यों के लिए चेन करता है, फिर भी ऐसी अनुकूलन कर सकता है अगर यह दस्तावेज करता है कि यह एक नमूदार साइड-इफेक्ट के रूप में ऐसे कार्यों के लिए कॉल का सटीक अनुक्रम नहीं मानता है, लेकिन इस तरह का उपचार थोड़ा अधिक कठिन हो सकता है।

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

void *p1 = malloc(2000000000);
void *p2 = malloc(2);
free(p1);
p2 = realloc(p2, 2000000000);

पी 2 के मुक्त होने तक पी 2 के लिए सिस्टम में 2000000000 बाइट्स उपलब्ध नहीं हो सकते हैं। यदि यह कोड बदलना था:

void *p1 = malloc(2000000000);
void *p2 = malloc(2000000000);
free(p1);

जिसके परिणामस्वरूप पी 2 के आवंटन में विफलता होगी। क्योंकि मानक कभी गारंटी नहीं देता है कि आवंटन अनुरोध सफल होंगे, ऐसा व्यवहार गैर-अनुरूप नहीं होगा। दूसरी ओर, निम्नलिखित भी एक "अनुरूप" कार्यान्वयन होगा:

void *malloc(size_t size) { return 0; }
void *calloc(size_t size, size_t count) { return 0; }
void free(void *p) {  }
void *realloc(void *p, size_t size) { return 0; }

इस तरह के कार्यान्वयन को यकीनन अन्य लोगों की तुलना में अधिक "कुशल" माना जा सकता है, लेकिन किसी को इसे बहुत उपयोगी मानने के लिए बाध्य होना पड़ेगा, शायद, दुर्लभ परिस्थितियों में जहां उपरोक्त कार्यों को कोड पथ पर कहा जाता है कभी अमल नहीं किया गया।

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


मेरी समझ यह है कि इस तरह के अनुकूलन को निषिद्ध किया जा सकता है (विशेष रूप से -indeed के लिए संभव नहीं है- मामला जहां malloc सफल होता है, लेकिन निम्नलिखित realloc विफल रहता है)।

आप मान सकते हैं कि malloc और realloc हमेशा सफल होते हैं (जो कि C11 मानक के खिलाफ है, n1570 ; मेरे मजाक-मजाक में भी देखें)। उस परिकल्पना में (सेंसु सेंसु गलत, लेकिन कुछ लिनक्स सिस्टम में उस भ्रम को देने के लिए मेमोरी ओवरकमिटमेंट है), यदि आप GCC उपयोग करते हैं, तो आप इस तरह का अनुकूलन करने के लिए अपना स्वयं का जीसीसी प्लगइन लिख सकते हैं।

मुझे यकीन नहीं है कि इस तरह के जीसीसी प्लगइन को कोड करने के लिए कुछ हफ्तों या महीनों का समय बिताने के लायक है (व्यवहार में, आप शायद यह चाहते हैं कि कभी-कभी malloc और realloc के बीच कुछ कोड को संभाल लें, और फिर यह इतना सरल नहीं है, क्योंकि आपको विशेषता देना है और पता लगाएं कि इस तरह का इन-कोड स्वीकार्य है), लेकिन वह विकल्प आपका है।


लेकिन आप पहले मॉलोक () के रिटर्न मान की जांच नहीं कर रहे हैं जो आप तब दूसरे रीयललोक () में उपयोग कर रहे हैं। यह सिर्फ NULL हो सकता है।

कंपाइलर पहले के रिटर्न वैल्यू के बारे में अनजान धारणाएं बनाए बिना दोनों कॉल को एक में कैसे ऑप्टिमाइज़ कर सकता है?

फिर एक और संभावित परिदृश्य है। FreeBSD में एक realloc() होता था जो मूल रूप से malloc + memcpy + पुराने सूचक को मुक्त करता था।

मान लीजिए कि मुफ्त मेमोरी में केवल 230 बाइट्स बचे हैं। उस क्रियान्वयन में, ptr = malloc(100) उसके बाद realloc(ptr, 200) विफल हो जाएगा, लेकिन एक भी malloc(200) सफल होगा।





compiler-optimization