- lsr io_uring-आधारित IO लाइब्रेरी ourio का उपयोग करके विकसित किया गया एक नया ls(1) replacement प्रोग्राम है
- मौजूदा ls और वैकल्पिक टूल्स (eza, lsd, uutils ls) की तुलना में कमांड execution speed बेहद तेज़ है, और system calls की संख्या 10 गुना से भी अधिक कम है
- directory open, stat, lstat जैसी सभी प्रमुख IO को io_uring के साथ asynchronous और batched processing द्वारा संभालकर performance को अधिकतम किया गया है। फ़ाइलें जितनी ज़्यादा हों, यह उतना तेज़ होता है
- Zig के StackFallbackAllocator का उपयोग करके memory allocation के समय mmap calls को न्यूनतम किया गया है
- dynamic linking के बिना statically build किया गया है, इसलिए executable file size भी मौजूदा ls से छोटा है
परिचय और महत्व
- lsr प्रोजेक्ट सामान्य ls कमांड का एक replacement है, जो io_uring का उपयोग करने वाला तेज़ directory listing tool है
- मौजूदा
ls, eza, lsd, uutils ls की तुलना में यह execution speed और system call usage दोनों में बेहतरीन performance दिखाता है
- स्वयं विकसित की गई io लाइब्रेरी (ourio) के जरिए जितना संभव हो उतना IO सीधे किया जाता है
- benchmarks के माध्यम से lsr ने बड़े पैमाने के file environments में भी तेज़ performance और गुणवत्ता साबित की है
benchmark परिणाम
hyperfine का उपयोग करके n सामान्य फ़ाइलों वाले directory में हर कमांड का execution time मापा गया
lsr -al ने 10–10,000 फ़ाइलों के मानक पर मौजूदा ls/विकल्पों की तुलना में स्पष्ट रूप से कम execution time दर्ज किया
- उदाहरण: 10,000 फ़ाइलों पर lsr ने 22.1ms दर्ज किया, जबकि मौजूदा ls (38.0ms), eza (40.2ms), lsd (153.4ms), uutils ls (89.6ms) की तुलना में सबसे तेज़ रहा
- system call aggregation
strace -c से की गई
lsr -al: न्यूनतम 20 calls (n=10) से अधिकतम 848 calls (n=10,000) तक, यानी बहुत कम call count बनाए रखता है
- ls में अधिकतम 30,396 calls (n=10,000), lsd में 100,512 calls, और बाकी विकल्प भी हज़ारों से लेकर लाख के करीब calls तक पहुँचते हैं
- समान परिस्थितियों में lsr ने कम-से-कम 10 गुना कम syscall count के साथ सर्वोच्च दक्षता हासिल की
lsr की संरचना और implementation
- प्रोग्राम argument parsing, data collection, data output के 3 चरणों में काम करता है
- सारा IO दूसरे data collection चरण में होता है, और संभव सभी file access / information lookup को io_uring से संभाला जाता है
- target directory open, stat, lstat, time/user/group information lookup — सब कुछ io_uring आधारित है
- stat को batched तरीके से process करके system calls की संख्या में बड़ा reduction किया गया है
- Zig StackFallbackAllocator के साथ 1MB memory pre-allocate करके mmap जैसे अतिरिक्त system calls को न्यूनतम किया गया है
static build और optimization
- libc dynamic linking के बिना पूरी तरह static build होने से execution overhead काफ़ी कम हो जाता है
- GNU ls की तुलना में lsr का ReleaseSmall build size 138.7KB बनाम 79.3KB है, यानी यह छोटा है
- हालांकि, lsr में locale (भाषा/क्षेत्र) support नहीं है। सामान्य ls कई भाषाओं के support के कारण अतिरिक्त overhead रखता है
system calls और performance issues का विश्लेषण
- lsd हर फ़ाइल पर clock_gettime को 5 बार से ज़्यादा call करता है; इसका कारण स्पष्ट नहीं है (संभवतः internal timing measurement आदि)
- sorting काम पूरे workload का बड़ा हिस्सा (लगभग 30%) लेता है
- uutils ls में system call efficiency अच्छी है, लेकिन sorting processing में यह धीमा पड़ जाता है
- सिर्फ io_uring अपनाने भर से भी server जैसे high-load IO environments में क्रांतिकारी performance improvement की संभावना दिखती है
निष्कर्ष
- development time भी बहुत ज़्यादा नहीं लगा, और syscall optimization का प्रभाव उम्मीद से बढ़कर निकला
- lsr एक प्रयोगात्मक ls replacement है, जो तेज़ speed, कम system calls, और compact size तीनों एक साथ हासिल करता है
- बड़े file environments या high-performance IO वाले systems के लिए यह बेहद उपयुक्त है
- locale support जैसी कुछ सीमाएँ हैं, लेकिन practical use और benchmarks दोनों में इसने बेहद नवोन्मेषी नतीजे दिखाए हैं
1 टिप्पणियां
Hacker News की राय
यह बताते हुए कि वही इस प्रोजेक्ट के लेखक हैं, उन्होंने io_uring-आधारित
lsrका परिचयात्मक लेख यहाँ देखने को कहाbfs -j1) में भी इसका उपयोग करना सोचने लायक हो सकता हैtim(परिचय लिंक) से समय नापा जाए तो शायद hyperfine से बेहतर हो। यह Nim में लिखा है, इसलिए चुनौती हो सकती है, लेकिन नाम का मिलता-जुलता होना मज़ेदार संयोग हैlibevringभी अभी शुरुआती अवस्था में है, इसलिए ज़रूरत पड़ने पर उसे ourio से बदला जा सकता है, इस बारे में वे खुले मन से सोचते हैं। उनका मानना है कि अगर Zig-आधारित प्रोजेक्ट्स में C/C++ bindings support हो, तो C/C++ से Zig में migration के समय वह उपयोगी होगाNFS server पर, खासकर खराब network environment में, lsr की performance कैसी होगी यह जानने की जिज्ञासा है। unstable network service पर blocking POSIX syscall का उपयोग करना NFS design की एक स्पष्ट कमी है। io_uring इस समस्या को कितना कम कर सकता है, यह भी देखने की बात है
lsआदि) को network error स्थितियों को सीधे handle नहीं करना पड़ता था। मूल NFS protocol stateless था, इसलिए server reboot के बाद भी client अपने-आप recover हो जाता था। io_uring ऐसे cases में errors को ठीक से pass करता है या नहीं, यह जानने की उत्सुकता है। NFS timeout होने पर यह कैसे handle होता है, यह भी रुचि का विषय हैintrmount option चल रहे remote server operation तक signal पहुँचाकर interrupt करने की सुविधा देता था, लेकिन Linux में यह बहुत पहले हटा दिया गया (अबsoftoption ही संभव है) (संदर्भ1, संदर्भ2(FreeBSD support))यह दिलचस्प है कि syscall calls की संख्या 35 गुना कम हुई, फिर भी speed improvement केवल लगभग 2x है
io_uring के उपयोग के एक case study के तौर पर, long-term speed gains की उम्मीद या tutorial-style usage introduction की वजह से यह project अधिक दिलचस्प लगा। eza जैसे मौजूदा tools की तुलना में यह क्यों ज़रूरी है, इसका व्यावहारिक motivation उतना महसूस नहीं हुआ। अगर 10,000 files की listing 40ms बनाम 20ms है, तो single run के हिसाब से शायद कोई फ़र्क महसूस नहीं होगा
ls/duचलाने में कई मिनट लग जाते हैं। coreutils के default commands अक्सर आधुनिक SSD की performance का पूरा लाभ नहीं उठा पातेlsr अच्छा है, लेकिन coloring और icons support में eza बेहतर है। एक व्यक्ति ने अपना setup
"eza --icons=always -1"पर रखा है, इसलिए music files (.opusआदि) अपने-आप icon और color के साथ दिखती हैं, जबकि lsr में वे बस सामान्य files की तरह दिखती हैं। फिर भी lsr को patch करना आसान है और यह बहुत तेज़ है, यह बात साफ़ महसूस होती है। साथ ही, वे उम्मीद करते हैं किcatऔर दूसरी utilities भी ऐसे ही बनाई जाएँ, tangled.sh और atproto का उपयोग भी उन्हें रोचक लगा। Zig में लिखा होने की वजह से यह उन्हें शुरुआती नज़रिए से Rust की तुलना में आसान लगता हैbatआधुनिकcatreplacement है (bat link)किसी को यह जिज्ञासा थी कि सभी CLI tools io_uring का उपयोग क्यों नहीं करते। उसका अनुभव है कि जब वह nvme को usb 3.2 gen2 से जोड़ता है, तो साधारण tools से speed 740MB/s रहती है, जबकि aio या io_uring-आधारित tools से यह 1005MB/s तक पहुँच जाती है। उसका मानना है कि queue length strategy और lock reduction का भी असर है
#ifdefजैसी macro branching के बिना लिखा जाता रहा है, इसलिए platform/version-specific नई technologies को अपनाने की रफ़्तार धीमी है। अब उसे लगता है कि अलग-अलग posixy platforms के बीच compatibility का फायदा पहले जितना बड़ा नहीं रहाstrace में देखा गया कि lsd हर file पर लगभग 5 बार
clock_gettimecall करता है। सटीक कारण स्पष्ट नहीं, शायद हर timestamp के लिए “कितने मिनट/घंटे/दिन पहले” जैसी गणना की वजह से, या फिर library legacy behavior हो सकता हैclock_gettimeअसली syscall नहीं, बल्कि vDSO के ज़रिए handle होता है (man 7 vDSOदेखें)। किसी ने सोचा कि शायद Zig इस structure का उपयोग नहीं कर रहा होगाथोड़ा topic से हटकर, लेकिन Mellanox 4 या 5 जैसे high-end enterprise servers में 10G NIC environment पर, socket latency overhead को io_uring, LD_PRELOAD की तुलना में microseconds के स्तर पर कितना घटाता है, इस बारे में किसी को वास्तविक अनुभव या benchmark numbers जानने हैं। ऐसा लगता है कि दोनों के effects additive नहीं हैं, इसलिए यदि किसी के पास प्रत्यक्ष अनुभव हो तो वह numbers सुनना चाहेंगे
io_uring
getdentsको support नहीं करता, इसलिए असली लाभ bulkstat(जैसेls -l) में दिखता है। कुछ लोगों को खेद है कि अगरgetdentshandling को asynchronous और overlapped बनाया जा सकता, तो और अच्छा होताreaddirplus(getdents+stat) operation को standardize कर दे, तो io_uring का कुछ लाभ कम हो सकता हैयह मज़ेदार लगा कि
.mjsऔर.cjsextensions के लिए icons हैं, लेकिन.c,.h,.shजैसे file extensions के लिए नहीं हैं