TIBCO General Interface™ Performance Profiler
Ever ask these questions about your Ajax applications?
How long did it take that service to respond?
How long did it take for that component to render?
How long did it take that data to parse?
How long did it take for that function to execute?
For answers to these kinds of questions, checkout TIBCO General Interface Performance Profiler, an open source (BSD License) Ajax application profiling tool for benchmarking the performance of Ajax solutions created with TIBCO General Interface and other Ajax toolkits. Create performance testing scripts in JavaScript then run them against live applications to get performance statistics for selected operations within your application. The Performance Profiler is smart enough to let you handle asynchronous operations too. Check out the live example, then see how it works below.
Demo
Here's a live demonstration profiling craigslist.remixedby.us which uses three Ajax libraries: TIBCO General Interface, dojo for offline capabilities, and Google Maps for, well, you know... maps.
- To start the test you'll want to press Run. Or you can press Step to execute one operation at a time.
- If it's your first time using the app, you'll notice a bit more load time on start up. This is when the initial libraries are loaded. The app is intended to be used for longer than the average 12 second life span of an HTML page, so a few more seconds spent on initialization pays off in time savings later, which is pretty typical for Ajax applications created with TIBCO General Interface.
- To see the real benefit of the cached application files, press Reload. This will run the app again, and you'll see faster times.
- You can also get the raw test data via Export CSV or Export XML
How it Works
To get started, you can download and use the Performance Profiler and its full docs under an open source BSD License. Also checkout the full test script (benchmark.js) from the demo. Several examples of test scripts from that file are also are shown below, but the examples that come with the full docs are probably the best place for those of you that want to use the tool.
In brief, there are just a few basic concepts you need to know when using the Performance Profiler.
- Test Script: This is the script that remote controls the application you're testing by passing JavaScript commands into a queue that in turn runs those scripts against your Ajax app. When a process is complete, the Performance Profiler measures the time it takes to complete those operations in the context of the Return Values (explained next).
Return Values: Each function in your test script must return one of the following values: SLEEP, SLEEP_LONG, WAIT, or POLL. See the docs for full details, but in brief...
SLEEP is useful in testing aspects of the user interface. SLEEP_LONG will measure the time it takes from invocation until all other processes returning SLEEP are complete. If you're unsure whether to use SLEEP or SLEEP_LONG, SLEEP_LONG is the safest choice because it covers all use cases. WAIT should be returned when testing asynchronous processes. The test case must asynchronously call completeTestCase to indicate that the test has completed. If your asynchronous process does not have a callback function, then use POLL. POLL should be usedwhen testing an asynchronous operation that doesn't have a callback. The test case should set POLL.poll to a function that returns true when the test completes. - By default at least one GI app is required, but you can use Performance Profiler to test other Ajax controls and libraries as well -- as shown in the demo and examples.
Example 1
Example 1 below is a snippet that selects a posting in the list, opens the first two postings in tabs, does another category search for "mattresses", then opens another tab with the first result for that search. gicx is the namespace for the GI application's javascript logic. The example shows uses of SLEEP_LONG, SLEEP, and POLL.
{name:"Select Posting", fct: function(objServer) {
gicx.getResultsTable().selectRecord(gicx.getResultsTable().getSortedIds()[0]);
return gi.test.gipp.SLEEP_LONG;
}},
{name:"Open Posting 1", fct: function(objServer) {
gicx.openPosting(gicx.getResultsTable().getSortedIds()[0]);
return gi.test.gipp.SLEEP;
}},
{name:"Open Posting 2", fct: function(objServer) {
gicx.openPosting(gicx.getResultsTable().getSortedIds()[1]);
return gi.test.gipp.SLEEP;
}},
{name:"Search craigslist 2", fct: function(objServer) {
gicx.APP.getJSXByName("query").setValue("mattress");
gicx.search();
gi.test.gipp.POLL.poll = function(objServer) {
return gicx.getResultsTable().getSortedIds().length;
};
return gi.test.gipp.POLL;
}},
{name:"Open Posting 3", fct: function(objServer) {
gicx.openPosting(gicx.getResultsTable().getSortedIds()[0]);
return gi.test.gipp.SLEEP_LONG;
}},
Example 2
Example 2 shows the calls used to persist data through dojo.storage and call Google Maps. The craigslist app encapsulates the specific dojo and google API calls within its own logic, but you could also directly call those APIs if desired.
{name:"Save Posting (Dojo Storage)", fct: function(objServer) {
//the cache has a throttle when an item is favorited;
//bypass by immediately calling serialize (which will call dojo.storage.put)
gicx.Cache.serialize("searchHistory");
return gi.test.gipp.SLEEP_LONG;
}, meta:{unit:"x",limit:500}},
{name:"Locate Posting (Google)", fct: function(objServer) {
if(objServer.statetracker) {
delete objServer.statetracker;
gicx.Contact.showPostingAddress(
"212 Sutter St, San Francisco, CA 94108",
gicx.Posting.getActiveRecord().getAttribute("jsxid"));
} else {
objServer.statetracker = true;
gicx.Contact.showPostingAddress(
"555 Market St, San Francisco, CA 94108",
gicx.Posting.getActiveRecord().getAttribute("jsxid"));
}
return gi.test.gipp.SLEEP_LONG;
}, meta:{unit:"x",limit:500}}
Example 3
Example 3 shows how to use the WAIT return value and its associated method completeTestCase.
{name:"Load a doc async", function(objServer) {
var d = new jsx3.xml.Document();
d.setAsync(true);
d.subscribe("*", function(objEvent) {
gi.test.gipp.completeTestCase("Load a doc async");
});
d.load("xml/doc1.xml");
return gi.test.gipp.WAIT;
}
);