1 पॉइंट द्वारा GN⁺ 2024-07-22 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • rr Linux पर असफल execution को एक बार रिकॉर्ड करके gdb में उसी execution को बार-बार replay करने देता है, जिससे reproduce करना मुश्किल C/C++ bugs को ट्रैक करना आसान हो जाता है
  • Replay के दौरान address space, registers, system call data और memory layout हर बार समान रहते हैं, इसलिए object addresses या event order जैसे debugging clues गायब नहीं होते
  • सामान्य gdb commands, scripting और IDE integration को support करता है, और hardware data watchpoint को reverse execution के साथ जोड़कर उस जगह तक वापस जा सकते हैं जहां value बदली थी
  • Firefox, Chrome, QEMU, LibreOffice, Go programs, multi-process workloads और containers तक संभालता है, लेकिन single-core emulation, shared memory, CPU और system call support coverage में कुछ सीमाएं हैं
  • Intermittent failures या fuzzer/random fault injection से निकली failures को save करके बार-बार analyze किया जा सकता है, इसलिए bug fix की लागत घटाने और software quality बढ़ाने में उपयोगी है

rr का debugging model

  • rr Linux के लिए C/C++ debugging tool है; यह gdb को replace करने के बजाय record-replay capability से gdb workflow को मजबूत करता है
  • जिस execution में failure हुआ हो उसे एक बार save कर लेने के बाद, उसी execution को बाद में जितनी बार चाहें debug किया जा सकता है
  • Replay live execution की तरह non-deterministically बदलता नहीं है; हर बार उसी state में आगे बढ़ता है
  • gdb के तहत efficient reverse execution देता है
    • breakpoints और data watchpoints set किए जा सकते हैं
    • रुचि वाले point तक तेजी से reverse-execute किया जा सकता है
  • यह real applications में इस्तेमाल होता है, और कई developers इसे वास्तविक bugs fix करने में उपयोग कर रहे हैं

समर्थित features और scope

  • rr की capabilities practical applications और gdb-based workflows के हिसाब से बनाई गई हैं
    • समान tools की तुलना में कम overhead, खासकर उन workloads में जो ज्यादातर single-threaded हैं
    • Firefox, Chrome, QEMU, LibreOffice, Go programs जैसी विभिन्न applications की recording और replay support
    • पूरे containers सहित multi-process workloads की recording, replay और debugging support
    • gdb scripting और IDE integration support
    • machines के बीच move किए जा सकने वाले durable और compressed traces का support
    • intermittent bugs को बेहतर तरीके से सामने लाने वाला Chaos mode उपलब्ध

Recording और replay flow

  • Application को rr record /your/application --args से record किया जाता है
  • Failure सहित पूरी execution disk पर save होती है, और बाद में rr replay से debug की जा सकती है
  • Replay के दौरान live execution नहीं, बल्कि recorded trace को debug किया जाता है
  • Address space, register contents और system call data हर replay में समान बने रहते हैं
  • अधिकतर सामान्य gdb commands वैसे ही इस्तेमाल किए जा सकते हैं
  • Debugging session फिर से शुरू करनी हो तो gdb के run command से recording को शुरुआत से replay करें
    • Restart के बाद भी वही execution फिर replay होती है
    • Debugging state restarts के बीच preserved रहती है
  • Dynamically allocated object का this pointer भी हर replay session में समान रहता है
    • Memory allocation हर बार समान होने से watch करने वाले address को hardcode किया जा सकता है

Reverse execution और watchpoint

  • rr values गलत set होने की वजह खोजते समय result से cause की ओर पीछे जाने वाली debugging संभव बनाता है
  • Firefox layout debugging example में mRect.width value गलत होने की पुष्टि के बाद watch -l mRect.width और reverse-cont का उपयोग किया जाता है
  • Hardware watchpoint और reverse execution को जोड़कर वह point खोजा गया जहां value 11220 से 12000 में बदली
  • यह तरीका समस्या दिखने वाले point से वास्तविक change point तक वापस जाने का काम घटा देता है

Installation और शुरुआत

  • Source से build करना हो तो Building And Installing instructions follow करें
  • जब package fit न हो तो source build recommended है
    • Kernel changes या OS updates के कारण कभी-कभी rr changes की जरूरत पड़ सकती है
  • Fedora installation example में rr-5.9.0-Linux-$(uname -m).rpm download करके sudo dnf install से install किया जाता है
  • Ubuntu installation example में rr-5.9.0-Linux-$(uname -m).deb download करके sudo dpkg -i से install किया जाता है

