User interface performance really matters for web applications; it is the part of the web application (and the cloud for that matter) that the user, the customer, experiences. If the user experience is dreadful, users complain and clients refuse to purchase the product.
As a performance engineer for IBM SmartCloud Enterprise, I developed a fully end-to-end automation framework for UI performance that provides professional measurements, including:
- Page-based performance metrics
- Necessary resource monitoring and capturing statistics
- Network bandwidth simulation and controlling
- Multiple parameter-based functionality control
Although many of these issues have been addressed by web-based performance-monitoring software, there are still two major challenges that need attention:
- Challenge #1: How do you target and obtain the detailed performance information for some special requests automatically?
- Challenge #2: How do you calculate the accurate page performance from end user experiences?
As an example for Challenge #1, there are three RPC requests on the control panel page of
the IBM Cloud: getInstances, getAvailableImages, and
getAvailableStorage. These requests are the most important
requests that can potentially bottleneck page performance. You need to have the performance metrics for them evaluated and reported on daily or weekly.
You should consider this a general requirement; you will need an automated module that can detect and target any special request (like these RPCs) and have the performance details captured or calculated. This includes such items as:
- Client begin requests
- Client done requests
- Server begin responses
- Server done responses
- Client begin responses
- Client done responses
It is hard to find an existing third-party engine or tool you can directly use to automatically handle this level of performance monitoring; that's why I list it as a challenge.
Why would I issue Challenge #2? Because general solutions always provide fully loaded time as the page response and the time can not be broken down. But sometimes you don't care about the fully loaded time; you'd rather be able to measure the performance from a starting request you defined to an ending request you defined. These are meaningful and useful metrics for web developers in performance tuning if they would like to focus on interval calculation for continuous code and performance improvements in regression life cycles.
Later in this article, we'll look closely at how this framework answers the challenges of automated metric type captures and interval time captures, but first let's examine the framework, the Fiddler integration, and then later discuss how the framework interacts with a cloud environment and how to install it on the IBM Cloud.
The automation framework and Fiddler
Let's look at the automation framework overview from architecture level (Figure 1).
Figure 1. The automation framework overview from architecture level
Outside the pink module Fiddler As Proxy/Agent is the framework prototype which has been implemented. It can be called the mainstream of the entire framework.
Now let's take a look at what's inside the Fiddler As Proxy/Agent. For better understanding of the details of Fiddler side, see Figure 2.
Figure 2. Inside Fiddler As Proxy/Agent component
This covers both the interactions with the framework mainstream, as well as Fiddler rule overwriting. More detailed explanation is provided later. For now, let's examine Fiddler and its integration into the framework.
- Fiddler is a web debugging proxy that logs all HTTP and HTTPS traffic between your computer and the Internet.
- Fiddler allows you to inspect all HTTP/HTTPS traffic, set breakpoints, and "fiddle" with incoming or outgoing data.
- Fiddler logs requests and the responses so you can see what is working and what isn't working.
Fiddler includes a powerful event-based scripting subsystem and can be extended using any .NET language. Figure 3 shows the UI sample.
Figure 3. The Fiddler UI sample
With Fiddler, you can leverage the subsystem by writing code to make your extensions. You can edit your scripts using the Rules | Custom Rules... menu. When you save the script, it is automatically recompiled and loaded into Fiddler. Scripts are written in Microsoft JScript.NET and include limited access to the Fiddler Object Model.
Fiddler's default rules are stored in \Program Files\Fiddler2\Scripts\CustomRules.js. All your secondary coding will overwrite this file; for example, if you are expecting to add custom columns to the Fiddler UI, to modify web request or response for different goals just like a hack, or to work with Fiddler menus.
Here is a simple example, adding the code to OnBeforeRequest in CustomRules.js in order to search all web responses for a list of strings then display the calculated output in the defined customcolumn:
oSession.utilDecodeResponse();
// Create a array of strings we're looking for.
var oFindStrings = new Array( "XMLHttp", "onreadystatechange", "readyState",
"responseBody", "responseText", "responseXML", "statusText", "abort",
"getAllResponseHeaders", "getResponseHeader", "setRequestHeader");
// For each target string, check the response to see if it's present.
var iEach=0;
oSession["ui-customcolumn"]=String.Empty;
for (iEach; iEach<oFindStrings.length; iEach++){
if (oSession.utilFindInResponse(oFindStrings[iEach], false)>0)
{
oSession["ui-color"]="purple";
oSession["ui-customcolumn"] += oFindStrings[iEach]+"; ";
}}
|
Remember the requirements; you need an interface to build interactions between Fiddler and
the user or any module (like an automation program). To do this, you can use Fiddler -ExecAction.exe, a command line executable suitable for calling from batch files or unit tests.
This is the only interface you can leverage to automate things, including controlling and interacting with Fiddler, since this command passes its command line into FiddlerScript's OnExecAction function for processing, just like Fiddler's QuickExec box.
Let's say you have done the implementation on the Fiddler side for Challenge #1 to make a
build verification test (BVT) delivery. Set rpc as the parameter for ExecAction.exe so that Fiddler knows what should be going if the command is triggered. Then it is easy to run this functionality; just type ExecAction rpc in Fiddler's QuickExec box.
To call it from any of your external automation programs, you just need to set the .exe
path in the system variables and run in your DOS console. For example, in AutoIT the one-line code is _RunDos("ExecAction rpc").
It is the same process for Challenge #2. You can use anything as the parameter (calc_cp) then invoke it in AutoIT with _RunDos("ExecAction calc_cp").
There are different types of requests for a general web application, things like images, js, css, app calls, etc. If you can get more information and performance metrics for each classified request, you will have more power to do performance tuning should the need arise.
For the IBM Cloud, there are three remote procedure call requests (getInstances, getAvailableImages, getAvailableStorage) on the control panel page that deserve your attention.
The request getInstance is designed to get detailed
necessary information for all the instances (actually, virtual machines) under the
current user, then return a text/json object. Figure 4 shows what this looks like.
Figure 4. The getInstance RPC
Figure 5 shows part of the raw metrics translated from the json in Figure 4.
Figure 5. Raw metrics from the text/json object
For this request, there are only 12 instances loaded in the current customer account and the received bytes are 15,544 (headers: 274; body: 15270). Just imagine that with the number of instances increasing, the return information will increase geometrically and the point becomes how scalable the request is:
- What if the customer holds 1,000 instances?
- Is it scalable to accommodate the largest number of instances available under a customer account?
- Is there bottleneck when the return is too large?
- What's the impact of such a thing happening on the performance parameters?
To answer these questions and to avoid the potential issues, you first need to keep the very getInstances request measurable and traceable in a regression test life cycle. You will need to obtain as much detailed metrics as possible and keep them in an apples-to-apples comparison format.
Now what about Challenge #2? How is interval time important to UI performance tuning?
This requirement is about how to calculate the accurate page response. Generally you can use tools to capture the fully loaded time for one page, but sometimes you do not need these metrics but you do need to measure a response starting from a specified request to another specified request.
This usually happens if a web developer would like to get feedback or an estimation of whether or not a code change is effective. In the IBM Cloud for example, when a developer submits code for control panel page performance improvement and additionally applies a lazy loading pattern for page loading, the developer needs to get metrics on the page response time ending with some specific request to provide an accurate reflection of the end user experience and how well the code updated (as shown in Figure 6).
Figure 6. Interval time is important to UI performance tuning
A successful getInstances call leads to the display of the instance table in the UI level. From the user experience perspective, you need to obtain the exact duration time once the instance table is visible. So for accurate performance measurement, you need to exclude in the same page the set of requests that follow getInstances.
Now let's look at how the framework performs in a cloud environment.
The framework works on UI performance for any general web application:
- From the browser-independent Fiddler side, there will be no limitation on whatever browser the cloud front tier is running on.
- From driver side, actually you can use the same language that is used in this framework AutoIT or just write your own driver using any language you are comfortable with. For example, you can leverage the WatiN framework using .Net programming or Selenium in Java™ programming.
Look again at Figure 2. You can see the rectangles specifying the code flow; the left one is for Challenge #1 requirements. In Fiddler-side development, the point is how to overwrite the Fiddler CustomRules.js in the Fiddler framework without having sufficient documents supported. Overwrite the rule to:
- Get all sessions.
- Traverse each session.
- Locate the target by condition.
- Allocate a new session array to store the target session.
- Write a session into the archives.
Here are partial code samples on how to process the RPC call getInstances:
var oSessions: Fiddler.Session[] = FiddlerObject.UI.GetAllSessions();
var iSessions : Session[] = new Session[1];
//[getInstances]for each session perform filtering:
//if session's url equals '/cloud/enterprise/auth/cloud-rpc' && its request
body contains 'getInstances' : save the session to RPC_getInstance_id.zip
for (var x = 0; x < oSessions.Length; x++)
{
if( (oSessions[x].PathAndQuery=="/cloud/enterprise/auth/cloud-rpc") &&
(oSessions[x].utilFindInRequest("getInstances",true)>-1) )
{
iSessions[0]=oSessions[x];
Utilities.WriteSessionArchive(
"RPC_getInstances_"+oSessions[x].id+".saz",iSessions,"",true);
FiddlerObject.StatusText = "Success dump the GetInstance PRC archive
to RPC_getInstances_"+oSessions[x].id+".saz";
break;
}
}
|
Processing getAvailableImages and getAvailableStorage are done the same way and it is easy to write the corresponding version using this listing as a template.
Look again at Figure 2. You can see the rectangles specifying the code flow. The right one is for Challenge #2 requirements. Overwrite the rule to:
- Get all sessions.
- Traverse each session.
- Locate the starting target request by condition.
- Obtain the
clientBeginRequesttime and the session ID. - Allocate a string list with
size=3and store the info in its first item. - Locate the ending target request by condition.
- Obtain the
clientDoneResponsetime and the session ID. - Store this info in its second item.
- Calculate the duration time.
- Store the info in its last item.
- Write the string list to duration.txt.
Here are the code samples on how to calculate the accurate interval time for the control panel page of the IBM Cloud:
//[cpbegin]for each session performs filtering:
//if sessions's url equals '/cloud/enterprise/user/control?csrftoken=':
record the ClientBeginRequest timestamp
for (var x = 0; x < o_calc_cp_allSessions.Length; x++)
{
if( o_calc_cp_allSessions[x].PathAndQuery.Contains
("/cloud/enterprise/user/control?csrftoken="))
{
var cp_begin:String = o_calc_cp_allSessions[x].Timers.ClientBeginRequest;
cp_b = new Date(o_calc_cp_allSessions[x].Timers.ClientBeginRequest);
cp_array[0] = "Sid,"+o_calc_cp_allSessions[x].id+",ClientBeginRequest,"+cp_begin;
FiddlerObject.StatusText = "the session indicating cp start is
successfully found, with Sid: "+o_calc_cp_allSessions[x].id;
Break;
}
}
//[cpend]for each session perform filtering:
//if sessions's url equals '/cloud/enterprise/auth/cloud-rpc' &&
its request body contains 'getInstances' : record the ClientDoneResponse timestamp
for (var x = 0; x < o_calc_cp_allSessions.Length; x++)
{
if( (o_calc_cp_allSessions[x].PathAndQuery=="/cloud/enterprise/auth/cloud-rpc")
&& (o_calc_cp_allSessions[x].utilFindInRequest("getInstances",true)>-1)
)
{
var cp_end:String = o_calc_cp_allSessions[x].Timers.ClientDoneResponse;
cp_e = new Date(o_calc_cp_allSessions[x].Timers.ClientDoneResponse);
cp_array[1] = "Sid,"+o_calc_cp_allSessions[x].id+",ClientDoneResponse,"+cp_end;
FiddlerObject.StatusText = "the session indicating cp end is successfully
found, with Sid: "+o_calc_cp_allSessions[x].id;
break;
}
}
//try calc the duration
if(cp_b != null && cp_e !=null)
{
var timePast : double = (cp_e - cp_b)/1000.00
cp_array[2] = "Timepast,"+timePast;
FiddlerObject.StatusText = "the time duration for cp is calculated
successfully: "+timePast;
}
var myByteArray:byte[] = System.Text.Encoding.UTF8.GetBytes
(cp_array[0]+"\n"+cp_array[1]+"\n"+cp_array[2]);
//write array to file by leveraging the built-in api.
Utilities.WriteArrayToFile(CONFIG.GetPath("Captures") +
"duration_cp.txt",myByteArray);
|
In driver-side development, you should understand where the code to be changed has to
adapt to the new website. In the IBM Cloud, there are six pages included for web
navigation, so you just need to look into the code and replace the page identities with
the expected identities in your cloud. For example, Figure 7 is one of those IBM Cloud
page samples for Account. Replace the identity Account with your entry.
Figure 7. Replace with your own entry
To apply the framework to the new cloud, you just need to understand the Fiddler scripting as well as the driver-side coding. Referring to the samples on the cloud pages, you should easily understand how to adapt them to make your own solutions.
Setting up the framework in the IBM Cloud
The set up and use the framework is easy because the framework is a full end-to-end solution. Figure 8 shows an overview:
Figure 8. Starting setup
To start:
- For software installation, you need AutoIT and Fiddler installed on your machine.
- As a configuration prerequisite, run SystVarDependencyCheck.exe to automatically update your system to run the solution. Add the path of Fiddler executables and the path of Fiddler default data. Do that once for all for the first user only.
- An overview of the driver-side binaries overview:
- Manager.exe is the run2run controller.
- UIIE_Fiddler_Shot_1.0.exe is the baseline run driver.
- baseline.properties is the only interface the user needs and can edit for customized purposes.
- The Fiddler-side source CustomRules.js doesn't appear in Figure 7; this javascript is the interface to interact with Fiddler by coding. You just need to copy the updated file of the framework to your local Fiddler as an overwrite.
Now let me brief you how to use the framework in the following scenarios. Store these files on your computer: UIIE_Fiddler_Shot_1.0.exe, Manager.exe, and baseline.properties. Edit the baseline.properties since it is the only interface used to customize the run.
For a clearer understanding, here are the entries of the properties file:
- URL: The cloud website.
- ServerAddress: The machine IP of the web application.
- User: The customer user ID you are using to login.
- PASSWORD: The password of the user.
- CacheClean: The flag or switch for browser cache controlling.
- SuccessCapacity: Expected number of successful baselines in a run2run session.
- TotalExitCapacity: The value for run2run to exit which the accumulated number of baseline run equals in this run2run session.
- BWEnable: The flag or switch for bandwidth simulation enablement.
- BWIN: The download rate via TCP/IP in a bandwidth enablement baseline run.
- BWOUT: The upload rate via TCP/IP in a bandwidth enablement baseline run.
- Comment: Any comments you would like to add in the output of the running baseline.
Now let's walk through the first scenario: Set up, execution, and results for a baseline run. The capturing and monitoring of the page-based performance metrics, resource-usage performance metrics, and network-usage performance metrics are built in, implemented in the driver-side, UIIE_Fiddler_Shot_1.0.exe. So there is no need to configure the baseline.properties upon capturing these metrics. As long as you trigger a baseline run, these metrics will be always obtained. Figure 9 is a screenshot of a sample baseline run.
Figure 9. Sample baseline run
Take the sample baseline folder with the name "Base_AllRequests_09-06-2011-07-42-59_N" for example, in which there is the following directory sys_metrics which contains four auto-generated files:
- cpu.tsv is the cpu usage information.
- ping.log records the network latency metrics.
- tracert.log is the information of IP trace route.
- baseline.properties is a copy indicating the settings for this baseline run.
For Challenge #1 requirements, the RPC_getAvailableImages_SID, RPC_getInstances_SID, and RPC_getAvailableStorage_SID directories are BVT deliveries in terms of the three target RPC requests. SID is the index number among the whole requests in this baseline run.
The duration_cp.txt file is for Challenge #2 requirements; it is the accurate page performance for control panel page in the IBM Cloud. It follows this format, with three lines:
Sid,233,ClientBeginRequest,9/6/2011 7:49:14 AM Sid,285,ClientDoneResponse,9/6/2011 7:49:29 AM Timepast,14.672 |
The _index.html file and the raw directory contain the raw metrics for all the requests during the navigation for entire website. Everything you can get, including but not limited to performance.
The Screen_*_.jpg files are the screen shots for each page. This can be useful information to help reproduce the scenarios if there is a need, including troubleshooting for exceptions.
Scenario: Baseline run with functionality control: Bandwidth and simulation
For the next scenario, let's look at set up, execution for a baseline run with functionality control: Bandwidth control and simulation. You'll see these lines of code:
BWEnable=false BWIN=400Kbit/s BWOUT=384Kbit/s |
Here BWEnable is the bandwidth simulation or control switch.
If set to true, then the baseline will enable bandwidth
simulation. When set to false, the functionality is disabled.
The parameter BWIN is used to set the download speed via TCP/IP.
The parameter BWOUT is used to set the upload speed via TCP/IP.
Scenario: Scenario: Baseline run with functionality control: Cache control
There is a variation on this scenario: Set up, execution for a baseline run with functionality control: Cache control. The code for this scenario looks like this:
CacheClean=false.
Here, CacheClean is the flag to control browser cache. If it is
set to true, then the browser cache will be cleaned before
each baseline. When set to false, the browser will be kept cached for each baseline run.
Scenario: Multiple baseline runs
In the final scenario: Set up, execution for a run2run session (multiple baseline runs), you'll see this code:
SuccessCapacity=7 TotalExitCapacity=14 |
Multiple baseline runs is the same as repeated baseline runs. That's basically required in performance tuning since users want more sampling from repeats while one baseline is insufficient.
You have to use a binary independent from baseline to do this job; its name is Manager.exe and this code is its parameters. SuccessCapacity is the value how many successful baseline runs you expect in this launch. TotalExitCapacity is the max value at which the main job is forced to exit when the accumulated run exceeds, whatever the expected number of success in this launch.
From the detailed metrics in BVT delivery, you can detect if the critical request is inducing a performance drop, so that the core efforts can be taken and a request profiling work will be performed.
From accurate page performance metrics, you can spot the apples-to-apples trend and can easily detect whether a performance issue exists at page level.
This article provided information on how to leverage secondary development in Fiddler for web application UI performance engineering. Two challenges and their accompanying requirement are detailed:
- The resolution of Challenge #1 provides a general solution on how to control and automate Fiddler to fully interact with any target web request you are interested in. Whether a tester or developer, using this information you can at least make a build verification suite test automation delivery for UI performance monitoring. And, you're not limited to this. You can make other types of deliveries because you have mastered the critical capability — how to locate/control/plunge into any web request you would like to be the target of your web application through coding.
- The resolution of Challenge #2 provides a general solution on how to calculate the response performance as specially required for any page of your web application. With this technique, you are armed with an interval computation capability in order to snag the response performance for any page using a starting and ending request as the parameters.
Learn
-
For developer resources mentioned in this article:
- Fiddler developer information
- Fiddler developer cookbook
- MSDN JScript.Net reference
- AutoIT developer information
-
Visit the IBM Cloud site for current cloud offers.
-
For more on how to perform tasks in the IBM Cloud, visit these resources:
- Up and download files from a Windows instance.
- Install IIS web server on Windows 2008 R2.
- Create an IBM Cloud instance with the Linux command line.
- Create an IBM Cloud instance with the Windows command line.
- Extend your corporate network with the IBM Cloud.
- High availability apps in the IBM Cloud.
- Parameterize cloud images for custom instances on the fly.
- Windows-targeted approaches to IBM Cloud provisioning.
- Deploy products using rapid deployment service.
- Integrate your authentication policy using a proxy.
- Configure the Linux Logical Volume Manager.
- Deploy a complex topology using a deployment utility tool.
- Provision and configure an instance that spans a public and private VLAN.
- Secure IBM Cloud access for Android devices.
-
In the developerWorks cloud developer resources, discover and share knowledge and experience of application and services developers building their projects for cloud deployment.
-
Find out how to access IBM SmartCloud Enterprise.
Get products and technologies
-
See the product images available for IBM SmartCloud Enterprise.
Discuss
-
Join a cloud computing group on developerWorks.
-
Read all the great cloud blogs on developerWorks.
-
Join the developerWorks community, a professional network and unified set of community tools for connecting, sharing, and collaborating.
Yu Tong Li has four years experience in software development and testing. His interests include testing tools development on different platforms, web-based automation framework development, and open source secondary development and performance engineering. He's worked at IBM since 2010 and has published five articles and holds two patents.




