1. 20
  1.  

  2. 7

    Usually calling println! inside a hot loop is a pretty common performance footgun. Switching out to ,write!(.., "{}\n", ...); on a std::io::Stdout removes the penalty almost entirely. This is because println! performs a syscall and locks and flushes stdout each time. Whereas other methods allow you to buffer your writes and perform the flushes in batches. Using writeln! can avoid some of the syscalls and doesn’t require locking stdout each time, but it still flushes the buffer on each call. Using write! does not auto flush on each call and gives full control over locking and flushing.

    I haven’t tested on this code but I wouldn’t be surprised if it had some impact even though I’m fairly sure the performance is largely bound by other items.

    1. 5

      I sat down and made those changes (with some other minor ones as well) to see if there was much of an impact, the end result was on my machine runtime was reduced from 35:28 to 22:58. Here’s the details…

      The primary changes I made were:

      • Using write! on a std::io::BufWriter wrapping std::io::Stdout
      • Ipv4Addr can natively be converted to a u32, so there isn’t a need to do all the multiplication by octets. Just change .octects() to into() and the variable binding to let ipv4: u32 = .... This also reduces the bounds checking performance hit, so it’s a win win. (A fun tidbit if you did need to do the multiplication its usually faster to bitshift, so that code would have become (ipv4[0] << 24) + (ipv4[1] << 16) + (ipv4[2] << 8) + ipv4[3]…is it worth the readability hit? That’s subjective).
      • Amortizing line allocations. BufReader::lines allocates a new String for each line. We can reduce that by using a String allocation and passing that as a buffer to BufReader::read_line. This means many lines won’t need to allocate at all. The downside is you have to remember to clear the line buffer before calling read_line() again.
      • Finally, if you know the machine that you’ll be running the code on supports AVX or AVX2, you can tell Rust to use those instructions via RUSTFLAGS='-Ctarget-feature=+av2,+avx' cargo build --release. Alternatively, if you’ll be running the code on the same machine you compile on you can just use RUSTFLAGS='-Ctarget-cpu=native' cargo build --release.

      There’s some good discussion on if Stdout should use block buffering by default which mentions the println! footgun in the Rust CLI book as well as a Reddit post asking about parsing a multi-gb file

      There is probably still things that could be done, but for a few line change that’s a decent speedup.

      1. 3

        For writing, you can also slightly reduce the overhead of each write by locking it ahead of time, though I doubt it matters much with a BufWriter.

        For reading, you might consider bstr’s for_byte_line or ripline, which in addition to avoiding unnecessary allocations, also avoids unnecessary copying.

        1. 1

          Absolutely, and the links have some good discussion (as well as they themselves linking to other good resources) on faster solutions or ways to reduce copies even more, but in this case I wanted to keep it as close(ish) to the original as possible since one of the authors notes was how readable/understandable the Rust code was coming from Python.

        2. 3

          Really insightful. Thanks for sharing these improvements. I rolled a few of them into the post and left a credit.

      2. 7

        For fun, I re-wrote the program. The original program took 30 minutes on my machine, my modified version took 2 minutes and 30 seconds. Most of the time is spent (wasted) in the tld extraction library, but since the input data is a set of hostnames and not URLs, it’s easier and faster to find the longest tld suffix and then return the domain.

        1. 1

          Did you publish your version anywhere?

          1. 1

            I just finished writing a blog post about it at http://vfoley.xyz/reasonable-use-2/. The code is on GitHub: https://github.com/gnuvince/vfb-tldextract

            1. 2

              Excellent, thank you. I also had the same thought when reading the post and discovered that the vast amount of time was spent parsing URLs. I was thinking of doing a write up too, but you did it for me :-)

        2. 3

          I think it’s good that people are liking these posts, but it’s also a little uncomfortable that you’ve authored four stories in the past 10 days without any other community engagement. Have you considered commenting on other people’s posts or submitting interesting things you find that you didn’t author?

          1. 13

            I did do some commenting a while back when there was a post on SQLite inserts. I read this site pretty much every day so if there is something to comment on, I won’t hesitate.

            As for the posts this month, this is the first time in a long time that I’ve had any free time to do research and writing. It’s very rare that I can take time out for this and I suspect I won’t be keeping it up once I find my next gig.

            1. 3

              The content itself is pretty interesting imo, I hadn’t seen the Rapid7 dataset before and seeing both that and some interesting tricks for processing it efficiently is pretty cool. It would be interesting to hear about why this Rust library ended up being significantly faster, but crazy deep dives into upstream libraries aren’t everyone’s cup of tea :P

              To somewhat echo another commenter though, it might be beneficial to think of changing the layout a bit on mobile. On PC it’s entirely fine, imo; the “About” sidebar doesn’t get in the way and seems reasonable enough. but on mobile it ends up being 50% the “about me” blurb, 40% article title and metadata, then we finally get the first sentence by the time we hit the bottom of the screen – I’d think maybe moving the “about” bits to be behind a menu or somewhere else on the page may be a big help to making the site feel less “promotional” on mobile.

              1. 2

                Yeah but it reeks like self-promotion when the first thing I get upon clicking on this link is a screen full of your Name,Photo and CV. Instead of the actual content I came for.

              2. 2

                Unrelated to this post, but related to your comment: I have some blog post ideas in the pipeline that I’ve been considering posting to lobsters. I comment quite frequently, but I don’t really think I’ll post much other than my own stuff since generally anything interesting I find that’s relevant is already here. Is that okay by community standards?

                1. 2

                  IMO that’s totally fine. We’ve had issues of people using Lobsters as an advertising dumping grounds, which is why a few of us try to remind people to engage more with the community. If you’re already commenting on other people’s stuff, then you’re already part of the community 🙂

                  1. 1

                    spread it over some time, don’t post it all at once and keep it in scope for lobster.rs, then you’re ok and after the first posts someone else might also post them for you

                    1. 1

                      ACK. that’s what I figured, just wanted to make sure.

                      (I actually registered because someone posted one of my posts here, I wanted to answer some questions, and I knew a member.)

                      1. 1

                        Even if you submit a lot fo your own posts, engaging with the community in other ways counts (i.e. commenting on not your own articles, posting on not your own articles, voting on not your own articles, etc.). Ratio is cited as a guideline, but if you’re someone like me, ratio starts to matter a lot less 😬