सबसे तेज़ Mutex
(justine.lol)- उच्च contention की स्थिति में Mutex implementations के बीच का अंतर बहुत साफ़ दिखता है, और Cosmopolitan Libc का
pthread_mutex_tWindows और Linux की प्रमुख implementations की तुलना में कम execution time और कम CPU उपयोग दिखाता है - Windows के 24-core Threadripper 29070WX टेस्ट में Cosmopolitan, Microsoft SRWLOCK से 2.75 गुना तेज़ था और CPU resources का 18 गुना कम उपयोग करता है
- Linux के 96-core Threadripper Pro 7995WX पर यह glibc से 3 गुना और musl libc से 11 गुना तेज़ है, जबकि CPU time का अंतर इससे भी बड़ा है
- MacOS M2 Ultra पर Apple Libc थोड़ा आगे है, और Cosmopolitan ARM environment में XNU के ulock system call पर निर्भर एक सरल algorithm इस्तेमाल करता है
- performance की बुनियाद Google के nsync integration पर है, जिसमें CAS fast path, waiter queue, futex/ulock/
WaitOnAddress(), starvation prevention और designated waker design मुख्य हैं
Contention Mutex benchmark का तरीका
- टेस्ट में 30 threads बनाए जाते हैं, और हर thread एक ही global integer
g_choresको 100,000 बार increment करता है - हर increment operation
pthread_mutex_lock()औरpthread_mutex_unlock()के बीच के बहुत छोटे critical section में चलाया जाता है - माप microseconds में लिए जाते हैं और तीन तरह के time अलग किए जाते हैं
- wall time: program चलने का वास्तविक समय, जिसमें thread creation और join overhead शामिल है
- user time: user space में खर्च हुआ CPU time
- system time: kernel में खर्च हुआ CPU time
- क्योंकि कई threads parallel में चलते हैं, इसलिए user time और system time का योग wall time से बड़ा हो सकता है
- non-contention स्थिति में implementations के बीच performance अंतर आम तौर पर छोटा होता है, लेकिन contention स्थिति में Mutex design का अंतर बहुत स्पष्ट हो जाता है
Windows: SRWLOCK से तेज़ Cosmopolitan
- Windows टेस्ट 24-core Threadripper 29070WX पर किया गया
- Mark Waterman का MutexShootout high-contention scenario में Windows के SRWLOCK को सबसे मज़बूत implementation मानता है
- उसी स्थिति में Cosmopolitan
pthread_mutex_tने SRWLOCK से कम wall time और कम CPU उपयोग दर्ज किया
| implementation | wall time | user time | system time |
|---|---|---|---|
Cosmopolitan pthread_mutex_t |
148,940µs | 328,125µs | 62,500µs |
| Microsoft SRWLOCK | 410,416µs | 5,515,625µs | 1,640,625µs |
Microsoft CRITICAL_SECTION |
949,187µs | 7,937,500µs | 5,078,125µs |
MSVC 2022 std::mutex |
991,750µs | 12,156,250µs | 4,031,250µs |
| spin lock | 1,165,435µs | 24,515,000µs | 15,000µs |
Cygwin pthread_mutex_t |
9,780,803µs | 1,937,000µs | 6,156,000µs |
- Cosmopolitan Mutex, Microsoft SRWLOCK से 2.75 गुना तेज़ है, और CPU resources का 18 गुना कम उपयोग करता है
- Windows पर POSIX implementation देने वाले Cygwin Mutex की तुलना में यह 65 गुना तेज़ है
- इस use case में Cygwin Mutex ने spin lock से भी खराब परिणाम दिया
Linux: wall time से भी बड़ा CPU time अंतर
- Linux टेस्ट 96-core Threadripper Pro 7995WX पर किया गया
| implementation | wall time | user time | system time |
|---|---|---|---|
Cosmopolitan pthread_mutex_t |
36,905µs | 44,511µs | 23,492µs |
glibc pthread_mutex_t |
101,353µs | 150,706µs | 2,724,851µs |
| spin lock | 202,423µs | 4,694,749µs | 2,000µs |
Musl libc pthread_mutex_t |
411,013µs | 2,167,898µs | 9,926,850µs |
- Cosmopolitan Mutex, glibc से 3 गुना और musl libc से 11 गुना तेज़ है
- CPU time के आधार पर यह glibc से 42 गुना और musl libc से 178 गुना कम उपयोग करता है
- ऐसे workload में जहाँ सभी threads को serialized काम करना पड़ता है, Cosmopolitan
htopमें ऐसा दिख सकता है जैसे सिर्फ़ एक core active हो - वहीं glibc और musl libc उसी स्थिति में CPU usage को काफी भर सकते हैं, जिससे उसी server पर कई workloads चलाने पर दबाव बढ़ता है
MacOS: Apple Libc थोड़ा आगे
- MacOS टेस्ट M2 Ultra पर किया गया
| implementation | wall time | user time | system time |
|---|---|---|---|
| Apple Libc | 52,263µs | 43,202µs | 911,009µs |
Cosmopolitan pthread_mutex_t |
54,700µs | 63,055µs | 1,003,674µs |
- MacOS M2 ARM64 पर Apple Libc, Cosmopolitan Mutex से थोड़ा तेज़ है
- Cosmopolitan का सामान्य Mutex implementation इस platform पर अच्छी तरह काम नहीं करता
- MacOS ARM पर Cosmopolitan, Ulrich Drepper के Futexes Are Tricky पर आधारित एक सरल algorithm इस्तेमाल करता है
- यह तरीका भारी processing का ज़्यादातर हिस्सा XNU के ulock system call को सौंप देता है, और नतीजतन Apple implementation के लगभग बराबर performance देता है
Performance की बुनियाद: nsync integration
- Cosmopolitan Mutex performance का मुख्य कारण Google की nsync library का integration है
- nsync GitHub पर 371 stars वाली library है, जिसे Google के Mike Burrows ने लिखा है
- Cosmopolitan integration के दौरान ये काम किए गए
- nsync के Mutex unlock function में लंबे समय से छिपा bug खोजकर ठीक किया गया
- AARCH64 पर C11 atomic operations के साथ port करके contended nsync Mutex को upstream nsync से 30% तेज़ बनाया गया
- futex जैसी system integrations को नए सिरे से लिखा गया ताकि runtime portability संभव हो सके
- इसे POSIX thread cancellation के साथ सहज रूप से काम करने लायक बनाया गया
nsync कैसे काम करता है
- nsync lock को जल्दी हासिल करने के लिए शुरुआत में तुरंत optimistic CAS(compare and swap) आज़माता है
- lock न मिलने पर calling thread को waiters की doubly linked list में जोड़ दिया जाता है
- हर waiter के पास अपने लिए एक अलग independent cache line में semaphore होता है
- wait state में जाने के बाद thread मुख्य lock को दोबारा नहीं छूता
- यह कई cores द्वारा एक ही cache line छूने पर होने वाले communication overhead को कम करने में महत्वपूर्ण है
- संबंधित पृष्ठभूमि के लिए Ulrich Drepper का What Every Programmer Should Know About Memory जुड़ा है
- nsync threads को सुलाने के लिए operating system के futex का उपयोग करता है
- MacOS में futex को ulock कहा जाता है
- Windows में
WaitOnAddress()futex की भूमिका निभाता है - Cosmo द्वारा समर्थित OS में सिर्फ़ NetBSD में futex नहीं है, वहाँ POSIX semaphores kernel space में implement होते हैं और हर semaphore के लिए नया file descriptor चाहिए होता है
- nsync long wait concept के ज़रिए starvation से बचता है
- अगर कोई waiter 30 बार जगाया गया लेकिन हर बार अंदरूनी रूप से lock लेने में विफल रहा, तो lock में एक bit जोड़ दिया जाता है ताकि अभी तक प्रतीक्षा न करने वाले threads lock न ले सकें
- इस bit के रहते नए आने वाले threads का शुरुआती CAS तब तक fail होता है जब तक queue कुछ हद तक खाली न हो जाए
- छोटे critical section वाले contention use cases में designated waker concept performance बढ़ाता है
- जब कोई thread जागकर lock लेने की कोशिश करता है, तो मुख्य lock में एक bit set कर दी जाती है
- nsync में unlock function की ज़िम्मेदारी अगला waiting thread जगाने की होती है
- इस bit की वजह से unlock कर रहा thread, अगर कोई thread पहले से जागा हुआ है, तो दूसरे waiter को जगाने की ज़रूरत नहीं होती
- संबंधित source code
cosmopolitan/third_party/nsync/mu.cऔरcosmopolitan/libc/intrin/pthread_mutex_lock.cमें है
वास्तविक service और validation code
- Cosmo Mutex का live demo http://ipv4.games/ server पर देखा जा सकता है
- यह service 2-core GCE VM पर चलती है और अब तक अधिकतम 49,131,669 IP आकार के botnet DDoS को झेल चुकी है
- nsync की वजह से SQL queries को background threads में भेजना और threads के बीच message passing वाली संरचना इस्तेमाल करना संभव हुआ
- status metrics /statusz पर देखे जा सकते हैं
- benchmark code
gettimeofday()से wall time मापता है औरgetrusage()से user time और system time मापता है - अंत में
g_chores == THREADS * ITERATIONSजाँचकर verify किया जाता है कि सभी increment operations पूरे हुए या नहीं
Spin lock को देखते समय सावधानियाँ
- non-contention स्थिति में Mutex implementations के बीच का अंतर छोटा होता है, और कुछ lines के spin lock बेहतर लग सकते हैं
- लेकिन spin lock का उपयोग तभी करना चाहिए जब सचमुच कोई दूसरा विकल्प न हो
- kernel जैसे बेहद low-level constraints वाले स्थानों में, जहाँ अधिक जटिल तरीका अपनाना मुश्किल हो, यह उपयोगी हो सकता है
- nsync lock की internal implementation details में भी spin lock इस्तेमाल हो सकता है
- अगर lock performance को सिर्फ़ wall time से देखा जाए तो spin lock अच्छा लग सकता है, इसलिए
getrusage()से CPU time भी साथ में देखना चाहिए
1 टिप्पणियां
Hacker News की राय
नए mutex implementations और comparisons हमेशा दिलचस्प होते हैं, लेकिन यह benchmark करने का तरीका मुझे पसंद नहीं आया। यह लगभग microbenchmark जैसा दिखता है
तेज locks को सच में deploy करने वाले लोग आम तौर पर बहुत बड़े multi-threaded programs को मुख्य performance test के रूप में इस्तेमाल करते हैं। complex workloads में, जहाँ critical section की लंबाई, competing threads की संख्या और contention का स्तर बदलता रहता है, mutex को तेज या धीमा बनाने वाले factors अलग दिखते हैं
संदर्भ के लिए, मैंने WebKit का fast lock लिखा था, lock implementations के लिए ParkingLot abstraction का आविष्कार किया था (जो Rust और Unreal Engine में भी इस्तेमाल होता है), और पहले Java के लिए fast locks पर research और paper भी किया था
real-time audio programmer के तौर पर, पहले से locked न होने वाले mutex को acquire करने की लागत मेरे लिए ज़्यादा महत्वपूर्ण है। हमारी app में यही situation भारी मात्रा में होती है। इसी तरह, N threads के contention की बजाय, failed होने वाले
try-lockoperation की लागत भी जानना चाहूँगाCosmopolitan open source है, इसलिए मैं खुद measure भी कर सकता हूँ, लेकिन फिर भी यह कमी खलती है
hashmap की तरह, एक ही hashmap का हर संभव workload में बेहतर होना दुर्लभ है
ऐसा mutex जो lock acquisition fail होने पर fixed time (जैसे 100µs) के लिए सो जाता है, लगभग हमेशा काम को batches में इकट्ठा कर देता है और इस behavior के करीब पहुँच जाता है, इसलिए benchmark में “जीत” सकता है। लेकिन real applications में जरा-सा contention भी हो तो ऐसा mutex भयानक होता है
मेरा मतलब यह नहीं कि यह mutex खराब है या pthread mutex अच्छा है; मतलब यह है कि वह microbenchmark ऐसी चीज़ नहीं measure करता जिससे real application performance predict हो सके
“Cosmopolitan Mutex अच्छा इसलिए है क्योंकि इसमें nsync नाम की library इस्तेमाल हुई है” वाले हिस्से पर, nsync के बारे में मैंने पहली बार सुना, लेकिन Mike Burrows ने Google का production mutex implementation भी लिखा था: https://github.com/abseil/abseil-cpp/blob/master/absl/synchr...
इसलिए मुझे हैरानी है कि यह mutex implementation benchmark से क्यों छूट गया। और अगर macOS पर
__ulockको delegate किया जा रहा है, तो लगता है कि libc++ की atomic library में मौजूदwait(),notify_one()member functions से ही यह और सरलता से हासिल किया जा सकता हैपहले Rust के mutex implementation को improve करने से जुड़ा एक बड़ा thread भी था: https://github.com/rust-lang/rust/issues/93740#issuecomment-... दिलचस्प बात यह है कि लगभग सभी popular mutex implementations की internal workings पर विस्तार से चर्चा है
यह सच भी हो सकता है, लेकिन मैं सीधे verify नहीं कर सकता। वे efficiency पर बहुत ज़ोर देने वाले बेहद smart engineer थे। हालांकि हम एक server को लंबे समय तक चलाए नहीं रखते थे
current Rust mutex implementation इस साल की शुरुआत में आया, और Linux पर शायद बहुत अलग न हो, लेकिन Windows और Mac पर मेरी जानकारी में यह नया काम है
फिर भी Mara ने अन्य implementations के internals जो समझाए हैं, वे अब भी दिलचस्प हैं, लेकिन अपनी situation में यह पुरानी जानकारी तो नहीं है, इसकी जाँच कर लेना बेहतर है
https://awards.acm.org/award-recipients/burrows_9434147
“यह अभी नई C लाइब्रेरी है इसलिए कुछ हिस्से खुरदरे हैं, लेकिन यह इतनी तेज़ी से बेहतर हो रही है कि इसे production में न इस्तेमाल करना पेशेवर ज़िम्मेदारी से बचना लगने लगा है” — यह वाक्य काफ़ी अजीब है। Cosmopolitan प्रोजेक्ट की मैं काफ़ी कद्र करता हूँ, लेकिन इस तरह के बढ़ा-चढ़ाकर किए गए श्रेष्ठता के दावे आम तौर पर काफ़ी खराब red flag होते हैं
यह भी समझ आता है कि कुछ लोगों को यह रूखा लग सकता है। पहले भी llamacpp में इसी तरह का drama हुआ था
production में सबसे पहली प्राथमिकता “बहुत तेज़ी से बेहतर होना” नहीं, बल्कि स्थिरता, predictability, reliability है। बेशक performance भी महत्वपूर्ण है। ज़्यादा तेज़ code infrastructure घटा सकता है, जिससे cost और environment दोनों के लिहाज़ से फायदा हो सकता है। लेकिन speed सबसे आख़िरी priority है
उदाहरण के लिए APE मुझे बहुत प्रभावशाली hacking लगता है, लेकिन यह आलोचना भी संभव है कि “अब यह सिर्फ़ एक platform पर unsafe नहीं, बल्कि कई platforms पर एक साथ unsafe हो सकता है?”
tech field में जितना लंबा समय बिताते हैं, उतना समझ आता है कि पूरी तरह mutual benefit बहुत दुर्लभ है, और ज़्यादातर चीज़ें कुछ पाने और कुछ खोने वाले trade-off ही होती हैं
यह पूरी तरह side note है, लेकिन game developer के तौर पर मुझे सभी developer builds में debug work ज़्यादा करने वाले धीमे mutex पसंद आने लगे हैं। जैसे उनके पास debug name/ID हो, owner track करें, contention में लगे समय को profiler में report करें, और ownership change भी profiler में report करें
games concurrency को अलग तरह से structure करते हैं, और lock से बचने के patterns भी evolve हुए हैं। लेकिन ऐसे patterns इस्तेमाल करना मुश्किल होता है और programmer को structure बदलना पड़ता है। ज़्यादातर code “चलो फिलहाल यहाँ lock लगा दें और milestone पार कर लें” से शुरू होता है
तेज़ lock भी unpredictable तरीके से धीमे हो सकते हैं, और अगर real-time guarantee थी तो उसे तोड़ देते हैं। average में वे तेज़ हो सकते हैं, लेकिन tail latency गायब नहीं होती। “हमारा game अटक रहा है” को trace करने के लिए वापस आने वाला व्यक्ति मैं नहीं बनना चाहता, लेकिन आम तौर पर मैं ही वह व्यक्ति बन जाता हूँ
इसलिए धीमे lock इस्तेमाल करना बेहतर है। वे lock जो profiler में बड़े लाल रंग में दिखते हैं। अगर दिख जाए कि वे चोट पहुँचा रहे हैं, तो refactor करके उन्हें हटा दें
मुझे पता है यह मुश्किल मांग है। AAA production में profiler इस्तेमाल करना जानने वाले लोग उंगलियों पर गिने जा सकते हैं। कई productions देखने पर भी हमेशा यही था
शिकायत के लिए माफ़ी, लेकिन उम्मीद है कि तेज़ concurrency primitives और algorithms पर research जारी रहेगी
games में अगर संभव हो तो आप lock contention कभी नहीं चाहते, और कई मामलों में यह साबित किया जा सकता है कि lock लेना unnecessary है। उदाहरण के लिए हर frame phases में बँटा होता है, और किसी shared resource पर mutable access सिर्फ़ किसी खास phase में चाहिए होता है। जैसे
render()से पहले काupdate()या asset hot reloadscoped threads और Rust के borrowing rules इस्तेमाल करके structure ऐसा बनाया जा सकता है कि mutex की ज़रूरत ही न पड़े, और बाद में code बदलने पर जैसे ही उसकी ज़रूरत पड़ेगी, compiler सख्ती से error देगा — इस पर भरोसा किया जा सकता है
जहाँ संभव हो, profiler spike की बजाय compile error मिलना हमेशा बेहतर है
एक तरफ़ Cosmo/APE/redbean वाली लाइन वाकई कमाल की लगती है, और उससे जुड़े लेखों के comments भी आम तौर पर सकारात्मक हैं; concept को ही खारिज करने वाली बातें भी ज़्यादा नहीं दिखतीं। लेकिन दूसरी तरफ़, मैंने लगभग कभी नहीं सुना कि कोई और इसे इस्तेमाल कर रहा हो
यह सही है कि हर कोई अपना काम बड़े पैमाने पर शेयर नहीं करता, लेकिन इतने साल बीत गए हैं तो मुझे लगता था कि कुछ project retrospective पोस्ट तो दिखी होंगी। Cosmo/APE/redbean का जितना भी ज़िक्र मैंने देखा है, वह सब Justine की साइट से ही आया है
इसलिए जिज्ञासा है। क्या इसमें कोई छिपा हुआ trap है? क्या यह performance पाने के लिए कुछ खराब हरकतें करने वाला tool है? क्या compilers या runtime की गहराई से जानकारी न होने के कारण मैं कोई tom7-style joke या trolling समझ नहीं पा रहा? या ये सचमुच बहुत चतुर tools हैं जो अभी व्यापक रूप से फैले नहीं हैं?
cross-platform software बनाने वाले ज़्यादातर लोग ऐसा single executable नहीं चाहते जो हर platform पर चले; वे ऐसा single codebase चाहते हैं जो हर supported platform पर सही तरीके से काम करे
उस नज़रिए से, Go जैसी languages, जिनमें CGO से बचने पर सभी targets के लिए cross-compile किया जा सकता है, काफ़ी सुखद हैं। लेकिन APE का तीन अलग-अलग तरीकों से executable हो जाने वाला जादू, चाहे कितना भी clever हो, यह भरोसा नहीं देता कि वह हमेशा चलता रहेगा, और ज़्यादातर मामलों में उसका practical फायदा भी बहुत कम है
हर platform की अपनी packaging और signing requirements होती हैं, इसलिए platform-specific targets के लिए अलग-अलग compile करना ही बेहतर है
उदाहरण के लिए, अगर आप पहले से project को अलग-अलग operating systems और platforms के लिए cross-compile कर सकते हैं, या ऐसी build infrastructure मौजूद है, तो हर जगह चलने वाली single binary बनाने का समाधान ढूँढने की कोई वजह नहीं है
साथ ही APE कई operating systems पर चलने के लिए clever hacking इस्तेमाल करता है। अगर executable formats evolve होते हुए किसी दिन वह hack टूट गया तो? अगर उस बदलाव के हिसाब से APE को ठीक करने का समय किसी के पास न हुआ तो?
इसके उलट gcc, clang, go, rust जैसे boring tools लगातार update होते और evolve होते operating systems पर भी चलते रहेंगे। इसलिए मैं बस boring विकल्प पर ही रहता हूँ। clever चीज़ों की परवाह न करने की वजह यह है कि boring चीज़ मेरे लिए बस ठीक से काम करती है
इसे bundled weights के बिना चलाकर filesystem से weights पढ़वाना भी संभव है। local LLM को “download करो और तुरंत चलाओ” बनाने का यह शायद सबसे आसान तरीका हो सकता है
लेकिन
libcजैसी foundational technology के रूप में इस्तेमाल करने के लिए यह मुख्यतः मज़ेदार toy या छोटे personal projects में उपयोगी लगता हैउस context में, जब इसे
glibc,musl,msvcrtजैसी चीज़ों के serious alternative के रूप में पेश किया जाता है, तो थोड़ा अजीब लगता है। यह बहुत प्यारा hack है, लेकिन अगर मुझे किसी ऐसी चीज़ में यह मिले जिस पर मैं गंभीरता से निर्भर हूँ, तो मैं काफ़ी असहज हो जाऊँगाHugging Face पर भी उस format में repackage किए गए popular models नियमित रूप से upload किए जाते हैं: https://huggingface.co/models?search=llamafile
हालांकि यह छोटे models को जल्दी test करने से आगे कितना practical है, यह अलग सवाल है
अगर यह इतना अच्छा है, तो हैरानी होती है कि सभी C लाइब्रेरी ने वही ट्रिक क्यों नहीं अपनाई
मेरा अनुमान है कि वे ट्रिक्स केवल किसी खास architecture, खास CPU मॉडल, खास workload या access pattern में ही हमेशा तेज़ होने की संभावना रखती हैं। supported सभी hardware पर अलग-अलग workloads को सही ढंग से benchmark करने पर शायद वही फायदा न निकले
या फिर हो सकता है कि Cosmopolitan जिस pthread API semantics को implement करना चाहता है, वह सूक्ष्म रूप से अलग हो, और यह implementation specification का सख्ती से पालन न करता हो
यह कल्पना करना मुश्किल है कि कई libc लेखक operating-system primitives पर नई research से अनजान रह गए होंगे
glibc का malloc ठीक-ठाक कामचलाऊ है, लेकिन overall speed और scalability में अधिक modern alternatives से आसानी से पीछे रह जाता है। fragmentation ज्यादा है और समय के साथ बिगड़ता है, और
MALLOC_ARENA_MAXजैसे कई tuning values भी हैं जिनका real workloads पर बड़ा असर पड़ता है। musl malloc performance के लिहाज से हर स्तर पर भयावह है। multi-threaded programs में musl allocator इस्तेमाल करने से performance इतनी खराब हो जाती थी कि इसे लगभग लापरवाही कहा जा सकता थाmusl में SIMD-optimized string comparison routines जैसी चीज़ें भी नहीं हैं। non-trivial programs में ऐसे कामों पर कितने CPU cycles खर्च होते हैं, यह जानकर आप चौंकेंगे; real profiles में भी यह साफ दिखता है, और इसे improve करने से लगभग हर program को broadly फायदा मिलता है। glibc की optimized routines अच्छी हैं, लेकिन फिर भी लगता है कि वे और तेज़ हो सकती हैं
ये चीज़ें “सिर्फ एक architecture के लिए specialized और generalize न होने वाली optimization” नहीं हैं। खासकर ये दोनों areas लगभग सभी workloads में wall-clock time को 2~5 गुना घटाने और long-term working set utilization को काफी improve करने वाले, अच्छी तरह explore और समझे गए areas हैं। फिर इन्हें क्यों नहीं अपनाया गया? हमेशा की तरह, शायद करने को और काम थे, या musl की तरह top performance के बजाय simplicity को priority देने वाली conflicting priorities थीं
मैं ऐसे projects को दोष नहीं दे रहा। कोई भी यह नहीं कहता कि “मेरा program बेहद धीमा है, कुछ भी ठीक से न कर पाने के लिए design किया गया है, और मुझे इस पर गर्व है।” बस यह सोच कि उन projects पर काम करने वालों ने designs में सिर्फ perfect Pareto frontier ही चुनी, बिल्कुल realistic नहीं है और यह ज्यादातर projects के असल में चलने के तरीके को नहीं दर्शाती
glibc या C++ वाले equivalent में कुछ बदलने में अनंत समय लग जाता है
synchronization primitives कई तरह के होते हैं, और pthreads उनमें से सिर्फ कुछ को support करता है। खुद को उसी तक सीमित करने पर आम तौर पर portability के बदले performance छोड़नी पड़ती है
libc maintainers के बारे में नहीं जानता, लेकिन कुछ चीज़ें maintain करने वाले के रूप में मैं latest research implement करने की कोशिश नहीं करता। मैं stability बनाए रखने और performance acceptable है यह सुनिश्चित करने की कोशिश करता हूँ। research implementations मेरे “maintenance” budget से बाहर हैं
एक आदमी और एक statistician सड़क पर चल रहे थे और उन्हें 50 euro का note दिखा। statistician चलता रहा, आदमी रुका और बोला, “देखिए, ज़मीन पर पैसे पड़े हैं।” तब statistician ने कहा, “नकली होगा। असली होता तो कोई पहले ही उठा चुका होता,” और चलता रहा। दूसरा आदमी वह पैसा उठा ले गया
threads और mutexes computer science में सबसे ज्यादा जटिलता पैदा करने वाली चीज़ों में हैं। किसी नए implementation को तब तक हमेशा skeptically देखना चाहिए, जब तक वह कई सालों तक बड़े scale पर इस्तेमाल न हो चुका हो
ऐसे threading mechanisms के bugs अक्सर सबसे गहन review से भी बच निकलते हैं। 90s के mid में जब Java आया, तो Solaris के तरह-तरह के thread और mutex bugs उजागर हुए थे
हमें सबसे तेज़ mutex implementation नहीं, बल्कि भरोसेमंद implementation चाहिए
यह code mutex lock performance नहीं, बल्कि mutex contention benchmark करता है। अगर आप इस तरह lock इस्तेमाल कर रहे हैं, तो अपने code का फिर से मूल्यांकन करना चाहिए
हर thread
g_choresincrement करते समय mutex को lock और unlock करता है। इससे mutex को बार-बार acquire और release करने का overhead पैदा होता है, और यह प्रति thread 100,000 बार दोहराया जाता हैयह overhead lock mechanisms के बीच असली performance differences को ढक देता है, क्योंकि benchmark real work के बजाय lock contention से dominated है। ऐसा benchmark बेकार है
मैं Justine और उनके काम का fan हूँ, लेकिन यह शायद mutex benchmark test case के तौर पर सबसे कम interesting case है। कई threads का लगातार उसी mutex पर hammer करना ऐसी स्थिति है जिससे शुरू में ही बचना चाहिए
इसलिए कौन-सा mutex implementation इस case को सबसे अच्छी तरह handle करता है, यह मुझे खास interesting नहीं लगता
एक important बात छूट गई थी: contention की स्थिति में खराब performance वाला lock memory network में hotspot बनाने जैसे बहुत negative system-level effects पैदा कर सकता है, और यह भी यहाँ सामने आएगा
मुझे कुछ cases याद आते हैं जहाँ कई threads एक ही mutex पर इकट्ठा होते हैं। आसान example के तौर पर list या dictionary जैसे data structures को concurrently भरना है
message passing से भी किया जा सकता है, लेकिन वह ज्यादा memory इस्तेमाल कर सकता है और shared location पर write करने के लिए इंतज़ार करने से धीमा हो सकता है
production speed, efficiency, या साफ तौर पर “clever hacking” के बारे में नहीं है
अगर रविवार सुबह 3 बजे खराब system ठीक करने के लिए बुलाए न जाने की guarantee के लिए efficiency का 50% त्यागना पड़े, तो मैं हर बार वही चुनाव करूँगा
production reliability के बारे में है, और reliable code लिखना “fast” code लिखने से 10 गुना ज्यादा कठिन है