• 'Inclusive' and 'Exclusive'

    While observing people using performance tools, I’ve seen some confusion around the terms ‘exclusive’ and ‘inclusive’ (some tools call them ‘self’ and ‘total’). The distinction between the two is simple, but understanding it is important in order to use your profiling data effectively.

    You’re likely to see these terms in tools like CPU profilers which show you what was on the stack over a period of time. Here’s what the difference is: costs (generally in units of samples for sampling-based tools or units of time for instrumentation-based tools) associated with code anywhere on the stack fall under the ‘inclusive’ category while costs associated with code at the top of the stack go under the ‘inclusive’ category and also the ‘exclusive’ category.

    Consider the following simple call tree from a sampling profiler. Remember, a sampling profiler walks and collects the call stack at some interval during program execution and aggregates information from all the stacks it collects in order to present a statistical approximation of where time was spent during program execution.

    Function       Inc Samples    Exc Samples
    foo()                  100              1
    |__bar()                50             20
       |__baz()             18             18
       |__quux()            12             12
    |__baz()                49             49

    The inclusive count for foo in the tree represents the number of samples spent in foo and its children. In this case, because foo and its children account for the entirety of the tree, we see that there were 100 samples taken in total. Of those, only 1 was in foo itself and the rest of the samples were taken when one of the functions it called (or one of the functions they called) was executing.

    Moving down, we see that bar is the next highest in terms of inclusive samples with 50, of which 20 were exclusive samples while the rest were in its children. We can also see that baz took up 49 of our 100 total samples and since it has no callees, all that time was spent inside baz itself. Thus, while foo has the largest count of inclusive samples, and bar has about the same as baz, making improvements in foo or bar will be of limited use compared to making baz faster. I’m not talking about improving the way other functions are called from foo or bar here, of course; if foo is calling baz in a loop millions of times unnecessarily, then fixing that will also reduce the amount of time spent in baz. As always, it’s important to have a reasonable understanding of the flow of the code you’re profiling in order to solve performance problems using tools.

    While this was a very simple example, hopefully the next time you use a profiler you will have a better understanding of which functions will give you the best “bang for the buck” when optimizing.

  • Release Notes Considered Helpful

    Every day, my phone prompts me to install some updates, and every day I go in to see which apps have updates and what the updates contain. I’m not sure why I bother anymore though; lately most updates come with release notes saying something like “improvements and bug fixes,” and sometimes not even that much.

    The problem isn’t limited to apps, either. I received an over-the-air OS update a while back which told me absolutely nothing about what was in it nor whether I could expect it to fix any bugs I’d been running into. My options were either to install it blindly, or search the web and hope a tech blog or forum user knew what was in this release.

    The release notes section is a place where a developer can tell their users what they’ve been up to, yet most developers seem content to say nothing at all. If what you’ve improved since the previous version was significant enough to merit an update, shouldn’t you be able to write a few bullet points about it? Surely, “refreshed visual design” and “improved startup performance” are much more informative than “improvements” and no harder to write.

    I’ll be the first to acknowledge that for most kinds of software, the majority of users simply don’t care about the changes in an update. They installed your program because it solves some problem for them, and as long as it continues to solve that problem, they don’t care if you reduced your memory footprint or fixed a bug in a feature they’ve never used.

    However, the kind of people who read your release notes are the ones who really care about your product. They are your evangelists, your word-of-mouth marketers, your beta testers.

    As developers, we should consider something broken when our most dedicated and engaged users are forced to turn to tech blogs to find out basic information about what has changed in our product. We have an established communication mechanism for this. Let’s start using it.

  • The Second Hardest Problem

    There’s an old saying that the two hardest problems in computer science are cache invalidation and naming things.

    It’s not just a funny aphorism–years of working on large codebases has taught me that unclear or imprecise naming is a giant red flag, as if your surgeon were to say he needs to move some stringy bits over and pull out the squishy blob. Be worried.

    The most obvious reason to care about naming is that, with very few exceptions, your code has to be maintained. Whoever comes along to fix or modify something (even if it’s just future-you) is going to have a much easier time understanding what’s going on if everything is named sensibly.

    But that’s an investment for the future, right? Nobody argues that poor names are better than precise ones. Good naming is right up there on the clean code checklist with stuff like having unit tests and not copying and pasting code. You have a feature to ship today, though, so you can’t be bothered with future-looking best practices nonsense. Well, the most important reason to care about naming has nothing to do with the future, and it’s why I encourage everyone to make the effort to get it right.

    Naming reflects thinking. If you can’t come up with a descriptive and precise name for a function, chances are that you don’t understand what it does. If you can’t figure out what to call a variable, you’re probably using it wrong too. Few things are worse than reading through an unfamiliar codebase and finding a function which appears, on the surface, to be doing what its name suggests, only to find out on closer inspection that the person writing it misunderstood what it was really doing and the whole system was working purely because of an unrelated coincidence. Raise your hand if you’ve seen that before.

    The other benefits of focusing on naming are endless. Good naming can obviate the need for many types of comments, it can help to quickly identify edge cases and potential logical flaws, and can help people reviewing your code follow along.

    These days I spend time and energy to get naming right, even to the point of discussing challenging naming problems with other people. The conversations may even lead to improvements to design decisions. It’s time well spent.

subscribe via RSS