2 पॉइंट द्वारा GN⁺ 2026-01-08 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • हाल की चर्चाओं में उठे I/O प्रदर्शन और CPU प्रोसेसिंग स्पीड के असंतुलन को प्रयोग से सत्यापित करते हुए दिखाया गया कि वास्तव में अब भी CPU ही मुख्य सीमा है
  • sequential read speed cold cache में 1.6GB/s और warm cache में 12.8GB/s तक पहुँचती है, लेकिन single-threaded word frequency गणना केवल 278MB/s के स्तर पर रहती है
  • कोड की branch संरचना vectorization में बाधा डालती है, और सिर्फ साधारण lowercase conversion optimization से भी यह केवल लगभग 330MB/s तक ही सुधरती है
  • wc -w कमांड भी केवल 245MB/s तक पहुँचती है, जिससे पुष्टि होती है कि डिस्क नहीं बल्कि CPU गणना और branch processing bottleneck हैं
  • AVX2 आधारित manual vectorization से इसे 1.45GB/s तक बढ़ाया गया, लेकिन यह अब भी sequential read speed का लगभग 11% ही है, जो साबित करता है कि bottleneck I/O नहीं बल्कि CPU है

I/O स्पीड और CPU प्रदर्शन की तुलना

  • Ben Hoyt के दावे के अनुसार, यह जाँचा गया कि हाल की sequential read speed में वृद्धि क्या CPU स्पीड की ठहराव स्थिति से आगे निकल चुकी है
    • उसी तरीके से मापने पर cold cache में 1.6GB/s और warm cache में 12.8GB/s दर्ज हुए
  • लेकिन single thread पर word frequency गणना चलाने पर यह केवल 278MB/s रही
    • यानी cache warm होने पर भी यह disk read speed की लगभग 1/5 ही है

C आधारित word frequency गणना प्रयोग

  • GCC 12 से optimized.c को -O3 -march=native विकल्पों के साथ compile करने के बाद 425MB input file पर चलाया गया
    • परिणाम: 1.525 सेकंड लगे, प्रोसेसिंग स्पीड 278MB/s
  • कोड के भीतर multiple branches और early exit ने compiler की vectorization optimization को बाधित किया
    • lowercase conversion logic को loop के बाहर ले जाने के बाद यह 330MB/s तक सुधरा
    • Clang का उपयोग करने पर vectorization बेहतर हुई

साधारण word count (wc -w) तुलना

  • frequency गणना की जगह केवल शब्दों की संख्या गिनने वाली wc -w कमांड चलाई गई
    • परिणाम: 245.2MB/s, जो अपेक्षा से धीमी थी
  • wc ' ', '\n', '\t' जैसे विभिन्न whitespace characters और locale characters को संभालती है
    • इसलिए यह केवल साधारण spaces को विभाजक मानने वाले कोड की तुलना में अधिक गणना करती है

AVX2 आधारित vectorization का प्रयास

  • आधुनिक CPU फीचर्स का उपयोग करते हुए AVX2 instruction set के साथ vectorization लागू की गई
    • 256-bit registers का उपयोग, डेटा को 32-byte alignment के साथ
    • whitespace character comparison के लिए VPCMPEQB निर्देश का उपयोग
  • bit mask (PMOVMSKB) और Find First Set(ffs) निर्देशों से word boundaries का पता लगाया गया
    • प्रेरणा Cosmopolitan libc के strlen implementation से ली गई

प्रदर्शन परिणाम और निष्कर्ष

  • manual vectorized code (wc-avx2) ने 1.45GB/s प्रोसेसिंग स्पीड हासिल की
    • wc -w के समान परिणाम (82,113,300 शब्द) सत्यापित किए गए
  • cold cache स्थिति में भी अब भी user mode computation time ही प्रमुख रहा
    • इससे पुष्टि हुई कि disk I/O की तुलना में CPU गणना bottleneck है
  • कुल मिलाकर disk speed पर्याप्त तेज़ है, लेकिन branch processing और hash calculation जैसे CPU operations अब भी सीमित करने वाले कारक बने हुए हैं
  • कोड और प्रयोग के परिणाम GitHub (haampie/wc-avx2) पर सार्वजनिक हैं

