George Barnett

Performance testing with JMeter

George Barnett talks about programming tools October 28, 2008 10:52 PM

This is the first in a series of blog posts aimed at documenting whats involved in setting up a performance test harness from scratch. In my next post, I will show how to deploy these performance tests using Maven 2 and how to automate the process using Bamboo. This post assumes you have already set up your application for initial testing, this should include a sample dataset. In this blog, I'm using a current version of Fisheye. I've set the application up, given it a license key and added a sample CVS repository.

Setup Tests

To start with, we'll use a basic directory structure. Later, I'll show you how to easily separate the data and tests, but for now I'll assume you are working on a local copy. We'll start to fill these with files as we go.

PerfTest/
PerfTest/resources
PerfTest/resources/repository
PerfTest/results

The first thing to do before jumping in to write the tests is to define what actions you want your test to perform.

JMeter uses the concept of a "Thread Group" to represent a set of users performing a set of actions. For example, this could be users logging in and then browsing the dashboard. At a minimum, you need to document thread groups (groups of simulated users), URLs you plan to sample in each Thread Group, what order they (the URLs) should be sampled in and what response assertions are needed to determine if an action was successful or not.

Skeleton JMeter test

JMeter works by running the actions which are placed on the test plan in the order that they are on the plan. To add an action, right click on the left menu where you want the action and then choose from the add menu. I start with the following skeleton. There are a few basics in place:

  • Startup variables on the first screen. Items such as startup dirs.
  • External resouces holds the locations of external data files like CSV's.
  • Thread details - the number of user threads and request delays.
  • Server details - defaults setting where the server resides, which port and protocol.
  • HTTP Cookie manager - keeps track of cookies for authenticated sessions.

1. Fisheye Skeleton - Test Plan.jpg1. Fisheye Skeleton - External Resources.jpg1. Fisheye Skeleton - Server.jpg1. Fisheye Skeleton - UDF.jpg

I have also created 3 Thread Groups, one of which is disabled as it's a storage for common functions.

After creating this skeleton, save it to here:

PerfTest/jmeter-test-fixedload.jmx

Filling in the details

With this skeleton, it's a matter of putting planned actions into JMeter as defined in your documentation. Have a look at the screen shots for the run order, but each thread group has at least:

  • CSV Dataset
  • a Pause
  • Several Samples in order

Note: Pauses are applied between requests to even out the request stream. Users will wait between clicking links in your application and so should your tests.
Tip: To get started, take a look at the FishEye tests which I've been working on.

Below I've listed some of the common items I use in a test. I've highlighted the names where possible so you know what you're looking for in the JMeter graphical interface.

HTTP Sampler

JMeter works with a number of different protocols. Atlassian software mostly talks HTTP, but JMeter also supports JUnit, FTP, AJP, Soap, JDBC, JMS, Ldap and more.

Using a Sampler for the correct protocol allows actions to be performed. In the case of the HTTP Sampler, this means making a HTTP Request to a web server.

2. Fisheye Test - HTTP Sampler.jpg

Response Assertion

As with any test it's important to make sure you get back the correct data. This is very important to ensure correct operation of the application under high load. By attaching a Response Assertion to a HTTP Sampler its easy to check the output matches some preset conditions. You can add two Response Assertions - one for testing the HTTP Response Code (200) and another assertion to check the Response Data for a text string.

2. Fisheye Test - Response Assertion.jpg

CSV Dataset

The CSV Dataset module allows data to be stored in a CSV file on disk. This is read in at runtime and the data is available in variables in the test plan. This makes it easy to change the data "behind" the test application. By keeping the tests generic to the software and the actual info about the data being tested in CSV files, these CSV files can be easily replaced to use a another application dataset. Using sets of CSV files, you can then have test for variations of data, such as production, test or development.

2. Fisheye Test - CSV Dataset.jpg

Module Controller

The Module Controller allows modules in other thread groups to be called. In the test plan I've created there is a Thread Group which is disabled so it does not run. To disable an element, right click on the elemnt you wish to disable and choose disabled. Common actions are then placed in this Thread Group to create a "function storage" area. Store the actions you want in a Simple Controller in the disabled Thread Group. Next, add a Module Controller in the Thread Group you want the action to be performed in and include the "function" from the disabled Thread Group - this allows for easy reuse of common actions (eg. Login).

2. Fisheye Test - Module Controller.jpg

Throughput Controller

