Archive for the 'Performance' Category

Aug 11 2008

ASP.Net Load Testing and Optimization Toolkit - So you want to be a hero

Published by morgan under .Net, ASP.Net, Optimization, Performance

One of my passions is optimization. There's no code related task I like more than making something run better, faster, snappier - from tweaking UI registry keys to stripping out crap code - I want results.  Usually if something is noticeably slow on the user's end, there's something fundamentally wrong that can be made faster - a lot faster.

Why do I love optimization? It's because it's the opposite of a thankless job. Everyone thanks you. Your sales team thanks you. Project Managers thank you. Executive management drools over your optimization report - they can take it straight to the bank. Product leads take your report and put it into the release notes. Or a press release. You're the hero! And it's downright fun.

Long story short, my team was recently assigned optimization targets for our app for increasing user capacity (+30%) and decreasing startup and postback times (-20%). During the iteration, the rest of the team was sucked away to emergency projects, and I singlehandedly blew so far past the targets I couldn't even see them anymore. Final optimizations included 100% increased concurrent user load and a 97% reduction in postback execution time. Application startup time was decreased by 40%. Total code changes was 40 lines. Call it precision strike coding. Toss in one nicely formatted "before and after" optimization report, and I'd say it's been a pretty good couple of weeks.

But you need to know what you're doing, and where to get started. You can't simply sit down in front of the code and start randomly caching things or turning every '+' operator into a StringBuilder. (Note: that's not a good idea anyway). But if you get familiar with the following tools, you'll already know where to start. So without further ado…

The ASP.Net Optimizer's Toolbox

If you want to optimize, you need to have an arsenal of tools to troubleshoot and profile your app. You should be familiar with as many of these tools as possible.

  1. Code Profiler
  2. Recommended: RedGate Ants (14-day free trial, $295 to purchase)

    Pretty much no exceptions here - you have to have a profiler. It's extremely time consuming and ugly to start adding TimeSpan calculations around every block of code in your app. For the amount of time it would take to track down one slow line of code "manually", you could have run four profiler sessions and have your top ten "target list" ready to go, made yourself a sandwich and played a game of foosball. Not only that, but profilers will identify fast blocks of code that are getting executed ridiculous numbers of times, making them slow overall.

    Since I've used RedGate's Ants Profiler pretty much exclusively, that's all I can recommend here, but others exist. RedGate is great at profiling code, but I find their memory profiling to be pretty lackluster, so if I need to dig into memory I'll generally fire up Windbg (see further down).

  3. Application Stress Tool
  4. Recommended: NeoLoad (10 "virtual user" Free Trial but fairly expensive to purchase)
    Also good: WAST (Free)

    You need to be able to load test your application to see how it performs. When does it crash? How many users does it support? How does your memory, disks, network and processors hold up? Load testing uncovers errors you couldn't even dream of by looking at your code - concurrency issues, how your application performs when resources are unavailable, etc.

    Load testing tools pose a problem however, because there is a huge gap between free tools and proprietary tools. Here's a list of some of the ones I know for Windows/IIS:

    TinyGet (Free) - run some HTTP requests sequentially in a loop.  Part of IIS 6 Resource Toolkit
    WAST (Free)- an oldie but a goodie - record basic web browsing and simulate lots of users
    MS ACT - (Application Center Test) - Next generation from WAST, allows for dynamic variables.  It comes with Enterprise Edition level MSDN subscription.  Thanks to mike for pointing it out.
    NeoLoad - good bang for the buck, all the functionality you'll need for even complex AJAX applications, but not cheap and has a predatory pricing model shared by higher end software
    Visual Studio Team Edition for Testers - you can buy a lot of NeoLoad virtual users for this kind of cash.
    HP LoadRunner - you could probably hire a thousand testers, buy them all computers and have them generate load manually for what you'd pay for this kind of software.

    The problem is that the free stuff (TinyGet, WAST) is next to useless for testing sessions and AJAX apps, they're just not built to handle it. I've recently gotten a lot of experience using Neoload and it's pretty good software with fantastic support behind it - you can record complex user sessions with many dynamic parameters, multiple viewstates and have multiple recorded sessions make up a "population" of users to test your app under a broad range of conditions. It also hooks into the perfmon API to give you flexible reporting and graphs. Unfortunately they charge per "virtual user" you want to have running, and it's not real cheap. Small businesses may find it worthwhile depending on the situation. Freelancers may want to stick with WAST, look at some other options, or roll their own.

    The top range stuff is for medium-very large businesses that can shell out the dough, and I don't have any experience with them. For the money, they'd better be good!

  5. Performance Monitor
  6. Recommended: Performance Monitor (perfmon.exe) (Free)
    Also good: NeoLoad

    At what point does your app spike the CPU? How's that CLR request queue going? What's your heap memory look like? Microsoft's perfmon API is very rich and if you don't have a custom app that hooks into it already, simply type "perfmon.exe" at the command prompt and you have everything you need in Microsoft's simple MMC app. You can monitor as many machines as necessary all in the same window or log. Experiment with recording counter log files and replaying them - this data can be exported and included for that extra-demanding CTO. If you're unfamiliar with perfmon, play around with it - it's not too hard to figure out even though the interface is a bit dated.

  7. HTTP Recorder
  8. Recommended: Fiddler2 (Free)

    Optimizing your AJAX app? Confused about how chatty your application is being? You need to be able to see exactly what's going between client and server - requests, responses, headers, what's compressed and what isn't. Enter Fiddler2 - this little proxy server sits between IE and any web page and records all the traffic, and reports it for you in an easy to see format. Tip: if you're looking at your pages on your local machine, use http://machinename instead of http://localhost, since IE ignores going through a proxy for localhost addresses.

    Fiddler2 is especially useful for ASP.Net apps because it's not always clear exactly what kind of HTML is being generated by webcontrols.

  9. Interface Manipulation
  10. Recommended: Firebug (Free)
    Also good: Developer Toolbar for IE (Free)

    Any web developer by now has heard of the Firebug plug-in for Firefox. It lets you manipulate CSS, HTML and javascript on the fly on any webpage you're viewing, complete with a javascript debugger and DOM explorer. In fact, I don't know what we did without it, back in the good 'ol Web 1.5.6.18 days. If you must develop with IE (*shudder*) you can get the Developer Toolbar for IE, which isn't nearly as good, but does the job in a pinch.

  11. Debugger
  12. Recommended: Windbg (Free)
    Also good: DebugDiag (Free)

    A good debugger/memory dump analyzer is probably the single most powerful tool in your arsenal if you know how to use it. Windbg will let you take a snapshot of your application as it's running or when it crashes, and you can quickly narrow down what's causing crashes, hangs, excessive memory usage, or identify potential optimizations. You can explore the runtime stacks, native and CLR, see what every thread was doing, and see what's in every memory address on your heaps. If you've never used Windbg, there are fantastic lab-style tutorials at Tess' blog at MSDN. These tutorials will also introduce you to perfmon and tinyget.

  13. FXCop (Free)
  14. FXCop can be a useful tool but depending on your environment, it might be more trouble than it's worth. Simply put, it scans your code looking for bad coding practices and comes up with a report about how sloppy you are. Unfortunately, some of the default rules may not apply to your development environment, but with a little effort you can certainly weed out the rules you don't need and make it more useful for your team.

  15. Viewstate Decoder
  16. Recommended: Fritz Onion's Viewstate Decoder (Free)

    At some point most ASP.Net apps undergo a Viewstate optimization. Let's face it, Viewstate can be downright disgusting. If you're jumping into the middle of an application, it's helpful to have some guidance on where the hell it's all coming from. Just copy and paste it into a Viewstate decoder and you might find a ton of clues.

  17. Text editor
  18. Recommended: Ultraedit (45 day free trial, $49.95 to buy)
    Also good: Notepad2 (Free)

    As every experienced coder knows, sometimes, you just don't want to look at something in your IDE. You just want to open a file fast and be done with it. I've used UltraEdit for a long time and it has great features, useful for optimization. For example, you can copy a recorded request from Fiddler, paste it into Ultraedit, and immediately count how many times your ultra-long image pathname occurs, and immediately know how many bytes you can shave out of your file. It has quick and easy syntax highlighting for pretty much any programming language, line numbers, and tracks the file and asks to reload it if it detects changes. It also detects blocks of code or xml for expanding/collapsing, and hundreds of other features.

Although I didn't include Lutz Roeder's Reflector in the list since I don't find that I use it that often when I'm debugging, it's something you should always have for easy reference, especially if you're dealing with unfamiliar assemblies.

Good luck optimizing! Remember to spellcheck your optimization report, and don't forget to put in a one page executive summary of what a hero you are.

12 responses so far

Jun 04 2008

Ten PHP Best Practices Tips that will get you a job

Published by blake under Code, PHP, Performance

The last couple of weeks have been quite the experience for me. I was part of a big layoff at my former company, which was interesting. I've never been in that position before, and it's hard not to take it personally. I started watching the job boards, and a nice-looking full-time PHP position caught my eye, so I sent out a resume and landed an interview. Before the face-to-face portion, I chatted with the owner and head programmer on a conference call, and they ended up sending me a technical assessment quiz. One particular question caught my eye on this quiz… it looked something like this:

Find the errors in the following code:

<?
function baz($y $z) {
	$x = new Array();
	$x[sales]  = 60;
	$x[profit] = 20:

	foreach($x as $key = $value) {
		echo $key+" "+$value+"<BR>";
	}
} 

?>

So, give it a shot. How many can you find?

If you got the missing comma in the parameter list, the "new Array()" error, the colon instead of a semi-colon, the '=' instead of '=>' in the foreach statement, and the erroneous use of '+' on the echo line, then congratulations, you found all the errors! You have the basic PHP technical skills to pay the bills.

That's not how I answered the question though. I noted the errors, obviously, but I went further than that. For instance, did you notice that there were no single quotes around the array indexes ($x[sales] and $x[profit])? That won't cause a fatal PHP error, but it is a coding error! Did you also notice the use of double-quoted strings instead of single-quoted strings on the echo line? Or the usage of the opening PHP short tag? Or the usage of "<BR>" instead of "<br/>"?

After pointing out the actual errors, I made a point of adding comments about those things I just mentioned. It was enough to push the answer from "correct" to "impressive", and it scored me a lot of points with the programmers who were reviewing my application. Enough so that they offered me the job! (I eventually turned it down, as I have been seduced by the siren call of the contracting life, and I intend to flex my PHP skills to the benefit of my clients, and not a faceless corporate overlord who dabbles in telemarketing. I need a shower).

So, read on for my Ten PHP Best Practices Tips that will get you a job:

1. Single-quoted strings are your friend. When you surround a PHP string in double quotes, it is subsequently parsed by the PHP interpreter for variables and special characters, such as "\n". If you just want to output a basic string, use single quotes! There is a marginal performance benefit, since the string does not get parsed. If you have variables or special characters, then by all means use double-quotes, but pick single quotes when possible.

2. String output. Which line of code do you think runs faster?

print "Hi my name is $a. I am $b";
echo "Hi my name is $a. I am $b";
echo "Hi my name is ".$a.". I am ".$b;
echo "Hi my name is ",$a,". I am ",$b;

This might seem weird to you, but the last one is actually the fastest operation. print is slower than echo, putting variables inline in a string is slower than concatenating them, and concatenating strings is slower than using comma-separated echo values! Not only does not-inlining your variables give you a performance boost, but it also makes your code easier to read in any editor that has syntax highlighting (your variables will show up in nice colors). The little-known use of echo as a function that takes a comma-separated list of values is the fastest of them all, since no string operations are performed, it just outputs each parameter. If you combine all this with Tip #1 and use single quotes, you're on your way to some finely-tuned strings.

3. Use single-quotes around array indexes. As you saw in the quiz question above, I pointed out that $x[sales] is technically incorrect! You should quote associative array indexes, like so: $x['sales']. This is because PHP considers the unquoted index as a "bare" string, and considers it a defined constant. When it can't find a matching symbol for this constant in the symbol table however, it converts it to a real string, which is why your code will work. Quoting the index prevents this constant-checking stuff, and makes it safer in case someone defines a future constant with the same name. I've also heard that it is up to seven times faster than referencing an unquoted index, although I haven't tested this. For more on this, see the section called "Array do's and don'ts" in the Array section of the PHP manual.

4. Don't use short open tags. Eww… are you really using these? <? is just bad form. It can cause conflicts with XML parsers, and if you ever distribute code, it's going to annoy the heck out of people who have to start modifying their PHP ini directives to get it to work. There's just no good reasons to use short open tags. Use the full <?php.

5. Don't use regular expressions if you don't need to. If you're doing basic string operations, stay away from the preg and ereg function groups whenever possible. str_replace is much faster than preg_replace, and strtr is even faster than str_replace! Save those crunch cycles… your enterprise applications will thank you.

6. Don't use functions inside a loop declaration. This isn't a PHP-specific tip, but you'll see it in a lot of code.

Bad:

for ($i = 0; $i < count($array); $i++) {
//stuff
}

Good:

$count = count($array);
for($i = 0; $i < $count; $i++) {
//stuff
}

That should be pretty self-explanatory, but it's amazing how many people would rather save a line of code at the expense of performance. If you use a function like count() inside a loop declaration, it's going to get executed at every iteration! If your loop is large, you're using a lot of extra execution time.

7. Never rely on register_globals or magic quotes. register_globals and magic quotes are both old features of PHP that seemed like a good idea at the time (ten years ago), but in reality turned out to be not that great. Older installations of PHP would have these features on by default, and they cause security holes, programming errors, and all sorts of bad practices, such as relying on user input to create variables. Both these features are now deprecated, and everyone needs to stop using them. If you are ever working on code that relies on these features, get it out of there as soon as you can!

8. Always initialize your variables. PHP will automatically create a variable if it hasn't been initialized, but it's not good practice to rely on this feature. It makes for sloppy code, and in large functions or projects can become quite confusing if you have to track down where it's being created. In addition, incrementing an uninitialized variable is much slower than if it was initialized. It's just a good idea.

9. Document your code. You've heard it many times, but this can't be said enough. I know places that won't hire people who don't document code. I even got my previous job after an interview where the VP sat-in with the interviewer and I, where I had brought my laptop in and I was just scrolling through some code I had written for one of my sites. He saw my documented functions and was impressed enough to ask me about my documenting habits. A day later I had the job.

I know a lot of self-declared PHP gurus out there like to pretend that their code is so good that they don't have to spend time documenting it, and these people are full of $largeAnimal poop. Learn docblock syntax, familiarize yourself with some PHP Documentation packages like phpDocumentor or Doxygen, and take the extra time to do it. It's worth it.

10. Code to a standard. This is something that you should ask potential employers about during interviews. Ask them what kind of coding standards they use… PEAR? Zend? In-house? Mention that you code to a specific standard, whether it be your own, or one of the more prevalent ones out there. The problem with loosely-typed languages like PHP is that without a proper coding standard, code tends to start looking like huge piles of garbage. Stinky, disgusting garbage. A basic set of rules that includes whitespace standards, brace matching, naming conventions, etc. is a must-have, must-follow for anyone who prides themselves on their code quality.

That being said, I hate all you space-indenters. I mean, what the hell? 4 space characters as an indent? That's exactly four times as much whitespace to parse as a tab. More importantly, you can set your tab-stops to any value you want if you're using any text-editor more advanced than Notepad, so every developer can having something that they like the looks of. Set it to 4 if you want, or 0 if you're a masochist. I don't care, but you can't do that with spaces! You're stuck with exactly the amount that Mr. Monkey Pants in cubicle 17 decided to put in. So why are spaces so popular? This "4-space indent" standard everyone uses is stupid! Stop it! Stop doing it!

… sorry, pet peeve.

Anyway, I hope these tips are helpful. If you want to impress at a job interview, it's the little details that will get you noticed! Maybe don't rant about your coding standards though.

72 responses so far

Mar 09 2008

Build a CentOS LAMP server

Published by blake under LAMP, Linux, MySQL, Optimization, PHP, Performance

I finally finished re-building a development CentOS LAMP server. More importantly, and the primary purpose of the whole exercise, is that I finished my guide to building a CentOS LAMP server. I am happy to now post said guide on this blog (under Articles), for everyone to read and abuse as they please!

So here you go… may I present Blake's CentOS LAMP Server Guide, single-page edition, and the perhaps friendlier multi-page edition.

The guide covers the basics of building up a CentOS box to use as a remotely-administered LAMP server, including installation and configuration of PHP, Apache and MySQL. Other goodies are in there too, like mail server setup with Postfix/Postgrey/Dovecot. Keep in mind this guide was written from my point of view, and contains the ways that I like to do things. I keep my basic LAMP stuff pretty slim for maximum performance, so you'll see some installations from source in there to help keep things tight.

Let me know if the guide is useful! I'm hoping to get Google to pick it up and get some comments going on the various ways people set up their own LAMP boxes.

4 responses so far

Feb 08 2008

Benchmarking Mono ASP.Net vs. PHP - a slight problem

Published by blake under ASP.Net, Linux, Mono, PHP, Performance

We promised some numbers, but I've run into a snag that's slowed down my testing. Originally when we first started toying with the idea of pitting Mono + ASP.Net against PHP, I wrote a quick PHP script that would just make a cheap fopen call to whatever URL you wanted to test, however many times you wanted to hit it. This isn't really load-testing, it's more like a basic timer, and not a very accurate one at that. However, it gave me some quick raw numbers to work with.

Now, the cleverer ones amongst you will know that Apache Benchmark, or ab, will do pretty much the exact same thing, plus much more. This is where I was planning to get my first batch of results from. But something has happened that is leaving me puzzled as to how I'm going to make these tests fair.

I ran a few benchmarks against a basic PHP page, and it was pretty consistent, within the realms of what you'd expect for a page just coughing up the same content over and over. When I ran the same benchmark against a similar .aspx page however, things were not consistent!

Mono benchmarks - an anomaly

Without going into a long post about what all results were, here's a brief summary. I originally noticed the problem when I ran ab -n 1000 -c 10 [url] from a remote machine that is on the other side of the country. ab was given a PHP URL and an ASP.Net URL for the test server here on my home network, and dutifully returned results for each. The PHP page was giving me results similar to the following (results in seconds for total test time, rounded for brevity):

75, 75, 74

Looks good. Kind of what you want to see in a benchmark. Predictable load times under a given circumstance means your application code is working predictably as well. I ran three tests and averaged the results. So what did I get from Mono? I restarted apache, hit a page to get rid of the initial .Net load time, then ran three tests. Check this out:

77, 77, 100

I thought that was kind of weird. Maybe the server was under some sort of load I didn't know about, so I thought I'd chuck the third benchmark as anomalous and run some more:

95, 107, 92, 106

Now I had a case of the WTFs. Thinking something was wrong, I rebooted apache (and hit a single .aspx page for the initial .Net load). Then I ran some more tests:

restart, 78, 79, 92

There it goes again! I switched to testing on the server machine itself under my desk to get rid of any network latency that might be occurring cross-continent. I ran some PHP benchmarks to see what I would get.

51, 51, 66, 52, 51, 51, 51

Looks good, save the spike in the middle. Back to Mono:

restart 56, 58, 61, 62, 68, 62, 63, restart, 57, 61, 61, 63, 67

WTF

It quickly became evident that the Mono environment is accruing some sort of overhead the more I pound on it. And it's not getting away from this overhead either. I left it alone for awhile to gather its thoughts (and maybe its garbage) while I took a break, but when I tried again it still showed much higher benchmark times than it would right after a server restart. The conclusion I came to over another hour of testing is that Mono would never serve pages as fast as the first benchmark on subsequent benchmarks.

This has delayed my actual collection of benchmark data between PHP and Mono ASP.Net, as I don't feel that it's a fair comparison between the two if Mono is accruing performance penalties the more I use it.

I'm going to have to research this a bit more. Maybe it's my configuration, maybe it's Apache, maybe it's mod_mono, maybe it's something wrong with the .aspx test page, maybe it's a spooky goblin. Maybe it's Mono itself. I don't have enough information at this point to be sure. I'll have to try to narrow this down, or continue testing knowing this limitation.

2 responses so far