1 टिप्पणियां

 
GN⁺ 2026-01-08
Hacker News की राय
  • मेरा मानना है कि आधुनिक CPU की performance limit इस बात से तय होती है कि एक single core कितना data संभाल सकता है, यानी memcpy() की speed
    ज़्यादातर x86 cores लगभग 6GB/s तक पहुँचते हैं, जबकि Apple M series करीब 20GB/s के स्तर पर है
    विज्ञापनों में दिखने वाले ‘200GB/s’ जैसे आँकड़े पूरे cores के aggregate bandwidth होते हैं; single core अब भी लगभग 6GB/s के आसपास ही रहता है
    इसलिए आप चाहे कितना भी perfect parser लिख लें, इस सीमा को पार नहीं कर सकते
    लेकिन zero-copy format इस्तेमाल करने पर CPU बेकार data को skip कर सकता है, इसलिए सिद्धांततः 6GB/s से ‘ज़्यादा’ हासिल किया जा सकता है
    मेरे द्वारा विकसित किया जा रहा Lite³ format इसी सिद्धांत का उपयोग करता है और simdjson से अधिकतम 120 गुना तेज़ performance दिखाता है

    • मुझे लगता है कि बताए गए single-core आँकड़े बहुत कम हैं
      उदाहरण के लिए, Zen 1 single core पर 25GB/s दिखाता है(संदर्भ लिंक)
      मेरे लिखे microbenchmark के अनुसार Zen 2, AVX के बिना 17GB/s और non-temporal AVX के साथ 35GB/s तक पहुँचता है
      Apple M3 Max पर non-temporal NEON के साथ 125GB/s तक मापा गया
      इसलिए x86 के लिए 6GB/s और Apple के लिए 20GB/s वाले आँकड़े वास्तविकता से काफ़ी कम लगते हैं
    • यह सीमा आती कहाँ से है, यह जानना चाहता हूँ — क्या इसकी वजह core और cache, या memory controller के बीच की bus architecture है?
    • यह भी जानना चाहता हूँ कि Apple M series में x86 की तुलना में प्रति core bandwidth 3 गुना ज़्यादा क्यों है
    • आधुनिक chips में केवल CPU से memory bandwidth को saturate करना मुश्किल है, और इसके लिए iGPU का उपयोग करना पड़ता है
      क्योंकि iGPU unified memory तक पहुँच सकता है
      इसलिए बड़े memory copy, parallel parsing, compression/decompression जैसे कामों में iGPU को blitter की तरह इस्तेमाल करना तकनीकी रूप से फ़ायदेमंद है
      हालाँकि zero-copy format में जिस ‘skip’ की बात है, वह cache line unit पर होता है
    • Samsung NVMe SSD 14GB/s read speed का दावा करता है; अगर CPU single core 6GB/s है, तो इन दोनों के बीच संबंध दिलचस्प है
  • लगता है कि मूल लेखक ने time command के output की ग़लत व्याख्या की है
    system time वह CPU time है जो kernel ने process की ओर से इस्तेमाल किया
    उदाहरण में real 0.395s, user 0.196s, sys 0.117s हो तो CPU ने कुल 313ms ही काम किया, और बाकी 82ms idle state में था
    यानी यह disk subsystem से तेज़ तो चला, लेकिन अंतर बहुत बड़ा नहीं था
    साथ ही I/O path CPU-bound है — भले ही disk और code अनंत तेज़ हों, kernel I/O code चलाने में फिर भी 117ms लगते हैं

  • मैं इस पोस्ट का लेखक हूँ। इसका एक follow-up भी है: I/O is no longer the bottleneck, part 2

    • मैंने पहले एक word frequency counting contest में भाग लिया था
      प्रतिभागियों द्वारा इस्तेमाल की गई अलग-अलग optimization techniques पर यह analysis post दिलचस्प है
      समस्या की complexity या whitespace classification की संख्या के आधार पर approaches अलग थीं
    • अगर यह test single core पर किया गया था, तो ऊपर कही गई “6GB/s limit” प्रयोगात्मक रूप से खारिज हो जाती है
  • performance bottleneck हमेशा “CPU या I/O” जैसे किसी एक factor से तय नहीं होता, बल्कि असली workload में सबसे पहले saturate होने वाले resource से तय होता है
    वह CPU, memory bandwidth, cache, disk, network, lock, latency — कुछ भी हो सकता है
    इसलिए measure करें, profiling से साबित करें, और बदलाव के बाद फिर से measure करें

  • समस्या CPU या I/O नहीं, बल्कि latency और throughput के बीच संतुलन है
    ज़्यादातर software latency को नज़रअंदाज़ करते हैं, इसलिए धीमे होते हैं
    data को memory में linear तरीके से रखना, या batch processing और parallelization लागू करना, इन्हें काफ़ी तेज़ बना सकता है

  • एक ऐसी architecture की कल्पना करें जो सिर्फ CPU ↔ cache ↔ non-volatile storage संरचना से बनी हो
    अगर mmap() की performance characteristics malloc() जैसी हों, तो program memory को file name से निर्दिष्ट करके persistence OS पर छोड़ी जा सकती है
    अब भी बहुत से software design hard disk era की सीमाओं में बँधे हुए हैं

    • लेकिन fsync() अब भी धीमा है
      असली persistence के लिए, rotational disk हो या न हो, अलग approach की ज़रूरत है
    • Linux पर भी ऐसा कुछ लागू किया जा सकता है
      वास्तव में ज़्यादातर memory requests mmap() के ज़रिए ही पूरी होती हैं
      लेकिन kernel के लिए access pattern का अनुमान लगाना मुश्किल होता है, इसलिए यह read/write से धीमा हो सकता है
  • cloud environment में performance कभी-कभी pricing lever भी बन जाती है
    hardware performance ने हैरान कर देने वाली प्रगति की है, लेकिन कुछ software, ख़ासकर Windows या messenger apps, उल्टे और धीमे लगते हैं

    • सच तो यह है कि cloud instance performance M1 MacBook से 5 गुना धीमी और कहीं ज़्यादा महंगी होती है
      developer remote workstation के रूप में यह अक्षम है
    • ज़्यादातर GUI apps के धीमे होने का कारण अब भी I/O wait है
      Telegram या FB Messenger तेज़ हैं, लेकिन Teams या Skype नहीं
    • CRT monitors data को और तेज़ दिखाते थे
      कुछ LCD में 500ms तक की latency होती है
  • जब NVMe SSD पहली बार आए थे, तब मज़ाक में कहा जाता था, “अब तो हमारे पास 2TB RAM है”
    लेकिन आजकल GPU servers में सचमुच 2TB RAM लगी होती है — यह कमाल की engineering है

    • मैंने पहले एक used Epyc server में 2TB DDR4 RAM configuration 5,000 डॉलर में देखी थी
      अब लगता है तब खरीद लेना चाहिए था
  • high-concurrency environment में OLAP database को optimize करने के अपने अनुभव के आधार पर कहूँ तो bottleneck ज़्यादातर memory speed थी

  • I/O bottleneck मूल रूप से sequential read नहीं, बल्कि seek time से जुड़ा विचार था
    मैं पोस्ट का मुख्य तर्क समझता हूँ, लेकिन इस बिंदु को उठाना चाहता हूँ

    • CXL/PCIe जैसी आधुनिक तकनीकों की वजह से अब RAM और memory controller को भी एक तरह का I/O device माना जा सकता है
    • पुराने database classes में I/O performance को hard disk seek time से मापा जाता था
      sequential read speed को code से सुधारा नहीं जा सकता था, इसलिए non-sequential access optimization ही मुख्य बात थी