Another useful controller is the Throughput Controller. It allows control of either number of executions or percentage executions. The percentage execution is useful since you can set different weights on actions to control the traffic load. Using this controller, you can choose between actions, for example, browse the first of two links 10% of the time and the second link 90% of the time.

JMeter has the __P function which allows variables to be controlled from the command link. This allows variations on traffic patterns to be scripted without needing to change the test plan.

2. Fisheye Test - Throughput Controller.jpg

Results

JMeter is a bit light on user feedback from actions performed in the graphical interface. When starting a test, the only feedback that there's something happening is the thread count which is displayed in the top right hand corner (and maybe the sound of a creaking application somewhere).

I find the following modules give enough debugging and feedback to be useful without overbearing.

Generate Summary Results

This Post Processor prints some summary results to the command line once every few minutes. Later, I'm going to show you how to put this test into an automated build. This feedback on the command line is very useful to see how your build is going by watching the output logs produced by the build.

3. Fisheye Results - Display Summary.jpg

Results Tree

This Listener shows the samples as they are happening. The downside of this is that it is expensive cpu wise when the graphical interface is running. However, it really helps for debuging since it generates a log. You will use the output of this log to generate your graphs using a perl script supplied below. Note, dont save the response data unless you really need to (see the image).

3. Fisheye Results - View Results Tree.jpg

Response Assertions

For each sampler you have, there should be a Response Assertion checking correctness as above. I like to check for both a sucessful response code and some text on the page. With this Listener you can catch any assertion failures and print them. More usefully, you can save them to a file for later by specifying a filename in the available text field.

When configuring this module, make sure you select the checkbox to save the response data. Since this module is only configured to catch errors, the amount of data should be small unless something goes wrong. Later, if you have errors in your test, you can use this logfile which can be loaded into the textfield and the output will from the test run will be displayed, showing which assertions failed.

3. Fisheye Results - Assertions.jpg

Summary Report

This Listener is another good way of getting feedback. It provides a table of results including response time, throughput and sample counts. The data in these cells can be copied to a spreadsheet.

If you'd like metrics with 90th percentile, you might prefer the Aggregate Report Listener instead which provides a similar functionality but with different metrics.

Creating Graphs

Now that you have a working test, its time to run it and get some graphs.

Be sure to remove any stale logs from the results directory before running the test as JMeter will append to any existing results file which would result in two test runs in one file.

To preserve system resources during tests, I run JMeter on the command line. This avoids the resource cost of displaying and updating a graphical interface.

If you have any variables you want to override (See the __P function in the JMeter docs), you can specify these on the command line using the -J switch. They can also be set in the user.properties file which is in the JMeter bin directory.

Here's an example of a test running on the command line:

~/PerfTest gbarnett$ jmeter -n -t jmeter-test-fixedload.jmx -Jfisheye.host=cheech -Jscript.runtime=600
Created the tree successfully using jmeter-test-fixedload.jmx
Starting the test @ Tue Sep 23 12:25:14 EST 2008 (1222136714842)
Display Summary Results During Run +   179 in 102.4s =    1.7/s Avg:    26 Min:     2 Max:   126 Err:     0 (0.00%)
Display Summary Results During Run +  1759 in 179.9s =    9.8/s Avg:    36 Min:     1 Max:   425 Err:     0 (0.00%)
Display Summary Results During Run =  1938 in 282.5s =    6.9/s Avg:    35 Min:     1 Max:   425 Err:     0 (0.00%)
Display Summary Results During Run +  3090 in 180.0s =   17.2/s Avg:    43 Min:     1 Max:   602 Err:     0 (0.00%)
Display Summary Results During Run =  5028 in 462.5s =   10.9/s Avg:    40 Min:     1 Max:   602 Err:     0 (0.00%)
Display Summary Results During Run +  2915 in 167.3s =   17.4/s Avg:    46 Min:     1 Max:   972 Err:     0 (0.00%)
Display Summary Results During Run =  7943 in 629.8s =   12.6/s Avg:    42 Min:     1 Max:   972 Err:     0 (0.00%)
Tidying up ...    @ Tue Sep 23 12:35:47 EST 2008 (1222137347433)
... end of run

Results will be saved in .jtl output files in locations specified in the test on the output Listeners. I used the results directory:

~/PerfTest/results/gbarnett$ ls -al
drwxr-xr-x  2 gbarnett  staff      170 23 Sep 12:38 .
drwxr-xr-x  4 gbarnett  staff      204 23 Sep 12:25 ..
-rw-r--r--  1 gbarnett  staff       83 23 Sep 12:48 jmeter-assertion-fixedload.jtl
-rw-r--r--  1 gbarnett  staff  6078035 23 Sep 12:48 jmeter-result-fixedload.jtl
-rw-r--r--  1 gbarnett  staff   636070 23 Sep 12:48 jmeter-summary-fixedload.jtl

