Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Detecting Performance Bottlenecks

DZone's Guide to

Detecting Performance Bottlenecks

Performance is more important than ever. You can use NDepend to inform reasoning about your code’s performance, but you should keep an eye out for probabilities.

· Performance Zone
Free Resource

Discover 50 of the latest mobile performance statistics with the Ultimate Guide to Digital Experience Monitoring, brought to you in partnership with Catchpoint.

In the past, I’ve talked about the nature of static code analysis. Specifically, static analysis involves analyzing a program's source code without actually executing it. Contrast this with runtime analysis, which offers observations of runtime behavior via introspection or other means. This creates an interesting dynamic regarding the idea of detecting performance bottlenecks with static analysis. This is because performance is inherently a runtime concern. Static analysis tends to do its best, most direct work with source code considerations. It requires a more indirect route to predict runtime issues.

For example, consider something simple.

public void DoSomething(SomeService theService)
{
    theService.DoYourThing();
}

With a static analyzer, we can easily look at this method and say, “You’re dereferencing ‘theService’ without a null check.” However, it gets a lot harder to talk definitively about runtime behavior. Will this method ever generate an exception? We can’t know that with only the information present. Maybe the only call to this in the entire codebase happens right after instantiating a service. Maybe no one ever calls it.

Today, I’d like to talk about using NDepend to sniff out possible performance issues. My use of the word "possible" carries significant weight because definitive gets difficult. You can use NDepend to inform reasoning about your code’s performance, but you should keep an eye out for probabilities.

That said, how can you use NDepend to identify possible performance woes in your code? Let’s take a look at some ideas.

Leveraging Out-of-the-Box Warnings

First of all, understand that NDepend does speak to this out of the box. As you explore the queries and rules, keep an eye out for the following:

  • Instance sizes too big. If you deal in big, unwieldy instances, they might hinder runtime performance.
  • Methods too long, complex, or with too many parameters. Similarly, if you have unwieldy methods you may experience problems.
  • Make methods static, if possible. As a micro-optimization, this saves passing around of a “this” parameter for the instance.
  • Avoid boxing and unboxing. Boxing and unboxing cause you a performance hit, so keep an eye out for methods that use them needlessly.
  • Remove calls to GC.Collect. If you’re messing with the garbage collector, chances are you have an opportunity to fix some performance issues around that code.

I do not intend this as an exhaustive list, per se. I’m only attempting to highlight that NDepend speaks some to performance right out of the box. You should take the first step of making use of that fact.

Detecting Lots of Throwing

Now, I’d like to get into some custom setups that you could create for yourself. Keep in mind that you’ll have to create your own implementations of these things to leverage them in your own codebase. Doing so won’t prove hard, and you can implement and then tweak to your specific situation.

With NDepend and CQLinq, you can detect the instantiation of exception types in methods or types. For an example of this, check out the out of the box rule, “do not raise reserved exception types.” This gives you an advantage.

I commonly see a mistake wherein developers drift toward using exceptions for control flow. For instance, they might have a method that returns an integer, but in some specific case, they want a string. Rather than rethinking the method’s responsibilities, they throw an exception for the string case and use the exception’s message as the “returned” string.

This doesn’t just violate the principle of least astonishment. It also creates real performance problems, because exception handling is expensive. You can use NDepend to keep an eye on types or namespaces that seem to generate a lot of exceptions. When you notice such a thing, go in manually to make sure people aren’t using them for control flow.

High Complexity, Doing Expensive Things

In keeping with the same theme of indirect warning, let’s reason about how performance problems tend to occur. How often do you find yourself chasing some performance problem only to realize you’re doing something inadvisable inside of a tight loop? I bet you’d answer, “usually.”

This situation proves somewhat hard to detect directly with static analysis, but you can go after it indirectly with NDepend. Consider that you have two essential ingredients to this situation: looping and expensiveness. You’ll need to nibble at both.

In NDepend, we have decent proxies for tight looping: cyclomatic complexity and nesting depth. Cyclomatic complexity tells us how many paths exist through the code, and nesting depth tells us about control flow statements within control flow statements.

So, let’s start with that. We can detect methods likely to have “tight loops” by looking for high cyclomatic complexity and/or deep nesting. From there, we can cross-reference that set of methods with references to the creation and/or use of known expensive operations. Does the method use the filesystem? A database? A network operation or web service? You can see what I’m driving at.

You can effectively create a list of candidates for “expensive things in tight loops.” Once you have this list, you can go through and investigate for actual performance problems.

Build a Blacklist

Finally, I’ll talk about something we built to in the last section. You can create a general “blacklist.”

That term may be a bit loaded, though, because I don’t actually advise you completely eschew expensive types. Indeed, you’d have a hard time doing much without databases, files, and web services. So, I’m not advising that you avoid these things, but rather that you track them.

Audit your application and find all of the expensive things you use. This will include the aforementioned set of external concerns, but it might also include random, poorly performing third party libraries or bits of untouchable legacy code. Add anything troublesome to the list.

From there, you just need to build a custom NDepend query to list any and all types using these things. This way, you establish a baseline and can see if usage increases. To make it a bit more concrete, consider that, while you may need to access a filesystem at times, you don’t want that happening willy-nilly all over the codebase.

This blacklist approach lets you keep a pretty tight eye on likely sources of performance woe.

Always Measure

In this post, I’ve offered some ideas for how you can use NDepend to flag potential performance bottlenecks and issues. These will all prove useful to you, but it bears repeating that you need to remember the word “potential.” It’s all about probabilities.

Once you’ve used NDepend to identify likely culprits, you should absolutely verify. To verify, you’ll find nothing more useful than a good performance profiling tool. All of the prediction in the world won’t show you as much as actual measurements at runtime. The fact that the runtime tool provides the ultimate source of truth does not mean it should be the only tool in your toolbox.

Is your APM strategy broken? This ebook explores the latest in Gartner research to help you learn how to close the end-user experience gap in APM, brought to you in partnership with Catchpoint.

Topics:
performance ,bottlenecks ,static analysis

Published at DZone with permission of Erik Dietrich, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}