Intermittent failures से निपटने का तरीका

  • rr की मूल motivation intermittent failures को debug करना आसान बनाना थी
    • Intermittent failures में कुछ executions में failure दिखाई नहीं देता, इसलिए debugging मुश्किल होती है
    • Test execution को कम overhead के साथ record करते हुए जब failure होता है, तो उस execution को debugger में बार-बार replay किया जा सकता है
  • Deterministic replay सामान्य bug debugging में भी clues लगातार जमा करने देता है
    • सामान्य debugger में re-run करते समय रुचि वाले object addresses या important events का order बदल सकता है, जिससे पहले की जानकारी बेकार हो सकती है
    • rr में failed execution के बारे में मिली जानकारी replay दोहराने पर भी बनी रहती है
  • Debugging आमतौर पर result से cause की ओर पीछे जाने की प्रक्रिया होती है, इसलिए time में पीछे execute कर पाने से cause track करना आसान हो जाता है
  • rr low-overhead record-replay system और gdb के reverse execution commands के लिए practical backend देता है
  • यह कई बड़े-छोटे projects में developers द्वारा regularly इस्तेमाल किया जाने वाला working tool है

Deterministic replay किन states की guarantee देता है

  • rr Linux user-space process groups को record करता है
  • Record किए गए process को kernel से मिलने वाले सभी inputs और non-deterministic CPU effects को capture करता है
  • Replay instruction-level control flow, memory और register contents को preserve करने की guarantee देता है
  • Memory layout हमेशा समान रहता है, object addresses नहीं बदलते, register values समान रहती हैं, और system calls वही data return करते हैं
  • Fuzzers और random fault injection tools rr के साथ इस्तेमाल होने पर ज्यादा powerful हो जाते हैं
    • ऐसे tools intermittent failures पैदा करने में अच्छे होते हैं, लेकिन उसी failure को फिर reproduce करना मुश्किल हो सकता है
    • rr random execution को record करता है और failure होने पर saved recording से problem को deterministically debug करने देता है

मौजूदा record-replay tools से फर्क

  • rr पुराने idea record-and-replay debugging को specific design goals के हिसाब से implement करता है
  • शुरुआती focus Firefox था
    • कई record-replay techniques को specific language की जरूरत होती है या वे scale नहीं करतीं, इसलिए Firefox को handle करना मुश्किल होता है
    • Firefox एक complex application है, इसलिए अगर कोई tool Firefox debugging में useful है तो सामान्य रूप से भी useful होने की संभावना होती है
  • Deployability को महत्व देता है
    • rr सामान्य Linux kernel और general-purpose hardware पर चलता है
    • System settings में changes की जरूरत नहीं होती
    • कई अन्य techniques kernel changes या virtual machine में OS चलाने की मांग करती हैं
  • Low runtime overhead लक्ष्य है
    • gdb workflow को replace करना हो तो gdb इस्तेमाल करते समय जैसी speed से results मिलें, वैसा होना चाहिए
    • Low overhead test disturbance भी घटाता है
  • Design simplicity को महत्व देता है
    • Dynamic binary instrumentation जैसी complex techniques पर निर्भर approaches से बचता है
    • Simplicity rr की robustness और low overhead में भी योगदान देती है

Performance और सीमाएं

  • rr का overhead application workload पर निर्भर करता है
  • Firefox test suite में recording performance practical level की है
    • कुछ cases में slowdown ≤ 1.2x तक कम हो जाता है
    • 10 मिनट लगने वाला test suite rr recording में लगभग 12 मिनट लेता है
  • Overhead workload के हिसाब से काफी बदल सकता है
  • ज्यादातर single-threaded programs में इसका overhead known competing record-replay systems की तुलना में काफी कम है
  • मुख्य सीमाएं ये हैं
    • Single-core machine को emulate करता है, इसलिए parallel programs को single-core execution के कारण slowdown झेलना पड़ता है
    • Recording tree के बाहर के processes के साथ memory share करने वाले processes को record नहीं किया जा सकता
    • Recorded processes में X shared memory जैसी features automatically disabled कर दी जाती हैं
    • अपेक्षाकृत नया x86 CPU या Apple M1+ जैसे specific ARM CPU की जरूरत होती है
    • Recorded process द्वारा execute की जाने वाली सभी system calls की जानकारी होनी चाहिए
    • Firefox और कई applications के लिए जरूरी system calls की wide range support करता है, लेकिन complete नहीं है
    • Unsupported system calls को GitHub issue के रूप में report किया जा सकता है
    • Kernel changes, system library updates और नए CPU families के अनुसार updates की जरूरत पड़ सकती है

