जटर, सिस्टम के काम करने के तरीके में होने वाला अचानक बदलाव है. इसकी वजह से, सिस्टम ठीक से काम नहीं करता. इस पेज पर, वीडियो में होने वाली रुकावटों से जुड़ी समस्याओं की पहचान करने और उन्हें ठीक करने का तरीका बताया गया है.
ऐप्लिकेशन थ्रेड शेड्यूलर में देरी
शेड्यूलर में देरी, जिटर का सबसे साफ़ लक्षण है: जिस प्रोसेस को चलाया जाना चाहिए उसे चलाने लायक बनाया जाता है, लेकिन वह कुछ समय तक नहीं चलती. देरी की अहमियत, संदर्भ के हिसाब से अलग-अलग होती है. उदाहरण के लिए:
- किसी ऐप्लिकेशन में, किसी भी हेल्पर थ्रेड को बिना किसी समस्या के कई मिलीसेकंड तक रोका जा सकता है.
- ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई) थ्रेड, 1 से 2 मिलीसेकंड तक के जिटर को बर्दाश्त कर सकता है.
- SCHED_FIFO के तौर पर चलने वाले ड्राइवर के kthread, 500us तक चलने से पहले, समस्याएं पैदा कर सकते हैं.
systrace में, किसी थ्रेड के चल रहे सेगमेंट से पहले मौजूद नीले बार से, रन होने में लगने वाले समय की पहचान की जा सकती है. किसी थ्रेड के लिए sched_wakeup
इवेंट और sched_switch
इवेंट के बीच के समय से भी, रन होने में लगने वाला समय तय किया जा सकता है. sched_switch
इवेंट, थ्रेड के शुरू होने का सिग्नल देता है.
बहुत लंबे समय तक चलने वाली थ्रेड
ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) की ऐसी थ्रेड जो बहुत देर तक चलती हैं, उनसे समस्याएं हो सकती हैं. आम तौर पर, लंबे समय तक चलने वाली लोअर-लेवल थ्रेड की अलग-अलग वजहें होती हैं. हालांकि, यूज़र इंटरफ़ेस (यूआई) थ्रेड के चलने में लगने वाले समय को शून्य पर ले जाने की कोशिश करने पर, उन समस्याओं को ठीक करना पड़ सकता है जिनकी वजह से लोअर-लेवल थ्रेड के चलने में लंबा समय लगता है. देरी को कम करने के लिए:
- थर्मल ट्रॉथलिंग में बताए गए तरीके से, cpuset का इस्तेमाल करें.
- CONFIG_HZ की वैल्यू बढ़ाएं.
- अब तक, arm और arm64 प्लैटफ़ॉर्म पर इस वैल्यू को 100 पर सेट किया गया है. हालांकि, यह इतिहास की एक गड़बड़ी है और इंटरैक्टिव डिवाइसों के लिए इसका इस्तेमाल करना सही नहीं है. CONFIG_HZ=100 का मतलब है कि एक jiffies 10 मिलीसेकंड का होता है. इसका मतलब है कि सीपीयू के बीच लोड बैलेंसिंग में 20 मिलीसेकंड (दो jiffies) लग सकते हैं. इससे, लोड किए गए सिस्टम पर jank की समस्या काफ़ी बढ़ सकती है.
- हाल ही में लॉन्च हुए डिवाइसों (Nexus 5X, Nexus 6P, Pixel, और Pixel XL) में, CONFIG_HZ=300 सेट है. इससे, रनिंग के समय में काफ़ी सुधार होता है. साथ ही, बिजली की खपत भी बहुत कम होती है. अगर CONFIG_HZ में बदलाव करने के बाद, बिजली की खपत में काफ़ी बढ़ोतरी होती है या परफ़ॉर्मेंस से जुड़ी समस्याएं आती हैं, तो हो सकता है कि आपका कोई ड्राइवर, मिलीसेकंड के बजाय रॉ jiffies पर आधारित टाइमर का इस्तेमाल कर रहा हो और उसे jiffies में बदल रहा हो. आम तौर पर, इसे आसानी से ठीक किया जा सकता है. CONFIG_HZ=300 पर बदलने के दौरान, Nexus 5X और 6P पर kgsl टाइमर की समस्याओं को ठीक करने वाला पैच देखें.
- आखिर में, हमने Nexus/Pixel पर CONFIG_HZ=1000 के साथ प्रयोग किया है. इससे हमें पता चला है कि आरसीयू के ओवरहेड में कमी आने की वजह से, डिवाइस की परफ़ॉर्मेंस बेहतर होती है और बिजली की खपत कम होती है.
सिर्फ़ इन दो बदलावों से, किसी डिवाइस पर यूज़र इंटरफ़ेस (यूआई) थ्रेड के लोड होने में लगने वाले समय में काफ़ी सुधार दिखेगा.
sys.use_fifo_ui का इस्तेमाल करना
sys.use_fifo_ui
प्रॉपर्टी को 1 पर सेट करके, यूज़र इंटरफ़ेस (यूआई) थ्रेड के चलने में लगने वाले समय को शून्य पर लाया जा सकता है.
चेतावनी: अलग-अलग सीपीयू कॉन्फ़िगरेशन पर इस विकल्प का इस्तेमाल तब तक न करें, जब तक आपके पास क्षमता के हिसाब से आरटी शेड्यूलर न हो.
फ़िलहाल, फ़िलहाल शिपिंग आरटी शेड्यूलर में, शिपिंग की क्षमता के बारे में जानकारी नहीं होती. हम ईएएस के लिए एक ऐप्लिकेशन पर काम कर रहे हैं, लेकिन यह अभी उपलब्ध नहीं है. डिफ़ॉल्ट आरटी शेड्यूलर, पूरी तरह से आरटी प्राथमिकताओं पर आधारित होता है. साथ ही, यह इस बात पर भी निर्भर करता है कि सीपीयू में पहले से ही, आरटी थ्रेड की प्राथमिकता बराबर या उससे ज़्यादा है या नहीं.
इस वजह से, डिफ़ॉल्ट आरटी शेड्यूलर, आपके UI थ्रेड को कम फ़्रीक्वेंसी वाले छोटे कोर से, ज़्यादा फ़्रीक्वेंसी वाले बड़े कोर पर ले जाएगा. ऐसा तब होगा, जब उसी बड़े कोर पर कोई ज़्यादा प्राथमिकता वाला FIFO kthread चालू हो. इससे परफ़ॉर्मेंस में काफ़ी गिरावट आएगी. इस विकल्प का इस्तेमाल, शिपिंग के लिए इस्तेमाल किए जाने वाले Android डिवाइस पर अब तक नहीं किया गया है. अगर आपको इसका इस्तेमाल करना है, तो पुष्टि करने के लिए Android की परफ़ॉर्मेंस टीम से संपर्क करें.
sys.use_fifo_ui
चालू होने पर, ActivityManager सबसे ज़्यादा इस्तेमाल किए जाने वाले ऐप्लिकेशन की UI टारगेट करने वाली थ्रेड और RenderThread (ये दोनों थ्रेड, यूज़र इंटरफ़ेस के लिए सबसे ज़्यादा ज़रूरी हैं) को ट्रैक करता है. साथ ही, इन थ्रेड को SCHED_OTHER के बजाय SCHED_FIFO बनाता है. इससे यूज़र इंटरफ़ेस (यूआई) और रेंडर थ्रेड से, झटके या फ़्लिकर की समस्या को पूरी तरह से खत्म किया जा सकता है. इस विकल्प के चालू होने पर, हमें मिले ट्रेस से पता चलता है कि ऐप्लिकेशन को चलाने में लगने वाला समय, मिलीसेकंड के बजाय माइक्रोसेकंड में है.
हालांकि, आरटी लोड बैलेंसर में कैपेसिटी के बारे में जानकारी नहीं थी. इसलिए, ऐप्लिकेशन के शुरू होने की परफ़ॉर्मेंस में 30% की गिरावट आई. इसकी वजह यह थी कि ऐप्लिकेशन को शुरू करने के लिए ज़िम्मेदार यूज़र इंटरफ़ेस (यूआई) थ्रेड को 2.1 गीगाहर्ट्ज़ के गोल्ड क्रियो कोर से 1.5 गीगाहर्ट्ज़ के सिल्वर क्रियो कोर पर ले जाया गया था. क्षमता के हिसाब से काम करने वाले आरटी लोड बैलेंसर की मदद से, हमें एक साथ कई कार्रवाइयों में पहले जैसी परफ़ॉर्मेंस दिखती है. साथ ही, हमारे कई यूज़र इंटरफ़ेस (यूआई) मानदंडों में 95वें और 99वें प्रतिशत वाले फ़्रेम टाइम में 10 से 15% की कमी आई है.
ट्रैफ़िक में रुकावट
ARM प्लैटफ़ॉर्म, डिफ़ॉल्ट रूप से सिर्फ़ सीपीयू 0 पर इंटरप्ट डिलीवर करते हैं. इसलिए, हमारा सुझाव है कि आप IRQ बैलेंसर (Qualcomm प्लैटफ़ॉर्म पर irqbalance या msm_irqbalance) का इस्तेमाल करें.
Pixel के डेवलपमेंट के दौरान, हमें रुकावटें मिलीं. इन रुकावटों की वजह सीधे तौर पर, सीपीयू 0 को रुकावटों से परेशान करना था. उदाहरण के लिए, अगर mdss_fb0
थ्रेड को सीपीयू 0 पर शेड्यूल किया गया था, तो स्कैनआउट से ठीक पहले डिसप्ले से ट्रिगर होने वाले किसी रुकावट की वजह से, jank की संभावना ज़्यादा थी. mdss_fb0
अपने काम के बीच में होगा और उसके पास तय समय में काम पूरा करने के लिए बहुत कम समय होगा. ऐसे में, MDSS के इंटरप्ट हैंडलर की वजह से उसे कुछ समय लगेगा. शुरुआत में, हमने mdss_fb0 थ्रेड के सीपीयू अफ़िनिटी को सीपीयू 1 से 3 पर सेट करके, इस समस्या को ठीक करने की कोशिश की, ताकि इंटरप्ट से होने वाली समस्या से बचा जा सके. हालांकि, हमें पता चला कि हमने अब तक msm_irqbalance को चालू नहीं किया था. msm_irqbalance चालू होने पर, अन्य इंटरप्ट की वजह से होने वाली रुकावट कम होने की वजह से, mdss_fb0 और MDSS इंटरप्ट, दोनों एक ही सीपीयू पर होने के बावजूद, jank में काफ़ी सुधार हुआ.
sched सेक्शन और irq सेक्शन को देखकर, systrace में इसकी पहचान की जा सकती है. शेड्यूल सेक्शन में, शेड्यूल की गई प्रोसेस दिखती है. हालांकि, irq सेक्शन में ओवरलैप होने वाले क्षेत्र का मतलब है कि शेड्यूल की गई सामान्य प्रोसेस के बजाय, उस समय कोई इंटरप्ट चल रहा है. अगर आपको रुकावट के दौरान काफ़ी समय दिखता है, तो आपके पास ये विकल्प हैं:
- इंटरप्ट हैंडलर को तेज़ बनाएं.
- रुकावट को शुरू होने से रोकें.
- रुकावट की फ़्रीक्वेंसी बदलें, ताकि वह उस सामान्य काम के फ़ेज़ से बाहर हो जिससे रुकावट आ रही है.
- सीपीयू के लिए, सीधे तौर पर रुकावट की प्राथमिकता सेट करें और इसे संतुलित होने से रोकें.
- जिस थ्रेड में रुकावट आ रही है उसके लिए सीपीयू अफ़िनिटी सेट करें, ताकि रुकावट से बचा जा सके.
- इंटरप्ट को कम लोड वाले सीपीयू पर ले जाने के लिए, इंटरप्ट बैलेंसर का इस्तेमाल करें.
आम तौर पर, सीपीयू अफ़िनिटी सेट करने का सुझाव नहीं दिया जाता. हालांकि, यह कुछ खास मामलों में काम का हो सकता है. आम तौर पर, ज़्यादातर सामान्य रुकावटों के लिए, सिस्टम की स्थिति का अनुमान लगाना बहुत मुश्किल होता है. हालांकि, अगर आपके पास कुछ खास शर्तों का सेट है, जो कुछ रुकावटों को ट्रिगर करता है, जहां सिस्टम सामान्य से ज़्यादा सीमित होता है (जैसे कि वीआर), तो सीपीयू अफ़िनिटी एक अच्छा समाधान हो सकता है.
लंबे सॉफ़्टइर्क़
सॉफ़्ट-इआरक्यू चलने के दौरान, यह प्रीएमप्शन को बंद कर देता है. सॉफ़्ट-इआरक्यू को कर्नेल में कई जगहों पर ट्रिगर किया जा सकता है और यह यूज़र प्रोसेस के अंदर चल सकता है. अगर सॉफ़्टइआरक की गतिविधि ज़्यादा है, तो उपयोगकर्ता प्रोसेस सॉफ़्टइआरक को चलाना बंद कर देंगी. साथ ही, सॉफ़्टइआरक को चलाने और लोड को बैलेंस करने के लिए, ksoftirqd चालू हो जाएगा. आम तौर पर, ऐसा करना ठीक है. हालांकि, एक बहुत लंबा सॉफ़्टइर्क् सिस्टम पर असर डाल सकता है.
softirqs, ट्रैक के irq सेक्शन में दिखते हैं. इसलिए, अगर ट्रैकिंग के दौरान समस्या दोबारा आती है, तो उन्हें आसानी से देखा जा सकता है. सॉफ़्टइआरक किसी उपयोगकर्ता प्रोसेस में चल सकता है. इसलिए, कोई खराब सॉफ़्टइआरक, बिना किसी वजह के उपयोगकर्ता प्रोसेस में अतिरिक्त रनटाइम के तौर पर भी दिख सकता है. अगर आपको ऐसा दिखता है, तो irq सेक्शन देखें और पता लगाएं कि क्या softirqs की वजह से ऐसा हो रहा है.
ड्राइवर, प्रीएमेशन या IRQs को बहुत लंबे समय तक बंद रखते हैं
प्रीएमेशन को बंद करने या बहुत ज़्यादा समय (दसियों मिलीसेकंड) के लिए रुकावट डालने पर, वीडियो में रुकावट आती है. आम तौर पर, जब कोई थ्रेड रन होने के लिए तैयार हो जाती है, लेकिन किसी सीपीयू पर नहीं चलती है, तब उसे जंक कहा जाता है. भले ही, रन होने के लिए तैयार थ्रेड, दूसरी थ्रेड की तुलना में ज़्यादा प्राथमिकता (या SCHED_FIFO) वाली हो.
कुछ दिशा-निर्देश:
- अगर चलने वाली थ्रेड SCHED_FIFO है और चल रही थ्रेड SCHED_OTHER है, तो चल रही थ्रेड में प्रीएमेशन या इंटरप्ट की सुविधा बंद है.
- अगर चल रही थ्रेड (120) की तुलना में, चलने वाली थ्रेड की प्राथमिकता (100) काफ़ी ज़्यादा है, तो हो सकता है कि चल रही थ्रेड में प्री-एंपशन या इंटरप्ट की सुविधा बंद हो. ऐसा तब होता है, जब चलने वाली थ्रेड दो jiffies में नहीं चलती.
- अगर चलने वाली थ्रेड और चल रही थ्रेड की प्राथमिकता एक जैसी है, तो हो सकता है कि चल रही थ्रेड में, पहले से चल रही प्रोसेस को रोकने या रुकावट डालने की सुविधा बंद हो. ऐसा तब होता है, जब चलने वाली थ्रेड 20 मिलीसेकंड के अंदर न चले.
ध्यान रखें कि किसी इंटरप्ट हैंडलर को चलाने से, आपको अन्य इंटरप्ट की सेवा करने से रोका जाता है. इससे, प्रीएमप्शन भी बंद हो जाता है.
समस्या वाले हिस्सों की पहचान करने के लिए, preemptirqsoff ट्रैसर का इस्तेमाल भी किया जा सकता है. डाइनैमिक ftrace का इस्तेमाल करना लेख पढ़ें. यह ट्रेसर, फ़ंक्शन के नाम जैसे किसी ऐसे क्षेत्र के मूल कारण के बारे में ज़्यादा जानकारी दे सकता है जिसे बीच में नहीं रोका जा सकता. हालांकि, इसे चालू करने के लिए ज़्यादा काम करना पड़ता है. इससे परफ़ॉर्मेंस पर ज़्यादा असर पड़ सकता है. हालांकि, इसे आज़माना ज़रूर फ़ायदेमंद है.
वर्कक्वे का गलत इस्तेमाल
इंटरप्ट हैंडलर को अक्सर ऐसा काम करना पड़ता है जो इंटरप्ट कॉन्टेक्स्ट के बाहर चल सकता है. इससे, कर्नेल में अलग-अलग थ्रेड में काम किया जा सकता है. ड्राइवर डेवलपर को पता चल सकता है कि कर्नेल में workqueues नाम का एक ऐसा फ़ंक्शन है जो सिस्टम के लिए, एक साथ कई टास्क करने की सुविधा देता है. इस फ़ंक्शन का इस्तेमाल, रुकावट से जुड़े काम के लिए किया जा सकता है.
हालांकि, इस समस्या के लिए वर्कक्वे हमेशा गलत जवाब होते हैं, क्योंकि वे हमेशा SCHED_OTHER होते हैं. कई हार्डवेयर इंटरप्ट, परफ़ॉर्मेंस के क्रिटिकल पाथ में होते हैं और इन्हें तुरंत चलाया जाना चाहिए. वर्कक्वे को कब चलाया जाएगा, इसकी कोई गारंटी नहीं है. जब भी हमें परफ़ॉर्मेंस के क्रिटिकल पाथ में वर्कक्वे मौजूद मिला है, तो डिवाइस के बावजूद, कभी-कभी रुकावट आती रही है. हमने फ़्लैगशिप प्रोसेसर वाले Pixel डिवाइस पर देखा कि अगर डिवाइस पर लोड है, तो एक वर्कक्वे को प्रोसेस होने में 7 मिलीसेकंड तक लग सकते हैं. यह समय, शेड्यूलर के व्यवहार और सिस्टम पर चल रही अन्य चीज़ों पर निर्भर करता है.
जिन ड्राइवरों को किसी अलग थ्रेड में, रुकावट जैसा काम मैनेज करना है उन्हें वर्कक्वे के बजाय, अपना SCHED_FIFO kthread बनाना चाहिए. kthread_work फ़ंक्शन की मदद से ऐसा करने के लिए, यह पैच देखें.
फ़्रेमवर्क लॉक का विवाद
फ़्रेमवर्क लॉक कॉन्टेंटेशन, परफ़ॉर्मेंस में रुकावट या अन्य समस्याओं का सोर्स हो सकता है. आम तौर पर, यह ActivityManagerService लॉक की वजह से होता है. हालांकि, यह अन्य लॉक में भी दिख सकता है. उदाहरण के लिए, PowerManagerService लॉक से स्क्रीन की परफ़ॉर्मेंस पर असर पड़ सकता है. अगर आपको अपने डिवाइस पर यह गड़बड़ी दिख रही है, तो इसे ठीक करने का कोई अच्छा तरीका नहीं है. ऐसा इसलिए है, क्योंकि इसे सिर्फ़ फ़्रेमवर्क के आर्किटेक्चर में सुधार करके ठीक किया जा सकता है. हालांकि, अगर system_server में चलने वाले कोड में बदलाव किया जा रहा है, तो लॉक को लंबे समय तक होल्ड करने से बचना ज़रूरी है. खास तौर पर, ActivityManagerService लॉक को.
Binder लॉक का विवाद
पहले, बाइंडर में एक ग्लोबल लॉक होता था. अगर लॉक रखने के दौरान, बिंडर लेन-देन को चलाने वाली थ्रेड को रोक दिया गया था, तो कोई भी दूसरी थ्रेड तब तक बिंडर लेन-देन नहीं कर सकती, जब तक ओरिजनल थ्रेड लॉक को रिलीज़ नहीं कर देती. यह खराब है; बाइंडर कॉन्टेंटेंस, सिस्टम में मौजूद सभी चीज़ों को ब्लॉक कर सकता है. इनमें डिसप्ले पर यूज़र इंटरफ़ेस (यूआई) अपडेट भेजना भी शामिल है. यूआई थ्रेड, बाइंडर के ज़रिए SurfaceFlinger के साथ कम्यूनिकेट करते हैं.
Android 6.0 में इस व्यवहार को बेहतर बनाने के लिए कई पैच शामिल किए गए हैं. इन पैच की मदद से, बाइंडर लॉक को दबाकर, प्रीइंप्रेशन को बंद किया जा सकता है. यह सिर्फ़ इसलिए सुरक्षित था, क्योंकि बाइंडर के लॉक को रनटाइम के कुछ माइक्रोसेकंड के लिए ही रखा जाना चाहिए. इससे, बिना किसी रुकावट के काम करने की स्थितियों में परफ़ॉर्मेंस काफ़ी बेहतर हुई. साथ ही, बाइंडर लॉक होने के दौरान शेड्यूलर के ज़्यादातर स्विच को रोककर, रुकावट को रोका गया. हालांकि, बिंडर लॉक को होल्ड करने के पूरे रनटाइम के लिए, प्रीएमेशन को बंद नहीं किया जा सका. इसका मतलब है कि प्रीएमेशन उन फ़ंक्शन के लिए चालू था जो स्लीप कर सकते थे (जैसे, copy_from_user). इस वजह से, ओरिजनल केस की तरह ही प्रीएमेशन हो सकता था. जब हमने पैच को अपस्ट्रीम भेजा, तो उन्होंने तुरंत हमें बताया कि यह इतिहास का सबसे खराब आइडिया था. (हम उनके साथ सहमत थे, लेकिन हम इस बात से भी सहमत नहीं थे कि पैच लगाने से, ऐप्लिकेशन में होने वाली रुकावट को रोका जा सकता है.)
fd contention within a process
ऐसा बहुत कम होता है. ऐसा हो सकता है कि इसकी वजह से आपको झटके न महसूस हों.
हालांकि, अगर किसी प्रोसेस में एक ही फ़ाइल डिस्क्रिप्टर (एफ़डी) लिखने वाली कई थ्रेड हैं, तो इस एफ़डी पर कॉन्टेंटशन दिख सकता है. हालांकि, Pixel के शुरू होने के दौरान, हमें यह सिर्फ़ एक टेस्ट के दौरान दिखी. इस टेस्ट में, कम प्राथमिकता वाली थ्रेड ने एक ही प्रोसेस में चल रही एक ही प्राथमिकता वाली थ्रेड के दौरान, सीपीयू का पूरा समय इस्तेमाल करने की कोशिश की. सभी थ्रेड, ट्रेस मार्कर fd में लिख रहे थे. अगर कम प्राथमिकता वाली थ्रेड के पास fd लॉक था और फिर उसे प्रीमप्ट कर दिया गया, तो ज़्यादा प्राथमिकता वाली थ्रेड, ट्रेस मार्कर fd पर ब्लॉक हो सकती थी. कम प्राथमिकता वाली थ्रेड से ट्रैकिंग बंद करने पर, परफ़ॉर्मेंस से जुड़ी कोई समस्या नहीं हुई.
हमने किसी और स्थिति में इस समस्या को दोहरा नहीं पाए. हालांकि, यह बताना ज़रूरी है कि ट्रैक करते समय परफ़ॉर्मेंस से जुड़ी समस्याओं की संभावित वजह यह हो सकती है.
सीपीयू के गै़र-ज़रूरी ट्रांज़िशन
आईपीसी, खास तौर पर मल्टी-प्रोसेस पाइपलाइन के साथ काम करते समय, रनटाइम के व्यवहार में ये बदलाव देखे जा सकते हैं:
- थ्रेड A, सीपीयू 1 पर चलता है.
- थ्रेड A, थ्रेड B को जगाती है.
- थ्रेड B, सीपीयू 2 पर चलने लगती है.
- थ्रेड A तुरंत स्लीप मोड में चली जाती है. थ्रेड B के अपना मौजूदा काम पूरा करने के बाद, वह थ्रेड A को जगाएगी.
ओवरहेड का एक आम सोर्स, दूसरे और तीसरे चरण के बीच होता है. अगर सीपीयू 2 निष्क्रिय है, तो थ्रेड B को चलाने से पहले, इसे फिर से चालू किया जाना चाहिए. एसओसी और इंतज़ार की अवधि के आधार पर, थ्रेड B के शुरू होने में 10 माइक्रोसेकंड लग सकते हैं. अगर आईपीसी के हर हिस्से का असल रनटाइम, ओवरहेड के करीब है, तो सीपीयू के आइडल ट्रांज़िशन की वजह से, उस पाइपलाइन की कुल परफ़ॉर्मेंस काफ़ी कम हो सकती है. Android पर, आम तौर पर बाइंडर ट्रांज़ैक्शन के दौरान यह समस्या आती है. साथ ही, बाइंडर का इस्तेमाल करने वाली कई सेवाओं में भी ऊपर बताई गई समस्या दिखती है.
सबसे पहले, अपने कर्नल ड्राइवर में wake_up_interruptible_sync()
फ़ंक्शन का इस्तेमाल करें और इसे किसी भी कस्टम शेड्यूलर से इस्तेमाल करें. इसे एक सुझाव के बजाय ज़रूरी शर्त के तौर पर लें. फ़िलहाल, Binder इसका इस्तेमाल करता है. इससे, सिंक्रोनस बाइंडर लेन-देन में काफ़ी मदद मिलती है. साथ ही, सीपीयू के ग़ैर-ज़रूरी ट्रांज़िशन से भी बचा जा सकता है.
दूसरा, पक्का करें कि आपके cpuidle ट्रांज़िशन टाइम सही हों और cpuidle गवर्नर इनका सही तरीके से इस्तेमाल कर रहा हो. अगर आपका SOC, सबसे कम बिजली खर्च करने वाली स्थिति में बार-बार ट्रैश हो रहा है, तो सबसे कम बिजली खर्च करने वाली स्थिति में जाने से बिजली की बचत नहीं होगी.
लॉग इन हो रहा है
सीपीयू साइकल या मेमोरी के लिए, लॉगिंग की सुविधा बिना किसी शुल्क के उपलब्ध नहीं है. इसलिए, लॉग बफ़र को स्पैम न करें. आपके ऐप्लिकेशन (सीधे) और लॉग डेमन में लॉगिंग की लागत के साइकल. डिवाइस को शिप करने से पहले, डीबगिंग लॉग हटा दें.
इनपुट/आउटपुट से जुड़ी समस्याएं
I/O ऑपरेशन, सामान्य तौर पर फ़्रेम रेट में उतार-चढ़ाव की वजह होते हैं. अगर कोई थ्रेड, मेमोरी मैप की गई फ़ाइल को ऐक्सेस करता है और पेज, पेज कैश मेमोरी में नहीं है, तो वह गड़बड़ी दिखाता है और पेज को डिस्क से पढ़ता है. इससे थ्रेड को ब्लॉक किया जाता है (आम तौर पर 10 से ज़्यादा मिलीसेकंड के लिए). अगर यह यूज़र इंटरफ़ेस (यूआई) रेंडर करने के क्रिटिकल पाथ में होता है, तो रुकावट आ सकती है. I/O ऑपरेशन की कई वजहें हो सकती हैं. हालांकि, I/O व्यवहार को बेहतर बनाने के लिए, यहां दी गई जगहों पर जाएं:
- PinnerService. PinnerService को Android 7.0 में जोड़ा गया है. इससे फ़्रेमवर्क, पेज कैश मेमोरी में कुछ फ़ाइलों को लॉक कर सकता है. इससे, किसी भी दूसरी प्रोसेस के इस्तेमाल के लिए मेमोरी हट जाती है. हालांकि, अगर कुछ ऐसी फ़ाइलें हैं जिनका इस्तेमाल नियमित तौर पर किया जाता है, तो उन फ़ाइलों को mlock करने से फ़ायदा मिल सकता है.
हमने Android 7.0 पर काम करने वाले Pixel और Nexus 6P डिवाइसों पर, चार फ़ाइलों को लॉक कर दिया है:- /system/framework/arm64/boot-framework.oat
- /system/framework/oat/arm64/services.odex
- /system/framework/arm64/boot.oat
- /system/framework/arm64/boot-core-libart.oat
- एन्क्रिप्शन (सुरक्षित) करने का तरीका. I/O से जुड़ी समस्याओं की एक और संभावित वजह. हमें पता चला है कि सीपीयू पर आधारित एन्क्रिप्शन या डीएमए के ज़रिए ऐक्सेस किए जा सकने वाले हार्डवेयर ब्लॉक का इस्तेमाल करने की तुलना में, इनलाइन एन्क्रिप्शन सबसे अच्छी परफ़ॉर्मेंस देता है. सबसे ज़रूरी बात यह है कि इनलाइन एन्क्रिप्शन, I/O से जुड़ी गड़बड़ी को कम करता है. खास तौर पर, सीपीयू पर आधारित एन्क्रिप्शन की तुलना में. पेज कैश मेमोरी में फ़ेच करने की प्रोसेस, अक्सर यूज़र इंटरफ़ेस (यूआई) रेंडर करने के क्रिटिकल पाथ में होती है. इसलिए, सीपीयू पर आधारित एन्क्रिप्शन, क्रिटिकल पाथ में सीपीयू का अतिरिक्त लोड जोड़ता है. इससे, सिर्फ़ I/O फ़ेच के मुकाबले ज़्यादा फ़्रीज़िंग होती है.
डीएमए पर आधारित हार्डवेयर एन्क्रिप्शन इंजन में भी यही समस्या होती है. इसकी वजह यह है कि कर्नेल को उस काम को मैनेज करने में साइकल खर्च करने पड़ते हैं, भले ही कोई और ज़रूरी काम करने के लिए उपलब्ध हो. हमारा सुझाव है कि एसओसी वेंडर, नया हार्डवेयर बनाते समय इनलाइन एन्क्रिप्शन की सुविधा शामिल करें.
छोटे टास्क को तेज़ी से पैक करना
कुछ शेड्यूलर, छोटे टास्क को एक सीपीयू कोर पर पैक करने की सुविधा देते हैं. इससे, ज़्यादा सीपीयू को लंबे समय तक निष्क्रिय रखकर, बिजली की खपत कम की जा सकती है. यह तरीका, डेटा ट्रांज़िट और बिजली की खपत के लिए अच्छा काम करता है. हालांकि, इससे इंतज़ार का समय काफ़ी ज़्यादा हो सकता है. यूज़र इंटरफ़ेस (यूआई) रेंडरिंग के क्रिटिकल पाथ में, कुछ ऐसी थ्रेड होती हैं जो कम समय तक चलती हैं और जिन्हें छोटा माना जा सकता है. अगर इन थ्रेड को दूसरे सीपीयू पर धीरे-धीरे माइग्रेट करने की वजह से देरी होती है, तो इससे जैंक की समस्या हो सकती है. हमारा सुझाव है कि छोटे टास्क को बहुत सावधानी से पैक करें.
पेज कैश थ्रैशिंग
अगर किसी डिवाइस में ज़रूरत के मुताबिक खाली मेमोरी नहीं है, तो हो सकता है कि कोई लंबी प्रक्रिया पूरी करने के दौरान, वह अचानक बहुत धीमा हो जाए. जैसे, कोई नया ऐप्लिकेशन खोलना. ऐप्लिकेशन के ट्रैक से पता चल सकता है कि किसी खास प्रोसेस के दौरान, वह I/O में लगातार ब्लॉक रहता है. भले ही, वह अक्सर I/O में ब्लॉक न होता हो. आम तौर पर, यह पेज कैश मेमोरी के ज़्यादा इस्तेमाल का संकेत होता है. ऐसा खास तौर पर, कम मेमोरी वाले डिवाइसों पर होता है.
इसकी पहचान करने का एक तरीका यह है कि pagecache टैग का इस्तेमाल करके, सिस्टम ट्रेस करें और उस ट्रेस को system/extras/pagecache/pagecache.py
पर मौजूद स्क्रिप्ट में फ़ीड करें. pagecache.py, फ़ाइलों को पेज कैश मेमोरी में मैप करने के लिए किए गए अलग-अलग अनुरोधों को, हर फ़ाइल के लिए एग्रीगेट किए गए आंकड़ों में बदल देता है. अगर आपको पता चलता है कि किसी फ़ाइल के ज़्यादा बाइट पढ़े गए हैं, तो इसका मतलब है कि पेज कैश थ्रैशिंग हो रही है.
इसका मतलब है कि आपके वर्कलोड (आम तौर पर, एक ऐप्लिकेशन और system_server) के लिए ज़रूरी वर्किंग सेट, आपके डिवाइस पर पेज कैश मेमोरी से ज़्यादा है. इस वजह से, जब वर्कलोड के एक हिस्से को पेज कैश में ज़रूरी डेटा मिल जाता है, तो आने वाले समय में इस्तेमाल किए जाने वाले दूसरे हिस्से को हटा दिया जाएगा और उसे फिर से फ़ेच करना होगा. इससे, लोड पूरा होने तक समस्या फिर से हो सकती है. जब किसी डिवाइस में ज़रूरत के मुताबिक मेमोरी उपलब्ध नहीं होती, तो परफ़ॉर्मेंस से जुड़ी समस्याएं होने की मुख्य वजह यही होती है.
पेज कैश थ्रैशिंग को ठीक करने का कोई ऐसा तरीका नहीं है जो हर बार काम करे. हालांकि, किसी डिवाइस पर इसे ठीक करने के कुछ तरीके हैं.
- लगातार चलने वाली प्रोसेस में कम मेमोरी का इस्तेमाल करें. अगर लगातार चलने वाली प्रोसेस कम मेमोरी का इस्तेमाल करती हैं, तो ऐप्लिकेशन और पेज कैश मेमोरी के लिए ज़्यादा मेमोरी उपलब्ध होगी.
- अपने डिवाइस के लिए, कैर्वआउट की ऑडिट करें. इससे यह पक्का किया जा सकता है कि आपने ओएस से ज़रूरत से ज़्यादा मेमोरी न हटाई हो. हमने ऐसे मामले देखे हैं जहां डीबग करने के लिए इस्तेमाल किए गए carveouts को गलती से शिपिंग कर्नेल कॉन्फ़िगरेशन में छोड़ दिया गया था. इससे, ज़्यादा मेमोरी का इस्तेमाल हुआ. इससे पेज कैश मेमोरी का इस्तेमाल कम या ज़्यादा हो सकता है. खास तौर पर, कम मेमोरी वाले डिवाइसों पर.
- अगर आपको ज़रूरी फ़ाइलों के लिए, system_server में पेज कैश थ्रैशिंग दिख रही है, तो उन फ़ाइलों को पिन करें. इससे मेमोरी का दबाव कहीं और बढ़ जाएगा, लेकिन ट्रैशिंग से बचने के लिए, व्यवहार में काफ़ी बदलाव हो सकता है.
- ज़्यादा मेमोरी खाली रखने के लिए, lowmemorykiller को फिर से ट्यून करें. lowmemorykiller के थ्रेशोल्ड, पूरी तरह से खाली मेमोरी और पेज कैश, दोनों पर आधारित होते हैं. इसलिए, किसी दिए गए oom_adj लेवल पर प्रोसेस को बंद करने के थ्रेशोल्ड को बढ़ाने से, बैकग्राउंड में ऐप्लिकेशन के बंद होने की संख्या बढ़ने के बावजूद, बेहतर परफ़ॉर्मेंस मिल सकती है.
- ZRAM का इस्तेमाल करें. हम Pixel पर ZRAM का इस्तेमाल करते हैं, भले ही Pixel में 4 जीबी रैम हो. ऐसा इसलिए किया जाता है, क्योंकि इससे कभी-कभी इस्तेमाल किए जाने वाले ग़ैर-ज़रूरी पेजों को मैनेज करने में मदद मिल सकती है.