{"id":359,"date":"2009-09-13T00:41:10","date_gmt":"2009-09-13T07:41:10","guid":{"rendered":"https:\/\/mathpirate.net\/log\/?p=359"},"modified":"2009-09-13T00:42:17","modified_gmt":"2009-09-13T07:42:17","slug":"being-mean-to-the-average","status":"publish","type":"post","link":"https:\/\/mathpirate.net\/log\/2009\/09\/13\/being-mean-to-the-average\/","title":{"rendered":"Being Mean To The Average"},"content":{"rendered":"<p>I hate the average.<\/p>\n<p>Specifically, I hate the use of the average as the predominant, sometimes only bit of information given when talking about software performance test results.\u00c2\u00a0 I will grant that it&#8217;s easy to understand, it&#8217;s easy to calculate, and I know that it&#8217;s one of the few mathematical concepts that can be passed along to management without much explanation.\u00c2\u00a0 However, it&#8217;s\u00c2\u00a0often misleading, presents an incomplete picture of performance, and is sometimes just plain wrong.\u00c2\u00a0 What&#8217;s worse is that most people don&#8217;t understand just how dangerously inaccurate it can be, and so they happily report the number and don&#8217;t understand when other things go wrong.\u00c2\u00a0<\/p>\n<p>Calculating the average is simple.\u00c2\u00a0 You take the sum of a set of numbers and divide it by the number of numbers in that set.\u00c2\u00a0 But what exactly does that give you?\u00c2\u00a0 Most people will say that you get a number in the middle of the original set or something like that.\u00c2\u00a0\u00c2\u00a0 That&#8217;s where the faith in the number begins and, more importantly, where the mistakes begin.\u00c2\u00a0 The average will not necessarily be a number in the middle of your original set and it won&#8217;t necessarily be anywhere near any of the numbers in your original set.\u00c2\u00a0 In fact, even if the average turns out to be dead-center in the middle of your data, it doesn&#8217;t tell you anything about what that data looks like.<\/p>\n<p>Consider, for a moment, the annual income of someone we&#8217;ll call Mr. Lucky.\u00c2\u00a0 Mr. Lucky&#8217;s salary\u00c2\u00a0starts at $50,000.\u00c2\u00a0 Every year, Mr. Lucky gets a $2500 raise.\u00c2\u00a0 So, for five years, here&#8217;s his income:\u00c2\u00a0 $50000, $52500, $55000, $57500, $60000.\u00c2\u00a0 Over that period, his average annual\u00c2\u00a0income is $55000.\u00c2\u00a0\u00c2\u00a0 Great, smack in the middle.\u00c2\u00a0 Now, in the sixth year, Mr. Lucky wins a $300 million lottery jackpot.\u00c2\u00a0 What&#8217;s his average income over all six years?\u00c2\u00a0 Over $50 million a year.\u00c2\u00a0 However, it&#8217;s clearly wrong to try to claim that Mr. Lucky made $50 million dollars a year over six years, because once you look at the data, it is obvious that the $300 million is skewing the average well away from what he was actually making at the time.<\/p>\n<p>Let&#8217;s take another example, one closer to home.\u00c2\u00a0 Every month, you get an electric bill.\u00c2\u00a0 Since heating and cooling are often the largest chunks of power consumption, the bill will have the average temperature for the month, in order to help you make sense of the fluctuating charges.\u00c2\u00a0\u00c2\u00a0 This year, you get a bill for $200.\u00c2\u00a0 Shocked, you pull out last year&#8217;s bill to compare, and discover that you paid only $50 then.\u00c2\u00a0 Last year, according to the bill, the average temperature was 54.3 degrees, and this year it was 53.8 degrees.\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 The average temperature was roughly the same, so your heating\/cooling shouldn&#8217;t have changed that much.\u00c2\u00a0 You didn&#8217;t buy a new TV or an electric car, you turn off the lights when you&#8217;re not in the room, your shut down the computer at night, you&#8217;ve got CFL bulbs everywhere, and as far as you know, the neighbors aren&#8217;t tapped into your breaker box to power the grow op in their basement.\u00c2\u00a0 So&#8230;\u00c2\u00a0 What happened?\u00c2\u00a0 Let&#8217;s take a closer look at that weather&#8230;<\/p>\n<p><strong>Daily Temperature Last Year:<\/strong><\/p>\n<p><strong><a href=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/ElectricityBill-LastYear.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-medium wp-image-361\" title=\"ElectricityBill-LastYear\" src=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/ElectricityBill-LastYear-300x163.png\" alt=\"ElectricityBill-LastYear\" width=\"300\" height=\"163\" srcset=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/ElectricityBill-LastYear-300x163.png 300w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/ElectricityBill-LastYear-1024x558.png 1024w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/ElectricityBill-LastYear.png 1116w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/strong><\/p>\n<p><strong>Daily Temperature This Year:<\/strong><\/p>\n<p><a href=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/ElectricityBill-ThisYear.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-medium wp-image-362\" title=\"ElectricityBill-ThisYear\" src=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/ElectricityBill-ThisYear-300x163.png\" alt=\"ElectricityBill-ThisYear\" width=\"300\" height=\"163\" srcset=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/ElectricityBill-ThisYear-300x163.png 300w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/ElectricityBill-ThisYear-1024x559.png 1024w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/ElectricityBill-ThisYear.png 1118w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Once you look at the actual daily temperature, it becomes clear what happened to your power bill.\u00c2\u00a0 Last year, the temperature was fairly constant, but this year, there were wild temperature swings.\u00c2\u00a0 You had your AC cranking full blast for the first part of the month, then you kept nudging up the thermostat during the end of the month.\u00c2\u00a0 However, since the temperature extremes offset one another, the average temperature\u00c2\u00a0makes it seem like both months had the same weather.<\/p>\n<p>That&#8217;s the key:\u00c2\u00a0 Once you look at the data, it&#8217;s often clear that the average doesn&#8217;t tell the whole story, or worse, tells the wrong story.\u00c2\u00a0 And the problem is that people typically don&#8217;t look at the data.<\/p>\n<p>Let me pull this back to the world of software performance testing and tell a story about a product I&#8217;ve worked on and how I first came to realize that typical performance testing was dead wrong.\u00c2\u00a0 The product was a keyword processor at the heart of a larger system.\u00c2\u00a0 Our customer had demanded a 1.5 second response time from our overall\u00c2\u00a0system, and that requirement\u00c2\u00a0got chipped down and used up by other components on its way to the keyword processor I was involved with.\u00c2\u00a0 By the time it got to us, we only had a response time cap of 250 ms in which to return our data, otherwise the larger system would give up on us and continue on its way.\u00c2\u00a0 So, great, I thought.\u00c2\u00a0 I&#8217;ll just load up the system with an ever increasing number of concurrent requests and find out how many requests we can process at the same time before our average hits 250 ms.\u00c2\u00a0 I did that and came up with 20 requests at once.<\/p>\n<p>So we set up enough\u00c2\u00a0machines to handle the anticipated load with a maximum of 15 requests per box at one time, so we&#8217;d have some room to grow before we needed to add capacity.\u00c2\u00a0 All was well.<\/p>\n<p>Until, that is, the day we launched and our keyword processor kept getting dumped on the floor by the system above us.<\/p>\n<p>Something was obviously wrong.\u00c2\u00a0 We knew what our performance was.\u00c2\u00a0 At 20 concurrent\u00c2\u00a0requests, we had a 250 ms response time, at 15\u00c2\u00a0requests, we has seen an average 200 ms response time.\u00c2\u00a0 We&#8217;re fast enough, and we&#8217;d proved that we were fast enough.\u00c2\u00a0 Statistics said so!<\/p>\n<p>That right there was the problem.\u00c2\u00a0 We trusted the wrong information.\u00c2\u00a0 Sure, the average response time was 200 ms at the load we were seeing, but that said absolutely nothing about the\u00c2\u00a0something like 30% of the requests that\u00c2\u00a0were hitting the 250 ms timeout.\u00c2\u00a0 We frantically reran the performance tests.\u00c2\u00a0 The results were stunning.\u00c2\u00a0 While the average response time did not hit 250 ms until we reached the 20 concurrent request level, we saw a significant (and SLA violating) number of requests that took more than 250 ms by the time we reached the 10 concurrent request level.<\/p>\n<p>People aren&#8217;t very happy when you tell them that a cluster size has to double&#8230;<\/p>\n<p>At the time, I thought I might have just made a rookie mistake.\u00c2\u00a0 It was the first major system I&#8217;d done the performance testing for, and I&#8217;d had no training or mentoring.\u00c2\u00a0 I did what I thought was right and ended up getting burned.\u00c2\u00a0 Surely, I thought, everyone else knows what they&#8217;re doing.\u00c2\u00a0 Real performance testers using real performance testing tools will get it right.\u00c2\u00a0 Trouble is, I&#8217;ve since discovered that&#8217;s not the case.\u00c2\u00a0 Everyone else makes these mistakes and they don&#8217;t even realize that they&#8217;re making any mistakes.\u00c2\u00a0 And performance testing tools actively encourage testers to make these mistakes by not giving the tester the information that they really need and, in some cases, giving testers information that is just plain invalid. ((I&#8217;ve seen several cases of odd numbers coming out of VS Perf Tests, but the one I&#8217;m specifically thinking of here is the fact that VS will still report an average response time, even when you&#8217;re ramping up the number of users.\u00c2\u00a0 The performance of your system when you have a single user is vastly different than when you have 100 users, so the single &#8220;Average Request Time&#8221; number that it will report is just plain useless.))<\/p>\n<p>So&#8230;\u00c2\u00a0 What do you do about it?\u00c2\u00a0 For starters, don&#8217;t use the average in isolation.\u00c2\u00a0 Pull in some other measurement.\u00c2\u00a0 I like using\u00c2\u00a0the 95th percentile for a second opinion. ((You can get the 95th\u00c2\u00a0percentile in\u00c2\u00a0Visual Studio, if you tweak a\u00c2\u00a0setting.\u00c2\u00a0 Set &#8220;Timing Details Storage&#8221; to &#8220;Statistics Only&#8221; or &#8220;All Individual Details&#8221; and it&#8217;ll start being recorded.))\u00c2\u00a0 The 95th percentile means that 95% of all requests take less than that amount of time.\u00c2\u00a0 That&#8217;s really more what you care about, anyway.\u00c2\u00a0 You&#8217;re probably not really concerned with the 5% that lie beyond that point, since they&#8217;re usually outliers\u00c2\u00a0or abberations in your performance anyway.\u00c2\u00a0 This will get rid of things like Mr. Lucky&#8217;s lottery winnings.\u00c2\u00a0\u00c2\u00a0 Additionally, you&#8217;re\u00c2\u00a0probably not really concerned with where the average response time lies.\u00c2\u00a0 People often use the results of performance testing to feed into capacity planning or SLAs.\u00c2\u00a0 When there are dollars on the line tied to the Five Nines, why do you care about a number that you think of as the middle of the road?\u00c2\u00a0 You care about the worst case, not the average case.\u00c2\u00a0 If we&#8217;d used the 95th or 99th percentile in our inital performance tests of that keyword processor, we would not have had the problem that we did.<\/p>\n<p>But even so, the 95th percentile has its own set of issues and should also not be used in isolation.\u00c2\u00a0 It, too, does not tell you the complete story, and can easily hide important\u00c2\u00a0trends of the data.<\/p>\n<p>There I go again with &#8220;the data&#8221;.\u00c2\u00a0 You have to look at the data. \u00c2\u00a0In order to get the full picture of your system performance, you actually\u00c2\u00a0have to look at the full picture of your system performance.\u00c2\u00a0 You can&#8217;t go to single aggregate\u00c2\u00a0numbers here or there and call it good.<\/p>\n<p>Of course, that leads to the obvious problem.\u00c2\u00a0 When you run a performance test, you&#8217;ll often end up running thousands upon thousands of iterations, collecting thousands upon thousands of data points.\u00c2\u00a0 You cannot\u00c2\u00a0wrap your head around that kind of data in the same way that you can see Mr. Lucky&#8217;s income or the daily chart of the temperature.<\/p>\n<p>Well, not without help&#8230;<\/p>\n<p>\u00c2\u00a0Whenever I do performance testing now, I rely on a tool that I built that will produce several graphs from the results of a performance test run.\u00c2\u00a0 The simplest graph to produce is a histogram of response times.<\/p>\n<p><a href=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/NormalHistogram.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-medium wp-image-366\" title=\"NormalHistogram\" src=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/NormalHistogram-300x167.png\" alt=\"NormalHistogram\" width=\"300\" height=\"167\" srcset=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/NormalHistogram-300x167.png 300w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/NormalHistogram.png 558w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>A histogram will show you the distribution of the response times for the performance test.\u00c2\u00a0 At a glance, you can see the where the fastest and slowest responses lie, and get a sense for how the service behaves.\u00c2\u00a0\u00c2\u00a0Are the response times consistent, with most of them around 150 ms, or are they spread out between 100 and 200 ms?\u00c2\u00a0 A histogram can also show you when things are acting strangely.\u00c2\u00a0 One piece of software I tested had most of the response times centered\u00c2\u00a0below\u00c2\u00a0400\u00c2\u00a0ms, but there was a secondary bump up between 500-900 ms.\u00c2\u00a0 That secondary bump indicated something was strange, perhaps there was a code path that took three times as long to execute that only some inputs would trigger, or there were random slowdowns due to garbage collection or page swapping or network hiccups.<\/p>\n<p><a href=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalHistogram.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-medium wp-image-367\" title=\"AbnormalHistogram\" src=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalHistogram-300x65.png\" alt=\"AbnormalHistogram\" width=\"300\" height=\"65\" srcset=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalHistogram-300x65.png 300w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalHistogram.png 555w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>As you can see, there are a sizeable number of responses in that bump, enough to make you want to investigate the cause.\u00c2\u00a0 This potential problem would have been completely invisible if you were only concerned with the average, and the full extent would not have been known if you&#8217;d been looking at the 95th percentile. ((Likely, the 95th percentile would lie in the middle of the bump, leading you to believe that the system performance is slow overall, not that there&#8217;s an anomaly.))\u00c2\u00a0 However, it&#8217;s plainly visible that something strange is going on when you see the graph like that.<\/p>\n<p>While helpful, simple histograms like this are not enough.\u00c2\u00a0 In particular, they fall down if anything changes during the test run.\u00c2\u00a0 If something like network latency slows down your test for a brief period of time, that will be invisible in this graph.\u00c2\u00a0 If you&#8217;re changing the number of users or the number of concurrent requests, then the times from all of them get squeezed together, rendering the graph invalid.\u00c2\u00a0 What you&#8217;re missing here is the time dimension.<\/p>\n<p>One way to bring in the time dimension is to animate the histogram.\u00c2\u00a0 You produce multiple histograms, each representing a slice of time in your test.\u00c2\u00a0 That way, you can watch the behavior of your service change over the length of the performance test.\u00c2\u00a0 The problem I have with an animated histogram is that you can&#8217;t just glance at the information.\u00c2\u00a0 You have to watch the whole thing, which can be time consuming for a long running performance test.<\/p>\n<p>Instead of animation, I prefer to visualize the time in this way:<\/p>\n<p>\u00c2\u00a0<a href=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/NormalDensityGraph.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-369\" title=\"NormalDensityGraph\" src=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/NormalDensityGraph.png\" alt=\"NormalDensityGraph\" width=\"428\" height=\"429\" srcset=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/NormalDensityGraph.png 428w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/NormalDensityGraph-150x150.png 150w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/NormalDensityGraph-299x300.png 299w\" sizes=\"(max-width: 428px) 100vw, 428px\" \/><\/a><\/p>\n<p>Going up the side, you have divisions for buckets of response times.\u00c2\u00a0 Going across, you have time slices. ((Time isn&#8217;t marked in these examples because the tool I use to generate them\u00c2\u00a0will usually generate other graphs, as well, making it possible to correlate the time on that graph with the\u00c2\u00a0time on this graph.\u00c2\u00a0 For these examples, it&#8217;s not really necessary to know how much time\u00c2\u00a0each column is or how many requests are represented by each block.))\u00c2\u00a0\u00c2\u00a0 Essentially, this is what you&#8217;d see if you stacked a bunch of histograms together side by side, then looked at them from the top.\u00c2\u00a0 It&#8217;s basically like a heat map or a graph of the density of the response times.\u00c2\u00a0 The red zones have the most responses, while the green areas have the least. ((And the white zones are for loading and unloading only.\u00c2\u00a0 There is no parking in the white zones.))\u00c2\u00a0 In the example above, you can see that there are a lot of responses in the 100 and 150 ms buckets and then\u00c2\u00a0it quickly trails off to zero.\u00c2\u00a0 There&#8217;s\u00c2\u00a0a lot of\u00c2\u00a0noise up to about 600 ms, and sporadic outliers above that.\u00c2\u00a0 The performance remains fairly stable throughout the test run.\u00c2\u00a0 All in all, this is a fairly standard graph for a well behaved piece of software. ((For comparison,\u00c2\u00a0this graph\u00c2\u00a0is from the same test run that produced the &#8220;Average Response Time: 149 ms&#8221; histogram that I showed earlier.))<\/p>\n<p>These density graphs aren&#8217;t terribly interesting when things are well behaved, though.\u00c2\u00a0 Here&#8217;s another graph I saw:<\/p>\n<p><a href=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph11.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-371\" title=\"AbnormalDensityGraph1\" src=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph11.png\" alt=\"AbnormalDensityGraph1\" width=\"455\" height=\"454\" srcset=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph11.png 455w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph11-150x150.png 150w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph11-300x299.png 300w\" sizes=\"(max-width: 455px) 100vw, 455px\" \/><\/a><\/p>\n<p>First, there&#8217;s bands of slowness between about 210 and 280 and 380-450.\u00c2\u00a0 These bands would appear in a histogram like the secondary hill shown above.\u00c2\u00a0 But what a histogram isn&#8217;t going to show you is the apparent pattern in the 380-450 band.\u00c2\u00a0 It appears that there&#8217;s groups of slow responses in a slice of time, then none for the next couple of slices, then another group of slow responses, then none, and so on.\u00c2\u00a0 Seeing this kind of behavior can help you find the problem faster.\u00c2\u00a0 In this case, the slow responses may be caused by something else running on the box that&#8217;s scheduled to run at a regular interval, like an anti-virus scanner or a file\u00c2\u00a0indexer, or they can be caused by something like\u00c2\u00a0the garbage collector waking up to do a sweep on a somewhat regular basis.<\/p>\n<p>Another benefit of a density graph is that they&#8217;re still useful, even if you change the parameters of the test during the test run.\u00c2\u00a0 For instance, a common practice in performance testing is to increase the load on a system during the run, in order to see how performance changes.<\/p>\n<p><a href=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph2.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-372\" title=\"AbnormalDensityGraph2\" src=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph2.png\" alt=\"AbnormalDensityGraph2\" width=\"426\" height=\"426\" srcset=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph2.png 426w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph2-150x150.png 150w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph2-300x300.png 300w\" sizes=\"(max-width: 426px) 100vw, 426px\" \/><\/a><\/p>\n<p>In this example, the number of concurrent users was steadily increased over the run of the test.\u00c2\u00a0 In the first part of the test, you can see that increasing the number of users will\u00c2\u00a0directly influence the\u00c2\u00a0response time.\u00c2\u00a0 It also increases the variation of those response times:\u00c2\u00a0 For the first part, all of the responses came in within 100 ms of one another, but pretty quickly, they&#8217;re spread over a 300-400 ms range.\u00c2\u00a0 And then, during the final third of the test, everything went all kerflooey.\u00c2\u00a0 I don&#8217;t know what happened, exactly, but I know that something bad happened there.<\/p>\n<p>I think this graph is one of my favorites:<\/p>\n<p><a href=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph3.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-373\" title=\"AbnormalDensityGraph3\" src=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph3.png\" alt=\"AbnormalDensityGraph3\" width=\"436\" height=\"438\" srcset=\"https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph3.png 436w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph3-150x150.png 150w, https:\/\/mathpirate.net\/log\/wp-content\/uploads\/2009\/09\/AbnormalDensityGraph3-298x300.png 298w\" sizes=\"(max-width: 436px) 100vw, 436px\" \/><\/a><\/p>\n<p>As you can see, this graph is distinctly trimodal.\u00c2\u00a0 There&#8217;s a steep, but well defined band shooting off the top, then a wide and expanding band in the middle, followed by a sharply narrow band with a shallow slope.\u00c2\u00a0 I like this graph because it doesn&#8217;t actually show anything that&#8217;s wrong.\u00c2\u00a0 What it illustrates is the huge impact that your test inputs can have on the results.\u00c2\u00a0 This test was run against a keyword index system.\u00c2\u00a0 The input I used was a bunch of random words or phrases.\u00c2\u00a0 Different words caused the keyword index system to do different things.\u00c2\u00a0 The shallow band at the bottom was created by the keywords for which the index system found no results.\u00c2\u00a0 When it didn&#8217;t find anything, the system simply returned immediately, making it very fast.\u00c2\u00a0 The middle band was filled with keywords that found a single result.\u00c2\u00a0 The top band was the set of keywords that found multiple results, which required extra processing to combine the two results into one before returning.<\/p>\n<p>\u00c2\u00a0<\/p>\n<p>Performance tests are the same as any other test, your goal is to find problems with the software.\u00c2\u00a0 You&#8217;re not going to find them if you&#8217;re only looking at the average.\u00c2\u00a0 So, the next time you&#8217;re involved with a performance test, remember: Look deeper.\u00c2\u00a0 There are more problems to be found under the surface.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I hate the average. Specifically, I hate the use of the average as the predominant, sometimes only bit of information given when talking about software performance test results.\u00c2\u00a0 I will grant that it&#8217;s easy to understand, it&#8217;s easy to calculate, and I know that it&#8217;s one of the few mathematical concepts that can be passed [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[34],"tags":[38,37,36,35],"_links":{"self":[{"href":"https:\/\/mathpirate.net\/log\/wp-json\/wp\/v2\/posts\/359"}],"collection":[{"href":"https:\/\/mathpirate.net\/log\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mathpirate.net\/log\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mathpirate.net\/log\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mathpirate.net\/log\/wp-json\/wp\/v2\/comments?post=359"}],"version-history":[{"count":27,"href":"https:\/\/mathpirate.net\/log\/wp-json\/wp\/v2\/posts\/359\/revisions"}],"predecessor-version":[{"id":395,"href":"https:\/\/mathpirate.net\/log\/wp-json\/wp\/v2\/posts\/359\/revisions\/395"}],"wp:attachment":[{"href":"https:\/\/mathpirate.net\/log\/wp-json\/wp\/v2\/media?parent=359"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mathpirate.net\/log\/wp-json\/wp\/v2\/categories?post=359"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mathpirate.net\/log\/wp-json\/wp\/v2\/tags?post=359"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}