Using the jmetergraph.pl script, graphs can be generated from these .jtl files.

The script requires the perl 'GD' and 'Chart' packages. Once those are installed, running it is easy:

$ jmetergraph.pl jmeter-result-fixedload.jtl

This script will scan the .jtl output files specified and create a set of graphs in the PNG file format in the currect directory.

Here's an example image. This shows the response times of various request laid out as percentages.

ChartStackedPct.png

In the next blog, I'm going to go over how to move these tests into a Maven 2 project. We'll start with splitting up the data and tests and move onto running the test with the Chronos maven plugin.

Update: The second part of this blog is available - Automated performance testing using JMeter and Maven

26 Comment(s)

Hi George,

this is a really nice article. I allowed myself to add it to my new blog category called "Recommended Readings". :-)

Cheers,
Robert

By Robert Spielmann at October 28, 2008 2:57 AM

Hi George,

Thank you for this interesting article.

Question : do you have any feedbacks on using JMeter to create new testing bugs/issues into JIRA ? I had some problems to realize it.

Cheers,
Thomas.

By Thomas Chemineau at October 29, 2008 8:11 AM

Hi Thomas,

Here's a link to the maven artifacts for our Jira performance tests:

https://maven.atlassian.com/public-snapshot/com/atlassian/performance/jira/performance-test/3.13-SNAPSHOT/

They're undocumented at the moment as that's still on my task list but hopefully you will find them useful in the interim.

Regards,

George

By George Barnett at October 29, 2008 4:03 PM

Hi George,

What a great big test plan :) Thank you for these files.

Finaly, I succeed into creating random issues in JIRA few days ago. But I am facing now to some errors of permission for few new issues. I will detail them on JIRA's user forum. But I saw we were doing similar things to achieve that. You had probably seen them.

Cheers,
Thomas.

By Thomas Chemineau at November 6, 2008 7:35 AM

Hi Thomas,

Have a look in the setup test plan for the groups. The tests I've written take care of group setup needed for users to "work" on the issues.

George

By George Barnett at November 6, 2008 9:51 PM

Hi George,

I am new to jMeter and having an issue with reading filenames from a .csv file and entering the same as a variable in the "File Path:" for "Sending Files with this Request:" feature.

Here are the detailed steps that I have done:
- Created a CSV Data Set config which has a list of filename
- Created a "HTTP Request", sending the information to a HTTP URL, using the "POST" Method and using the variable from the CSV dataset in the "File Path:" for "Send Files with this Request" feature.

The CSV file has 5 files.
- I tried running the test with 1 thread looping 5 times and each time, it pulled the first file from the list. Is there a way that it can iterate through the filelist and pull different files?

By Vimal at November 20, 2008 11:09 AM

Hi Vimal,

The first resource I should suggest is to subscribe to the JMeter Users mailing list:

http://jakarta.apache.org/site/mail2.html#JMeter

A thread group looping 5 times should read a new variable each time. I've checked that it works - I would suggest checking the delimiter on the CSV Data settings and then looking for errors in the following ways.

I would add a "Tree Listener" to the project so you can check the output, as well as a "Debug Post Processor" after the HTTP module since it will print the variables at that point.

The final place to look for errors is in the jmeter.log file that's created where you start JMeter. If you want more detail from the log, you can edit the jmeter.properties file in the JMeter bin directory which has log settings.

By George Barnett at November 23, 2008 3:25 PM

Hi,
Neat article, gives me a few ideas for my next bunch of performance scripts. Look forward to seeing your next article.

T (Byron bay)

By T at December 10, 2008 6:59 PM

Can anyone one clarify me how can we edit jmeter source files

By Anonymous at December 17, 2008 10:14 PM

Hi,

JMeter source files are XML so it's possible to edit them using a text editor. That said, it's not very practical. The best way to change the files is to open JMeter and then open the .jmx files as you would any file, using File->Open.

By George Barnett at December 17, 2008 10:58 PM


How to analysis the output of the jmeter??

Whtr average is the response time ???

Pls clear my doubt

balachit@yahoo.co.in

By balaji at February 19, 2009 9:49 PM

Hi George --

