[HN Gopher] Speeding up the Rust edit-build-run cycle
___________________________________________________________________
Speeding up the Rust edit-build-run cycle
Author : tempaccount420
Score : 83 points
Date : 2024-11-14 19:30 UTC (3 hours ago)
(HTM) web link (davidlattimore.github.io)
(TXT) w3m dump (davidlattimore.github.io)
| renewiltord wrote:
| Good set of tips. Thank you.
| Comma2976 wrote:
| It was my pleasure.
| omani wrote:
| thanks
| Comma2976 wrote:
| You're welcome
| nuudlman wrote:
| Not linking debug info must be some kind of sick joke. What is
| the point of a debug build without symbols?
| 0x457 wrote:
| Enable them when you need to debug. This is for speeding up
| "edit-build-run" workflows.
| nuudlman wrote:
| It's a lot faster to add a log point in a debugger than to
| add a print statement and recompile. Especially with cargo
| check, I really don't see the point of non-debuggable builds
| (outside of embedded, but the size of debuginfo already makes
| that a non-starter).
| RichardLake wrote:
| Doesn't rust have overflow checks in debug and skips them in
| release?
| 0x457 wrote:
| Rust has compiled time overflow checks enabled by default in
| any profile. Runtime overflow checks are disabled by default
| in release profile.
| vbezhenar wrote:
| 1. Skipping some optimizations to build faster.
|
| 2. Conditionally compiling some code like logging (not sure if
| matters for typical Rust projects, but for embedded C projects
| it's typical).
|
| 3. Conditionally compiling assertions to catch more bugs.
|
| I'm using logs, because debugger breaks hardware. Very rarely
| do I need to reach debugger. Even when hard exception occurs,
| usually enough info is logged to find out the root cause of the
| bug.
| vlovich123 wrote:
| > because debugger breaks hardware
|
| What? Seems like you're talking about embedded but I've done
| a lot of embedded projects in my time and I've never had a
| debugger that breaks the HW.
| viraptor wrote:
| Depends what you're working on. Stopped in an unfortunate
| place? That one element didn't get turned off and burned
| out. Or the motor didn't stop. Or the crucial interrupts
| got missed and your state is now reset. Or...
| bippihippi1 wrote:
| are there debugging tools specifically for situations
| like that? do you just write code to test manually? How
| do you ensure dev builds don't break stuff like that even
| without considering debugging?
| rcxdude wrote:
| The most useful tool is a full tracing system (basically
| a stream of run instructions you can use to trace the
| execution of the code without interrupting it), but
| unfortunately they're quite expensive and proprietery,
| and require extra connections to the systems that do
| support them, so they're not particularly commonly used.
| Most people just use some kind of home-grown
| logging/tracing system that tracks the particular state
| they're interested in, possibly logged into a ringbuffer
| which can be dumped when triggered by some event.
| bsder wrote:
| On embedded, debuggers almost never work until you get to
| really expensive ones.
|
| In addition, debuggers tend to obscure the failure because
| they turn on all the hardware which tends to make bugs go
| away if they are related to power modes.
|
| One of my "best" debuggers for embedded was putting an
| interactive interpreter over a serial interface on an
| interrupt so I could query the state of things when a
| device woke up even if it was hung--effectively a run time
| injectable "printf".
|
| Crude, but it could trace down obscure bugs that were rare
| because the device would stay in the failure mode.
|
| The bigeest problem was maintaining the database of code so
| that we knew _exactly_ what build was on a device. We had
| to hash and track _the universe_.
| ryangs wrote:
| >Debug information tends to be large and linking it slows down
| linking quite considerably. If you're like many developers and
| you generally use println for debugging and rarely or never use
| an actual debugger, then this is wasted time.
|
| Interesting. Is this true? In my work (java/kotlin, primarily in
| app code on a server, occasional postgres or frontend js/react
| stuff), I'm almost always reaching for a debugger as an
| enormously more powerful tool than println debugging. My tests
| are essentially the println, and if they fail for any interesting
| reason I'll want the debugger.
| Aurornis wrote:
| println debugging is where everyone starts. Some people never
| graduate to knowing how to use a debugger.
|
| Debugging through log data still has a place, of course.
| However, trying to do all of your debugging through println is
| so much harder, even though it feels easier than learning to
| use a debugger.
| 0x457 wrote:
| To be fair, if your code is multithreaded and sensitive to
| pauses, it becomes harder to debug with a debugger.
|
| Ultimately, if you have a good logging setup and kinda know
| where the issue is a quick log message could be faster than
| debugging if all you want to do is look a variable value.
| pjmlp wrote:
| That is where OS tracing like DTrace and ETW come into
| play, which can then be loaded into a debugging session.
| stouset wrote:
| I am comfortable using a debugger, but println debugging is
| easy, fast, and disproportionately effective for most of my
| debugging in practice.
|
| I reach for a "real" debugger when necessary, but that's less
| than 5% of the time.
| bluGill wrote:
| Depends on the developer. in the Practice of Programming
| https://en.m.wikipedia.org/wiki/The_Practice_of_Programming by
| Brian W. Kernighan and Rob Pike they say they use debuggers
| only to get a stack trace from a core dump and use printf for
| everything else. You can disagree but those are known very good
| programmers.
| dgfitz wrote:
| What if the program doesn't crash? It just black-boxes the
| data incorrectly? I can find that error infinitely faster
| with a debugger.
| bluGill wrote:
| They use printf. Which they claim is faster.
| dgfitz wrote:
| I'm not against printf at all, my lifetime commit history
| is evidence of that. Do you also think that in the case
| of a coredump not existing, that printf is faster?
| Sincere question. I'm having an internal argument with
| myself about it at the moment and some outside
| perspective would be most welcome.
| ehaliewicz2 wrote:
| printf isn't faster if you want to single step through
| code to find math precision errors.
|
| I've had to do that on a system that didn't support
| debugging. It was hell.
| grey-area wrote:
| Your existing logs will tell you roughly where and you just
| insert some more log lines to check the state of the data.
|
| Depends how fast your build/run cycle is and how many
| different prcocesses/threads whether a debugger will be
| faster/easier but a lot of it just comes down to
| preference. Most time spent debugging for me at least is
| spent thinking about the probable cause then choosing what
| state to look at.
| dietr1ch wrote:
| Printf debugging excels on environments where there's
| already good logging. Here I just need to pinpoint where in
| my logs things have already gone wrong and work my way
| backwards a bit.
|
| You could do the same with a debugger setting up a
| breakpoint, but the logs can better surface key
| application-level decisions made in the process to get to
| the current bad state.
|
| On a debugger I need to wind back on all functions, which
| it might get awful as some of them might be likely correct
| library calls that you need to skip over when going back in
| time, but that will take a huge portion of the functions
| called before the breakpoint. I don't think it's impossible
| to do with a debugger, but logging sort of bypasses the
| process of telling the debugger what's relevant so it can
| hide the rest, and it might already be in your codebase,
| but there's no equivalent annotations already there in the
| code to help the debugger understand what's important.
|
| To me printf helps surfacing the relevant application-level
| process to get to a broken state, and debuggers help
| understand hairy situations where things have gone wrong at
| a lower level, say missing fields or memory corruption, but
| these days with safer languages lower level issues should
| be way less frequent.
|
| ---
|
| On a side-note, it doesn't help debuggers that going back
| in time was really hard with variable-length instructions.
| I might be wrong here, but it took a while until `rr` came
| out.
|
| I do think that complexities like that resulted in spending
| too much time dealing with hairy details instead of
| improving the UI for debugging.
| canucker2016 wrote:
| But what source code debuggers did they have available?
|
| Other than gdb, I can't name any Unix C source code
| debuggers. I believe they were working on Unix before GDB was
| created (wikipedia says gdb was created in 1986 -
| https://en.wikipedia.org/wiki/Gdb).
|
| Plan 9 has acid, but from the man page and english manual,
| the debugger is closer to cli/tui than gui.
|
| see https://9fans.github.io/plan9port/man/man1/acid.html and
| https://plan9.io/sys/doc/acid.html
| fiedzia wrote:
| Debugging in Rust is substantially less common for me (and
| probably not only for me) because it is less often needed and
| more difficult - many things that are accessible in interpreted
| world don't exist in native binary.
|
| I do care about usable tracebacks in error reports though.
| Animats wrote:
| The only time I use a debugger with Rust is when unsafe code in
| some library crate messes up. My own code has no "unsafe". I
| have debug symbols on and a panic catcher that displays a
| backtrace in a popup window. That covers most cases.
|
| Rust development is mostly fixing compile errors, anyway. Once
| it compiles, it often works the first time. What matters is
| compile time for error compiles, which is pretty good.
|
| Incremental compile time for my metaverse client is 1 minute 8
| seconds in release mode. That's OK. Takes longer to test a new
| version.
| toast0 wrote:
| I trained in the cout school of debugging. I can use a
| debugger, and sometimes do, but it's really hard to use a
| debugger effectively when you're also dealing with concurrency
| and network clients. Maybe one day, I'll learn how to use one
| of the time traveling debuggers and then I can record the
| problem and then step through it to debug it.
| dgunay wrote:
| I use the debugger fairly regularly, though for me I'm on a
| stack where friction is minimal. In Go w/ VS Code, you can just
| write a test, set your breakpoints, hit "debug test", and
| you're in there in probably less than 20 seconds.
|
| I am like you though, I don't typically resort to it
| immediately if I think I can figure out the problem with a
| quick log. And the times where I've not had access to a
| debugger with good UX, this tipping point can get pushed quite
| far out.
| jesse__ wrote:
| I came here to write exactly this .. if I was drinking
| something I would have spit it everywhere laughing when I read
| it.
|
| I guess 'many developers' here probably refers to web
| developers who don't use the debugger, cause it's mostly
| useless/perpetually broken in JS land ..? I rely heavily on the
| debugger; can't imagine how people work without one.
| bippihippi1 wrote:
| when you write async JS code the debugger essentially adds no
| value over printing
| eminence32 wrote:
| In my experience Java debuggers are exceptionally powerful,
| much more so than what I've seen from C/C++/Rust debuggers.
|
| If I'm debugging some complicated TomEE application that might
| take 2 minutes to start up, then I'm absolutely reaching to an
| IntelliJ debugger as one of my first tools.
|
| If I'm debugging some small command line application in Rust
| that will take 100ms to exhibit the failure mode, there's a
| very good chance that adding a println debug statement is what
| I'll try first
| freeone3000 wrote:
| CLion adds the power of IntelliJ debuggers to Rust. It works
| _exceptionally_ well.
| Aurornis wrote:
| > If you're like many developers and you generally use println
| for debugging and rarely or never use an actual debugger
|
| You lost me here.
|
| Using a debugger to step through the code is a huge timesaver.
|
| Inserting println statements, compiling, running, inserting more
| println, and repeating is very inefficient.
|
| If you learn to use a debugger, set breakpoints, and step through
| code examining values while you go then the 8 seconds spent
| compiling isn't an issue.
| Ar-Curunir wrote:
| Just ignore that part then? You don't have to stop reading the
| rest of the (very good) article lol.
| sunshowers wrote:
| Step through debuggers and tracers are two different dimensions
| of debugging, and not directly comparable.
| fmbb wrote:
| > Inserting println statements, compiling, running, inserting
| more println, and repeating is very inefficient.
|
| That all depends on how long it takes to compile and run.
|
| > If you learn to use a debugger, set breakpoints, and step
| through code examining values while you go then the 8 seconds
| spent compiling isn't an issue.
|
| Meh, it's fine.
|
| You still have to set new ones and re-run your code to trigger
| the reproduction iteratively if you don't know where anything
| is wrong.
|
| Clicking "add logging break point here" and adding a print
| statement is really not very different. In my experience the
| hard part is know where you want to look. Stepping through all
| your code line by line and looking at all values every step is
| not a quick way to do anything. You have to divide and conquer
| your debugging smartly, like a binary search all over your call
| sites in the huge tree-walk that is your program.
| forrestthewoods wrote:
| Stepping through code and adding breakpoints is a spectacular
| way to figure out where to put log statements. Modern code is
| so abstract that it's nigh impossible to figure out what the
| fuck function even gets called just from looking at code.
| saurik wrote:
| Engh... I used to rely on a debugger a lot 25 years ago when I
| was learning to program, and was extremely good at making it
| work and using its quirks; but, I was building overly-
| simplistic software, and it feels so rare of a thing to be
| useful anymore. The serious code I now find myself actually
| ever needing to debug, with multiple threads written in
| multiple languages all linked together--code which is often
| performance sensitive and even often involves networked
| services / inter-process communication--just isn't compatible
| with interactive debugging.
|
| So like, sure: if I have some trivial one-off analysis tool I
| am building for which I am running into some issue I could
| figure out how to debug it, but even then I am going to have to
| figure out yet another debugging environment for yet another
| language, and also of course surmount the hassle of a ton of
| ensuring that sufficient debugging information is available and
| I'm running a build that is somehow not optimized enough for
| debugging and yet also not so slow that I'm gouging my eyes
| out, I _could_ use a debugger, but I 'd rather sit and stare at
| the code longer than start arguing with a debugger.
| bluGill wrote:
| Is it really saving time or are you not thinking enough about
| what is wrong until you stumble on an answer? I can't answer
| for you but I find that the forced wait for build also forces
| me to think and so I find the problem faster. It feels slower
| though but the clock is the real measure.
| unclad5968 wrote:
| It's one click to set the breakpoint in the ide or one line
| if you're using gdb from the command line. I'm not sure how
| printf debugging could be quicker even if you didn't have to
| rebuild. Having done both, I'd take the debugger any day.
| ehaliewicz2 wrote:
| I find this line of argument odd. A debugger helps you
| understand what your code is _actually_ doing, while your
| brain is flawed and makes flawed assumptions. Regardless of
| who you are, it 's unlikely you will be manually evaluating
| code in your head as accurately as gdb (or whatever debugger
| you use).
|
| I think a lot of linux/mac folks tend to printf debug, while
| windows folks tend to use a debugger, and I suspect it is a
| culture based choice that is justified post hoc..
|
| However, few things have been better for my code than
| stepping through anything complex at least once before I move
| on (I used to almost exclusively use printf debugging).
| cmontella wrote:
| Trace debugging can be inefficient, but it's also highly
| effective, portable between all languages, and requires no
| additional tooling. Hard to beat that combo.
| tel wrote:
| Just my lack of experience here, but I'm trying to verify I'm
| successfully using sold. The mold linker claims it leaves
| metadata in the .comment section, but on mach-o does that exist?
| Is there a similar evaluation command using objdump as the mold
| readelf command?
| James_K wrote:
| Surely it would be better to use a debugger and avoid recompiling
| your code for the added print statements than to strip out the
| debug information to decrease build times.
| evrimoztamur wrote:
| I build wasm as a target and this is sadly not an option, I
| have to rebuild for each little bit. I will be trying a
| different linker and see how it goes though!
| khuey wrote:
| split-debuginfo = "unpacked" (-gsplit-dwarf for C/C++) is the
| way. Your tools (debuggers, profilers, etc) _probably_ support it
| by now.
| sendomatic wrote:
| There are a lot of different t views on debugging with a debugger
| vs print statements and what works better. This often seems to be
| based on user preference and familiarity. One thing that I
| haven't seen mentioned is for issues with dependencies. Setting
| up a path dep in rust or fetching the code in whatever language
| you're using for your project usually takes more time than simply
| adding some breakpoints in the library code.
| zerd wrote:
| This post is from February, any interesting changes/improvements
| since then? Progress on "wild"?
___________________________________________________________________
(page generated 2024-11-14 23:01 UTC)