References और community

  • Extended Technical Report rr के काम करने के तरीके और performance को cover करने वाला overview material है
  • rr wiki rr से जुड़े technical topics cover करता है
  • सवाल mailing list या #rr on chat.mozilla.org पर पूछे जा सकते हैं
  • Demo videos भी उपलब्ध हैं
    • Video 7: Firefox record-replay का quick demo
    • Video 8: rr basic features का detailed demonstration
    • Video 9: Robert O'Callahan का rr high-level technical presentation

1 टिप्पणियां

 
GN⁺ 2024-07-22
Hacker News की रायें
  • rr में variable change breakpoints और reverse-continue को साथ इस्तेमाल करके बड़े codebase को reverse engineer करने में बहुत सफलतापूर्वक काम लिया है
    गहराई में छिपे core logic को निकालने में थोड़ा समय लगा, लेकिन यह उपयोगी रहा

    • दिलचस्प लग रहा है; जानना चाहूंगा कि क्या इस पर शेयर करने लायक कोई write-up है
    • सोच रहा हूं कि क्या उस बड़े codebase को, भले यह सही शब्द न हो, dynamically typed भाषा में लिखा हुआ माना जा सकता है
  • यह भी उल्लेखनीय है कि किसी ने rr को Rust में port करने की कोशिश की थी, और करीब 60 हजार lines लिखने के बाद project को archive कर दिया
    C++ से Rust में दोबारा लिखने के प्रभाव, फायदे, सीमाएं और कठिनाइयों की तुलना करने वाली यह एक दिलचस्प case study हो सकती है
    https://github.com/sidkshatriya/rd/

    • rr maintainer के नजरिए से Sid का काम अच्छा था और हमने उसका समर्थन भी किया
      लेकिन उसे official version में ले जाना मुश्किल होने के बड़े कारण थे: 1) rr में 10 सालों में जमा हुए, अजीब kernel/process behavior से निपटने वाले कई जटिल fixes हैं, जिन्हें porting के दौरान खो देने की चिंता थी, और 2) rr के ऊपर बने closed-source project remix[0] को भी साथ में port करना पड़ता
      [0] https://robert.ocallahan.org/2020/12/rr-remix-efficient-repl...
    • पिछले कुछ सालों से चल रहे “X/Y/Z को Rust में दोबारा लिखें” वाले trend को मैं ठीक से समझ नहीं पाता
      Rust के बारे में ज्यादा नहीं जानता, लेकिन C के साथ इसकी interoperability अच्छी लगती है। अगर software पहले से अच्छी तरह काम कर रहा है, तो Rust rewrite का फायदा क्या है, यह जानना चाहूंगा
    • अच्छी analysis होगी, लेकिन शायद आसान नहीं होगी
      मोटे तौर पर देखने पर rr 1.0 में 3 साल लगे, 3–4 बड़े contributors थे, और कम से कम 5 लोगों ने contribute किया दिखता है। आज का rr उसके ऊपर 10 साल के अतिरिक्त काम का नतीजा है
  • सच में यह केवल C/C++ के लिए है या नहीं, यह जानना चाहूंगा
    मेरी सीमित समझ में debugger को symbols की list, Windows की .pdb files जैसी चीजें और Linux में उनके equivalents, system calls की समझ, और ऐसी ही बाकी चीजों की जरूरत होती है। मैंने सोचा था कि debug किए जा रहे binary को किसने generate किया, इससे उसे बहुत फर्क नहीं पड़ता। बेशक, मानकर चलें कि यह native code है
    जानना चाहूंगा कि rr Rust, Zig, Odin, Nim जैसी भाषाओं में भी काम नहीं करता क्या। Python, JS, C# जैसी managed memory इस्तेमाल करने वाली भाषाओं से तो स्वाभाविक रूप से उम्मीद नहीं है

    • मैं इसे Zig के साथ इस्तेमाल कर रहा हूं
      Zig के allocator के साथ इस्तेमाल करने पर यह काफी सुविधाजनक है। free करते समय यह 0xaa bytes लिखता है और address reuse नहीं करता, जिससे crash होने की संभावना बढ़ जाती है, और फिर उस memory पर watchpoint लगाकर उसे free किए जाने के समय तक पीछे लौटा जा सकता है
    • पहले मैंने एक बहुत specific rpython build पर rr चलाया था; यह बात हैरान कर सकती है कि इसमें अभी भी दिलचस्पी बनी हुई है
      https://github.com/python/devguide/issues/1283
      https://morepypy.blogspot.com/2016/07/reverse-debugging-for-...
      https://github.com/mesalock-linux/mesapy/blob/mesapy2.7/READ...
    • Julia में RR का काफी इस्तेमाल होता है
      यह system को सिर्फ GDB के नजरिए से दिखाता है, लेकिन चाहे interpreted language हो या compiled language, यह काम कर सकता है
      जहां यह काम नहीं करता, वह मामला है जब driver mapped address को सीधे update करता है। CUDA इसका एक उदाहरण है; replay करने के लिए driver interactions को model करना पड़ेगा, और UVM तक पहुंचने से पहले ही ऐसा हो जाता है
      एक और अच्छी बात यह है कि RR process tree को record करता है, इसलिए executable द्वारा शुरू किए गए दूसरे processes को आसानी से देखा जा सकता है
    • rr असली debugger हिस्से के लिए gdb का इस्तेमाल करता है, इसलिए जो gdb में चलता है वह rr में भी चलता है
      हालांकि rr को सभी system calls को wrap करना पड़ता है, इसलिए यह Linux-specific है और Windows पर नहीं चलता। Linux का symbol information format DWARF है
    • Rust में भी इस्तेमाल होता है: https://bitshifter.github.io/rr+rust/index.html#1
  • rr वाकई शानदार है, लेकिन जब भी मैंने इसे “बड़ा हथियार” समझकर निकालने का फैसला किया, लगभग हमेशा मामला concurrency bug का था, और इसलिए rr अक्सर उसे reproduce नहीं कर पाया
    फिर भी अगर कुछ भाषाएं rr को सीधे अपने toolchain में शामिल कर दें तो बहुत अच्छा होगा। बेशक आप कभी भी rr/gdb को “बस ऐसे ही” इस्तेमाल कर सकते हैं, लेकिन कल्पना करें कि rr call setup और उपयोग Python के pdb जितना आसान हो जाए

    • rr चलाते समय chaos mode option इस्तेमाल करने से कुछ concurrency issues सामने आ सकते हैं
      मूल रूप से यह running thread को बार-बार बदलकर कई cores पर एक साथ execution जैसी स्थिति की नकल करता है। मेरे लिए इसने सच में कुछ race conditions ढूंढीं, हालांकि सीमाएं तो हैं
    • सच में rr से पकड़ा जा सकने वाला एक concurrency bug था
      MPI job में केवल rank 0 पर rr लगाया था, और अलग-अलग send/recv order जहां समस्या पैदा कर रहा था, वह जगह ढूंढ निकाली। ऊपर से यह native code generation से काफी जुड़ा Python model था, इसलिए मामला काफी जटिल था
    • एक और चीज जिसे rr अफसोस के साथ support नहीं करता, वह GPU है
      इस्तेमाल करना चाहूंगा, लेकिन मेरे ज्यादातर काम में किसी न किसी तरह GPU शामिल होता है
    • मेरे साथ भी कुछ ऐसा ही है
      जब सच में इसकी जरूरत थी, वह Mac पर था, लेकिन दुर्भाग्य से rr केवल Linux पर चलता है
      Mac पर चलने वाला Undodb है, और शायद multithreading भी कर सकता है, लेकिन अफसोस इसकी कीमत करीब 50 हजार डॉलर है
  • rr पर आधारित, लेकिन पूरे प्रोग्राम execution को query किए जा सकने वाले database के रूप में जोड़ने वाला https://pernos.co/ भी देखने लायक है
    यह ऐसे काम कर सकता है

    [...] आपको बस गलत value पर क्लिक करना है। चूँकि पूरे program का history मौजूद है, Pernosco तुरंत समझा सकता है कि यह value कहाँ से आई। value को memcpy या registers के अंदर-बाहर move होने जैसी events के पीछे तक trace किया जाता है, और value जहाँ “originated” हुई वहाँ तक के हर step को अपने-आप खुलने वाले “Dataflow” panel में दिखाया जाता है। code पढ़ने या समझने और यह सोचने की जरूरत नहीं कि क्या हुआ होगा; debugger से पूछिए कि वास्तव में क्या हुआ था।
    https://pernos.co/examples/race-condition

  • GDB में built-in reverse debugging भी है: https://www.sourceware.org/gdb/wiki/ProcessRecord/Tutorial
    मेरा मानना है कि rr ज्यादा features और flexibility देता है, लेकिन खैर, GDB खुद भी काफी समय से reverse debugging कर सकता है

    • अगर आप इसका जिक्र करना चाहते हैं, तो लगभग तय है कि आपने इसे सच में इस्तेमाल नहीं किया है
      GDB implementation में आप जब चाहें recording शुरू/बंद कर सकते हैं, इसलिए यह rr से सुविधाजनक है, लेकिन efficiency कई orders of magnitude कम है। यह सिर्फ बहुत छोटे code fragments के लिए काम का है; बाकी मामलों में यह व्यावहारिक रूप से हमेशा के लिए चलता रहेगा या resources खत्म हो जाएँगे
    • मैंने एक बार ऐसे platform पर GDB की built-in reverse debugging सफलतापूर्वक इस्तेमाल की थी जिसे rr तब तक support नहीं करता था
      यह काम किया और bug track करने में मदद मिली, लेकिन दर्दनाक रूप से धीमा था। इसे इस्तेमाल लायक बनाने के लिए input size घटाना पड़ा, और सौभाग्य से ऐसा करने के बाद भी problem reproduce हो रही थी
    • gdb की built-in replay implementation program पर लगभग 10000 गुना slowdown लगाती है
      अगर आप मनचाहे program state तक 10000 से कम restarts में binary search कर सकते हैं, तो reverse execution इस्तेमाल करने की तुलना में machine time कम लगेगा। असल में slowdown इतना ज्यादा है कि कई बार debugger को interactive तरीके से लगभग सही state तक कई बार ले जाकर फिर program restart करना ही पर्याप्त होता है
      gdb की replay सुविधा को मैं उपयोगी इसलिए बना पाया क्योंकि मेरे पास ऐसा input file था जो शुरू होने के 1 सेकंड से भी कम समय में program crash करा देता था। इसलिए “यह variable गलत है” से “यह variable उस गलत value पर कैसे set हुआ?” तक कुछ मिनट इंतजार करके पीछे जाया जा सकता था
    • अगर मेरी याद सही है, तो rr gdb वाले से पहले आया था
  • Windows पर इसी काम के लिए WinDbg इस्तेमाल कर सकते हैं
    multithreaded problems debug करने के लिए support बेहतर है
    https://www.forrestthewoods.com/blog/windbg-time-travelling-...

    • WinDbg instruction-level emulation आधारित time travel implementation इस्तेमाल करता है, इसलिए उस technique के साथ आने वाला 10~20 गुना slowdown होता है
      rr record-replay तरीके वाला time travel debugging implementation इस्तेमाल करता है, और सही implementation हो तो overhead काफी कम हो सकता है। आखिरी बार जब मैंने देखा था, rr का overhead करीब 2 गुना slowdown था, और अगर याद सही है तो मैंने दूसरे record-replay time travel debuggers में 10% के स्तर का भी देखा है
      10% WinDbg की तुलना में 100 गुना सस्ता है, और production में हमेशा on रखने के लिए पर्याप्त कम है। यह game-changing अंतर है
  • बहुत पहले VMWare Workstation भी यह feature support करता था
    सिर्फ user-space programs ही नहीं, VM के अंदर के kernel और drivers तक के लिए यह संभव था। feature release हुआ और कुछ versions तक रहा, फिर internal politics के कारण हटा दिया गया

    • उससे पहले शायद AMD SimNow था
      यह plugins से extend किया जा सकता था, और plugin emulated CPU को पूरी तरह control कर सकता था। सोचता हूँ कि कहीं ऐसा कुछ अब भी मौजूद है या नहीं
  • सोच रहा हूँ कि rr की Ryzen CPU problem अब पक्के तौर पर बीती बात हो चुकी है या नहीं

    • हाँ
      मैं काफी नए Threadripper Pro 7950 पर Firefox run record करने के लिए rr रोज पूरे दिन इस्तेमाल कर रहा हूँ, और Pernosco के साथ भी। GitHub पर rr wiki में इसे काम कराने का तरीका बताया गया है। बस छोटा workaround apply कर दें तो यह बहुत stable चलता है
  • पुरानी चर्चाएँ भी हैं
    https://news.ycombinator.com/item?id=31617600 (जून 2022)
    https://news.ycombinator.com/item?id=18388879 (नवंबर 2018)