I am somewhat new to Jira (and JMeter) but would be interested if there are existing performance tests that one could throw at Jira itself (not Fisheye) so we could evaluate it on different configurations.

-- Tom

By Tom Deneau at February 20, 2009 1:59 PM

Hi,

It possible to generate graphs using the perl script linked to in the content of this blog. I would also suggest using a Summary Report in your JMeter plan as this will give you the average response time of your samplers.

By George Barnett at February 26, 2009 5:51 PM

Hi Tom,

I've contacted you via email regarding your query.

By George Barnett at February 26, 2009 5:52 PM

Hi George...
I have not found links to the 'future' articles. Have they been written yet? This is a fun and educating article and I would like to continue. Thanks

By Glenn at March 25, 2009 10:33 AM

Some more information is provided at http://jmetertips.blogspot.com regarding JDBC testing in Jmeter.It might help for anyone.

By pramod at April 27, 2009 6:13 AM

Hi George,
Do you have any idea how to get the average response time for a number of threads via command line and not GUI such as 'Summary Report' listener?
Thanks in advance,
Hamid

By Hamid at June 9, 2009 6:12 PM

I am currently running my own JIRA (and Confluence, if time permits) performance tests. See http://www.schirmacher.de/display/INFO/JIRA+Performance+Tests .

If you have other ideas for JIRA performance tests please let me know.

By Arne Schirmacher at July 2, 2009 5:26 AM

Hi Grorge,
I am new to JMeter, and curious about variable-features you use in this article.
But, how does ${__P(script.base,.)} means?
Could you give me some explanation?

Thanks

By Ricky at July 6, 2009 8:49 PM

Hamid - there's a listener called "Generate Summary Results". See if that meets your needs?
Arne - There's some excellent information on that page. I look forward to watching it as more information is added!
Ricky - in this case, the ${script.base} variable in JMeter will either contain the default (a ".") or whatever is passed in on the command line with -J. Since normally there's nothing passed in on the command line, it will contain a "." meaning the current working directory

By George Barnett at July 6, 2009 9:24 PM

Hi George,

I got nagtive numbers for the response time in the reports (summary report, aggregate report, etc) often. Any ideas about that? I am using jakarta-jmeter-2.3.3

Label # Samples Average Median 90% Line Min Max Error % Throughput KB/sec
/review/message 5 -141805 155 287 0 287 0 0.698031551 258.4517715
/ocumen/message 5 -141886 8 236 0 236 0 0.931272118 4.228921238
/revapp/logoff 1 70 70 70 70 70 0 14.28571429 4297.614397

By Shan at July 14, 2009 11:33 AM

Hi George,

I tried running the test from the command line, but instead of displaying the summary results I'm getting this message:

D:\Jmeter\bin>jmeter -n -t Test.jmx
Created the tree successfully using Google_search_csv.jmx
Starting the test @ Fri Oct 23 07:50:29 CST 2009 (1256255429500)
Waiting for possible shutdown message on port 4445
Tidying up ... @ Fri Oct 23 07:50:34 CST 2009 (1256255434468)
... end of run

Did I miss something?

Thanks in advance,
Girlie

By girlie at October 22, 2009 7:57 PM

Hi Girlie,

From the data you have provided, it looks like the test has run fine. I would suggest adding in some of the listeners I mention above. Configure them to save the data to a result file which can then be parsed later to display the results.

George

By George Barnett at October 22, 2009 8:02 PM

Hi Shan,

That's very strange - I've never seen negative numbers. I would suggest asking on the JMeter Users mailing list.

George

By George Barnett at October 22, 2009 8:03 PM

Hi George,
I've got a test plan where I'm trying to use a variable for where my listeners are logged to, same where you are doing in your test plan. So "logs" - defined in the UDV as the following: C:\path\to\jmeter\table.jtl and in the View Results in Table -> Filename contains the following line: ${logs}\view_results_in_table.jtl

This all looks good to me, or perhaps I'm missing something, but the logs are created under the actual directory called "${logs}"... Can't figure it out. Any ideas?

By Anonymous at January 28, 2010 7:00 AM

The directory you're creating should exist. I think the problem is though that you're double specifyingthe logfile, so you're going to end up with C:\path\to\jmeter\table.jtl\view_results_in_table.jtl. Choose either one of the other, ie remove the \view_results_in_table.jtl from the "Results in Table" or change the UDV logs variable to: C:\path\to\jmeter\

By George Barnett at January 28, 2010 4:18 PM

Post a comment

If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.





Remember personal info?

Type the characters you see in the picture above.