कैश पॉल्यूशन: Difference between revisions

From Vigyanwiki
(Created page with "{{Short description|Performance degration due to memory access patterns}} {{Distinguish|cache poisoning}} {{More citations needed|date=January 2021}} कैश प्रद...")
 
No edit summary
Line 1: Line 1:
{{Short description|Performance degration due to memory access patterns}}
{{Short description|Performance degration due to memory access patterns}}
{{Distinguish|cache poisoning}}
{{Distinguish|cache poisoning}}कैश प्रदूषण उन स्थितियों का वर्णन करता है जहां कार्यकारी [[कंप्यूटर प्रोग्राम]] डेटा को अनावश्यक रूप से [[सीपीयू कैश]] में लोड करता है,<ref>{{Cite journal |last1=Karami |first1=Amin |last2=Guerrero-Zapata |first2=Manel |date=2015-04-07 |title=नामांकित डेटा नेटवर्किंग में कैश प्रदूषण हमलों को कम करने के लिए एक ANFIS-आधारित कैश प्रतिस्थापन विधि|url=https://linkinghub.elsevier.com/retrieve/pii/S1389128615000316 |journal=Computer Networks |language=en |volume=80 |pages=51–65 |doi=10.1016/j.comnet.2015.01.020|hdl=2117/76980 |hdl-access=free }}</ref> इस प्रकार अन्य उपयोगी डेटा को कैश से मेमोरी पदानुक्रम के न्यूनतम स्तरों में निष्कासित कर दिया जाता है, जिससे प्रदर्शन निम्नकारी होता है। उदाहरण के लिए [[मल्टी-कोर प्रोसेसर]] में, एक कोर अन्य कोर द्वारा प्राप्त किए गए ब्लॉक को सहभाजी कैश में प्रतिस्थापित कर सकता है, या प्रीफ़ेच किए गए ब्लॉक कैश से डिमांड-फ़ेच किए गए ब्लॉक को प्रतिस्थापित कर सकते हैं।
{{More citations needed|date=January 2021}}
 
कैश प्रदूषण उन स्थितियों का वर्णन करता है जहां एक निष्पादित [[कंप्यूटर प्रोग्राम]] अनावश्यक रूप से [[सीपीयू कैश]] में डेटा लोड करता है,<ref>{{Cite journal |last1=Karami |first1=Amin |last2=Guerrero-Zapata |first2=Manel |date=2015-04-07 |title=नामांकित डेटा नेटवर्किंग में कैश प्रदूषण हमलों को कम करने के लिए एक ANFIS-आधारित कैश प्रतिस्थापन विधि|url=https://linkinghub.elsevier.com/retrieve/pii/S1389128615000316 |journal=Computer Networks |language=en |volume=80 |pages=51–65 |doi=10.1016/j.comnet.2015.01.020|hdl=2117/76980 |hdl-access=free }}</ref> इस प्रकार अन्य उपयोगी डेटा को कैश से मेमोरी पदानुक्रम के निचले स्तरों में निकाल दिया जाता है, जिससे प्रदर्शन में गिरावट आती है। उदाहरण के लिए, एक [[मल्टी-कोर प्रोसेसर]] में, एक कोर अन्य कोर द्वारा लाए गए ब्लॉक को साझा कैश में बदल सकता है, या [[कैश प्रीफ़ेचिंग]] ब्लॉक कैश से मांग-प्राप्त ब्लॉक को बदल सकता है।


==उदाहरण==
==उदाहरण==
निम्नलिखित दृष्टांत पर विचार करें:
निम्नलिखित दृष्टांत पर विचार करें:
    
    
  टी[0] = टी[0] + 1;
  T[0] = T[0] + 1;
  मेरे लिए 0..[[sizeof]](CACHE) में
  for i in 0..sizeof(CACHE)
     सी[आई] = सी[आई] + 1;
     C[i] = C[i] + 1;
  टी[0] = टी[0] + सी[आकार(कैश)-1];
  T[0] = T[0] + C[sizeof(CACHE)-1];


(यहां धारणाएं यह हैं कि कैश केवल एक स्तर से बना है, यह अनलॉक है, प्रतिस्थापन नीति छद्म-एलआरयू है, सभी डेटा कैश करने योग्य है, सीपीयू कैश # कैश की एसोसिएटिविटी एन है (जहां एन> 1), और अधिकतम एक [[प्रोसेसर रजिस्टर]] प्रोग्राम मानों को शामिल करने के लिए उपलब्ध है)।
(यहां अवधारणाएं यह हैं कि कैश केवल एक स्तर से समाहित है जो अनलॉक है, प्रतिस्थापन नीति छद्म-एलआरयू है, सभी डेटा कैश करने योग्य है, कैश की सेट एसोसिएटिविटी N है (जहां N > 1), और प्रोग्राम मान सम्मिलित करने के लिए अधिकतम एक [[प्रोसेसर रजिस्टर]] उपलब्ध है)।


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


इस मामले में कैश को प्रदूषित कहा जाता है। T[0] के पहले अपडेट को लूप और दूसरे अपडेट के बीच रखकर डेटा एक्सेस के पैटर्न को बदलने से अक्षमता समाप्त हो सकती है:
इस स्थिति में कैश को "प्रदूषित" कहा जाता है। T[0] के प्रथम अपडेट को लूप और द्वितीय अपडेट के बीच स्थापन कर डेटा एक्सेस के पैटर्न को परिवर्तन करने से अक्षमता विलोपित हो सकती है:


   मेरे लिए 0..sizeof(CACHE) में
   for i in 0..sizeof(CACHE)
     सी[आई] = सी[आई] + 1;
     C[i] = C[i] + 1;
  टी[0] = टी[0] + 1;
  T[0] = T[0] + 1;
  टी[0] = टी[0] + सी[आकार(कैश)-1];
  T[0] = T[0] + C[sizeof(CACHE)-1];


==समाधान==
==हल==
ऊपर उल्लिखित कोड-पुनर्गठन के अलावा, कैश प्रदूषण का समाधान यह सुनिश्चित करना है कि कैश में केवल उच्च-पुन: उपयोग वाला डेटा संग्रहीत किया जाए। इसे विशेष कैश नियंत्रण निर्देशों, [[ऑपरेटिंग सिस्टम]] समर्थन या हार्डवेयर समर्थन का उपयोग करके प्राप्त किया जा सकता है।
उपरोक्त उल्लिखित कोड-रिस्ट्रक्टरिंग के अतिरिक्त कैश प्रदूषण का हल यह सुनिश्चित करना है कि कैश में केवल उच्च-पुन: उपयोग वाला डेटा संग्रहीत किया जाए। इसे विशेष कैश कंट्रोल इंस्ट्रक्शंस, [[ऑपरेटिंग सिस्टम]] सपोर्ट या हार्डवेयर सपोर्ट का उपयोग करके प्राप्त किया जा सकता है।


विशेष हार्डवेयर निर्देशों के उदाहरणों में [[PowerPC]] [[AltiVec]] द्वारा प्रदान किया गया lvxl शामिल है। यह निर्देश एक 128 बिट विस्तृत मान को एक रजिस्टर में लोड करता है और संबंधित कैश ब्लॉक को कम से कम हाल ही में उपयोग किए गए के रूप में चिह्नित करता है यानी अपने कैश सेट से एक ब्लॉक को कैश करने की आवश्यकता पर निष्कासन के लिए प्रमुख उम्मीदवार के रूप में। उपरोक्त उदाहरण के संदर्भ में उस निर्देश का उचित उपयोग करने के लिए, लूप द्वारा संदर्भित डेटा तत्वों को इस निर्देश का उपयोग करके लोड करना होगा। जब इस तरीके से लागू किया जाता है, तो कैश प्रदूषण नहीं होगा, क्योंकि ऐसे लूप के निष्पादन से कैश से टी [0] का समय से पहले निष्कासन नहीं होगा। इससे बचा जाएगा क्योंकि, जैसे-जैसे लूप आगे बढ़ेगा, सी में तत्वों के पते उसी कैश तरीके से मैप हो जाएंगे, जिससे वास्तव में पुराना (लेकिन कम से कम हाल ही में उपयोग किए गए के रूप में चिह्नित नहीं) डेटा दूसरे तरीके पर बरकरार रहेगा। केवल सबसे पुराना डेटा (दिए गए उदाहरण के लिए प्रासंगिक नहीं) को कैश से निकाला जाएगा, जिसका T[0] सदस्य नहीं है, क्योंकि इसका अपडेट लूप के शुरू होने से ठीक पहले होता है।
विशेष हार्डवेयर इंस्ट्रक्शंस के उदाहरणों में [[PowerPC]] [[AltiVec]] द्वारा प्रदान किया गया lvxl सम्मिलित है। यह निर्देश 128 बिट विस्तृत मान को एक रजिस्टर में लोड करता है और संबंधित कैश ब्लॉक को प्रायः वर्तमान में प्रयुक्त के रूप में, या फिर किसी ब्लॉक को उसके कैश सेट से निष्कासित की आवश्यकता पर निष्कासन के लिए प्रमुख पदान्वेषी के रूप में चिह्नित करता है। उपरोक्त उदाहरण के कॉन्टेक्ट में उस इंस्ट्रक्शन का उचित उपयोग करने के लिए लूप द्वारा रिफ्रेंस्ड डेटा एलिमेंट्स को इस इंस्ट्रक्शन का उपयोग करके लोड करना होगा। जब इस प्रकार से प्रयुक्त किया जाता है तो कैश प्रदूषण नहीं होगा क्योंकि ऐसे लूप के एक्जिक्यूशन से कैश से T [0] का समय से पूर्व इविक्शन नहीं होगा। इससे बचा जाएगा क्योंकि जैसे-जैसे लूप आगे बढ़ेगा सी में तत्वों के पते उसी कैश तरीके से मैप हो जाएंगे, जिससे वास्तव में पुराना (लेकिन "कम से कम हाल ही में उपयोग किए गए" के रूप में चिह्नित नहीं) डेटा दूसरे तरीके पर बरकरार रहेगा। केवल सबसे पुराना डेटा (दिए गए उदाहरण के लिए प्रासंगिक नहीं) को कैश से निकाला जाएगा जिसका T[0] सदस्य नहीं है क्योंकि इसका अपडेट लूप के शुरू होने से ठीक पहले होता है।


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


==बढ़ता महत्व==
==महत्वता में वृद्धि ==
कैश प्रदूषण नियंत्रण का महत्व बढ़ रहा है क्योंकि तथाकथित [[ स्मृति दीवार ]] के कारण होने वाला जुर्माना बढ़ता जा रहा है। चिप निर्माता लगातार बढ़ती सापेक्ष मेमोरी-टू-सीपीयू विलंबता को दूर करने के लिए नई तरकीबें ईजाद करना जारी रखते हैं। वे कैश आकार बढ़ाकर और सॉफ्टवेयर इंजीनियरों को सीपीयू में डेटा आने और रहने के तरीके को नियंत्रित करने के लिए उपयोगी तरीके प्रदान करके ऐसा करते हैं। कैश प्रदूषण नियंत्रण (मुख्य रूप से एम्बेडेड) प्रोग्रामर के लिए उपलब्ध कई उपकरणों में से एक है। हालाँकि, अन्य विधियाँ, जिनमें से अधिकांश मालिकाना और अत्यधिक हार्डवेयर और एप्लिकेशन विशिष्ट हैं, का भी उपयोग किया जाता है।
कैश प्रदूषण नियंत्रण के महत्व में वृद्धि हो रहा है क्योंकि तथाकथित [[ स्मृति दीवार |मेमोरी वॉल]] के कारण होने वाले दंड में वृद्धि हो रहा है। चिप निर्माता निरंतर वर्द्धमान सापेक्ष मेमोरी-टू-सीपीयू विलंबता को दूर करने के लिए अनवरत नई योजनाएं निर्माण करते हैं। वे कैश आकार में वृद्धि करके और सॉफ्टवेयर इंजीनियरों को सीपीयू में डेटा आगमन और सुरक्षित रखने के तरीके को नियंत्रित करने के लिए उपयोगी तरीके प्रदान करके ऐसा करते हैं। कैश प्रदूषण नियंत्रण (मुख्यतः अंत:स्थापित) प्रोग्रामर के लिए उपलब्ध कई उपकरणों में से एक है। यद्यपि, अन्य विधियाँ, जिनमें से अधिकांश सांपातिक और अत्यधिक हार्डवेयर और एप्लिकेशन विशिष्ट हैं, का भी उपयोग किया जाता है।


==संदर्भ==
==संदर्भ==

Revision as of 18:43, 8 August 2023

कैश प्रदूषण उन स्थितियों का वर्णन करता है जहां कार्यकारी कंप्यूटर प्रोग्राम डेटा को अनावश्यक रूप से सीपीयू कैश में लोड करता है,[1] इस प्रकार अन्य उपयोगी डेटा को कैश से मेमोरी पदानुक्रम के न्यूनतम स्तरों में निष्कासित कर दिया जाता है, जिससे प्रदर्शन निम्नकारी होता है। उदाहरण के लिए मल्टी-कोर प्रोसेसर में, एक कोर अन्य कोर द्वारा प्राप्त किए गए ब्लॉक को सहभाजी कैश में प्रतिस्थापित कर सकता है, या प्रीफ़ेच किए गए ब्लॉक कैश से डिमांड-फ़ेच किए गए ब्लॉक को प्रतिस्थापित कर सकते हैं।

उदाहरण

निम्नलिखित दृष्टांत पर विचार करें:

  T[0] = T[0] + 1;
  for i in 0..sizeof(CACHE)
   C[i] = C[i] + 1;
  T[0] = T[0] + C[sizeof(CACHE)-1];

(यहां अवधारणाएं यह हैं कि कैश केवल एक स्तर से समाहित है जो अनलॉक है, प्रतिस्थापन नीति छद्म-एलआरयू है, सभी डेटा कैश करने योग्य है, कैश की सेट एसोसिएटिविटी N है (जहां N > 1), और प्रोग्राम मान सम्मिलित करने के लिए अधिकतम एक प्रोसेसर रजिस्टर उपलब्ध है)।

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

इस स्थिति में कैश को "प्रदूषित" कहा जाता है। T[0] के प्रथम अपडेट को लूप और द्वितीय अपडेट के बीच स्थापन कर डेटा एक्सेस के पैटर्न को परिवर्तन करने से अक्षमता विलोपित हो सकती है:

 for i in 0..sizeof(CACHE)
   C[i] = C[i] + 1;
  T[0] = T[0] + 1;
  T[0] = T[0] + C[sizeof(CACHE)-1];

हल

उपरोक्त उल्लिखित कोड-रिस्ट्रक्टरिंग के अतिरिक्त कैश प्रदूषण का हल यह सुनिश्चित करना है कि कैश में केवल उच्च-पुन: उपयोग वाला डेटा संग्रहीत किया जाए। इसे विशेष कैश कंट्रोल इंस्ट्रक्शंस, ऑपरेटिंग सिस्टम सपोर्ट या हार्डवेयर सपोर्ट का उपयोग करके प्राप्त किया जा सकता है।

विशेष हार्डवेयर इंस्ट्रक्शंस के उदाहरणों में PowerPC AltiVec द्वारा प्रदान किया गया lvxl सम्मिलित है। यह निर्देश 128 बिट विस्तृत मान को एक रजिस्टर में लोड करता है और संबंधित कैश ब्लॉक को प्रायः वर्तमान में प्रयुक्त के रूप में, या फिर किसी ब्लॉक को उसके कैश सेट से निष्कासित की आवश्यकता पर निष्कासन के लिए प्रमुख पदान्वेषी के रूप में चिह्नित करता है। उपरोक्त उदाहरण के कॉन्टेक्ट में उस इंस्ट्रक्शन का उचित उपयोग करने के लिए लूप द्वारा रिफ्रेंस्ड डेटा एलिमेंट्स को इस इंस्ट्रक्शन का उपयोग करके लोड करना होगा। जब इस प्रकार से प्रयुक्त किया जाता है तो कैश प्रदूषण नहीं होगा क्योंकि ऐसे लूप के एक्जिक्यूशन से कैश से T [0] का समय से पूर्व इविक्शन नहीं होगा। इससे बचा जाएगा क्योंकि जैसे-जैसे लूप आगे बढ़ेगा सी में तत्वों के पते उसी कैश तरीके से मैप हो जाएंगे, जिससे वास्तव में पुराना (लेकिन "कम से कम हाल ही में उपयोग किए गए" के रूप में चिह्नित नहीं) डेटा दूसरे तरीके पर बरकरार रहेगा। केवल सबसे पुराना डेटा (दिए गए उदाहरण के लिए प्रासंगिक नहीं) को कैश से निकाला जाएगा जिसका T[0] सदस्य नहीं है क्योंकि इसका अपडेट लूप के शुरू होने से ठीक पहले होता है।

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

महत्वता में वृद्धि

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

संदर्भ

  1. Karami, Amin; Guerrero-Zapata, Manel (2015-04-07). "नामांकित डेटा नेटवर्किंग में कैश प्रदूषण हमलों को कम करने के लिए एक ANFIS-आधारित कैश प्रतिस्थापन विधि". Computer Networks (in English). 80: 51–65. doi:10.1016/j.comnet.2015.01.020. hdl:2117/76980.