2 पॉइंट द्वारा GN⁺ 2025-07-19 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • 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 टिप्पणियां

 
GN⁺ 2025-07-19
Hacker News की राय
  • यह बताते हुए कि वही इस प्रोजेक्ट के लेखक हैं, उन्होंने io_uring-आधारित lsr का परिचयात्मक लेख यहाँ देखने को कहा

    • उन्होंने Sun में I18N प्रोजेक्ट पर काम करने का अनुभव साझा किया। कई environments (localization, utf8 आदि) को support करने के लिए प्रोग्राम में तरह-तरह की processing जोड़नी पड़ती है, इसलिए output निकालने की लागत और speed का रिश्ता उलटा महसूस होता है। मूल UNIX का ls(1) simple design की वजह से बहुत तेज़ था, लेकिन अलग-अलग features, virtual file system (VFS), विभिन्न character sets, color support आदि के छोटे-छोटे costs जुड़ते गए और वह धीमा हो गया। उनके हिसाब से io_uring जिस abstraction cost को handle करता है, उस पर यह एक दिलचस्प चर्चा है
    • bfs प्रोजेक्ट भी io_uring का उपयोग करता है (source code link). उन्हें lsr और bfs -ls की performance तुलना जानने की उत्सुकता है। अभी bfs केवल multithreading में io_uring का उपयोग करता है, लेकिन single thread (bfs -j1) में भी इसका उपयोग करना सोचने लायक हो सकता है
    • tim (परिचय लिंक) से समय नापा जाए तो शायद hyperfine से बेहतर हो। यह Nim में लिखा है, इसलिए चुनौती हो सकती है, लेकिन नाम का मिलता-जुलता होना मज़ेदार संयोग है
    • वे C++ प्रोजेक्ट को Zig में port करने का विचार रखे हुए हैं। उनका अपना बनाया हुआ libevring भी अभी शुरुआती अवस्था में है, इसलिए ज़रूरत पड़ने पर उसे ourio से बदला जा सकता है, इस बारे में वे खुले मन से सोचते हैं। उनका मानना है कि अगर Zig-आधारित प्रोजेक्ट्स में C/C++ bindings support हो, तो C/C++ से Zig में migration के समय वह उपयोगी होगा
    • उनका कहना है कि उस परिचय लेख में background की व्याख्या बेहतर है, इसलिए वे उसे main link बनाना चाहते हैं और repo thread को ऊपर जोड़ने की योजना है
  • NFS server पर, खासकर खराब network environment में, lsr की performance कैसी होगी यह जानने की जिज्ञासा है। unstable network service पर blocking POSIX syscall का उपयोग करना NFS design की एक स्पष्ट कमी है। io_uring इस समस्या को कितना कम कर सकता है, यह भी देखने की बात है

    • NFS के designer ने distributed system को hard drive की तरह बहुत consistent तरीके से काम करने वाला बनाया। इसका फायदा यह था कि पुराने tools (ls आदि) को network error स्थितियों को सीधे handle नहीं करना पड़ता था। मूल NFS protocol stateless था, इसलिए server reboot के बाद भी client अपने-आप recover हो जाता था। io_uring ऐसे cases में errors को ठीक से pass करता है या नहीं, यह जानने की उत्सुकता है। NFS timeout होने पर यह कैसे handle होता है, यह भी रुचि का विषय है
    • कोई व्यक्ति घर में कई PCs पर NFS $HOME का उपयोग करता है, और कहता है कि जब तक network अच्छा हो और parallel writes जैसे मुश्किल cases से बचा जाए, NFS की औसत usability काफ़ी संतोषजनक है। हालांकि, network cable unstable होने पर disconnect issues की वजह से परेशानी हुई थी
    • NFS folder पढ़ रही app में ctrl+c काम न करना एक जाना-माना असुविधाजनक व्यवहार है। सिद्धांत रूप में intr mount option चल रहे remote server operation तक signal पहुँचाकर interrupt करने की सुविधा देता था, लेकिन Linux में यह बहुत पहले हटा दिया गया (अब soft option ही संभव है) (संदर्भ1, संदर्भ2(FreeBSD support))
    • Samba में भी इसी तरह की समस्या है
  • यह दिलचस्प है कि syscall calls की संख्या 35 गुना कम हुई, फिर भी speed improvement केवल लगभग 2x है

    • अधिकांश syscalls VDSO के ज़रिए होते हैं, इसलिए उनकी लागत बहुत बड़ी नहीं होती
    • किसी ने पहले io_uring benchmarks पढ़े थे जिनमें io_uring-आधारित syscall पारंपरिक syscall से भारी निकले थे। फिर भी अनुभव के स्तर पर यह काफ़ी बड़ा improvement लगता है। सटीक source याद नहीं, लेकिन बात प्रभावशाली लगी थी
  • io_uring के उपयोग के एक case study के तौर पर, long-term speed gains की उम्मीद या tutorial-style usage introduction की वजह से यह project अधिक दिलचस्प लगा। eza जैसे मौजूदा tools की तुलना में यह क्यों ज़रूरी है, इसका व्यावहारिक motivation उतना महसूस नहीं हुआ। अगर 10,000 files की listing 40ms बनाम 20ms है, तो single run के हिसाब से शायद कोई फ़र्क महसूस नहीं होगा

    • यह मज़े-मज़े में io_uring का उपयोग सीखने के लिए बनाया गया एक experimental project है। वास्तविक समय-बचत प्रभाव मामूली है (ज़िंदगी भर में शायद 5 सेकंड बचें), और यही इसका मुख्य point नहीं था
    • वास्तव में जिन directories में लाखों JSON files होती हैं, वहाँ 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 आधुनिक cat replacement है (bat link)
    • coloring support के लिए LS_COLORS/dircolors जैसी standard approach लागू करना सबसे अच्छा होगा। GNU ls के colors अच्छे लगते हैं
  • किसी को यह जिज्ञासा थी कि सभी CLI tools io_uring का उपयोग क्यों नहीं करते। उसका अनुभव है कि जब वह nvme को usb 3.2 gen2 से जोड़ता है, तो साधारण tools से speed 740MB/s रहती है, जबकि aio या io_uring-आधारित tools से यह 1005MB/s तक पहुँच जाती है। उसका मानना है कि queue length strategy और lock reduction का भी असर है

    • portability बनाए रखने के लिए परंपरागत रूप से #ifdef जैसी macro branching के बिना लिखा जाता रहा है, इसलिए platform/version-specific नई technologies को अपनाने की रफ़्तार धीमी है। अब उसे लगता है कि अलग-अलग posixy platforms के बीच compatibility का फायदा पहले जितना बड़ा नहीं रहा
    • io_uring को प्रभावी ढंग से उपयोग करने के लिए async event-based model चाहिए। ज़्यादातर मौजूदा CLI tools सीधे-साधे और sequential style में लिखे गए हैं। अगर language स्तर पर async स्वाभाविक रूप से इस्तेमाल होता, तो porting आसान होती, लेकिन अभी बड़े refactoring की ज़रूरत है। io_uring भी पूरी तरह stable नहीं हुआ है, इसलिए कुछ लोग मानते हैं कि अगली नई technology आने तक इंतज़ार करना, या automatic porting tools/AI के उभरने का देखना ठीक हो सकता है
    • io_uring के शुरुआती adoption phase में बड़े security issues थे (करीब 2 साल पहले)। अब उनमें से काफ़ी सुलझ चुके हैं, लेकिन adoption पर उसका बुरा असर पड़ा
    • security के नज़रिए से io_uring काफ़ी कठिन है
    • io_uring बहुत नई technology है, जबकि coreutils (और उससे पहले आने वाले packages) दशकों पुरानी परंपरा रखते हैं, इसलिए io_uring adoption में और समय लगेगा। “shared ring buffer” style की syscalls को पुराने synchronous तरीके की जगह standard बनने में समय लगेगा
  • strace में देखा गया कि lsd हर file पर लगभग 5 बार clock_gettime call करता है। सटीक कारण स्पष्ट नहीं, शायद हर 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 नहीं करता, इसलिए असली लाभ bulk stat (जैसे ls -l) में दिखता है। कुछ लोगों को खेद है कि अगर getdents handling को asynchronous और overlapped बनाया जा सकता, तो और अच्छा होता

    • POSIX अगर NFS के readdirplus (getdents + stat) operation को standardize कर दे, तो io_uring का कुछ लाभ कम हो सकता है
  • यह मज़ेदार लगा कि .mjs और .cjs extensions के लिए icons हैं, लेकिन .c, .h, .sh जैसे file extensions के लिए नहीं हैं