Skip to content
This repository has been archived by the owner on May 27, 2024. It is now read-only.

Performance Benchmarks

Sean Barbeau edited this page Jul 11, 2013 · 92 revisions

Performance (i.e., fast parsing of JSON or XML) is important to us, since it has a direct affect on the amount of time a user has to wait before they can see results fetched from the internet - in our case, real-time transit information from a SIRI REST API. Slower parsing also typically results in longer CPU, screen, and radio usage, which all negatively affect battery life.

We can optimize our SIRI client in many different ways. In this article, we'll look at the following items related to Jackson, since that's what we're using as the JSON and XML parser in our SIRIRestClient library:

  1. HTTP connection - should we use an Android-specific HTTP connection object, or the default internal Jackson HTTP object (carried over from J2SE)?
  2. Should we use the Jackson ObjectMapper or the ObjectReader for JSON parsing?
  3. Should we choose XML or JSON as the response data format?

Note: You can perform your own benchmarks using the SiriRestClientUI app, just like we did for this article!

HTTP Connection Type

We have two basic options for HTTP connections when using Jackson:

  1. Android HttpURLConnection - Instantiate our own HTTP connection via Android's HttpURLConnection, and pass the InputStream from that connection into the Jackson object.
  2. Use embedded Jackson HTTP connection - Simply pass the URL into the Jackson object (e.g., ObjectMapper, ObjectReader, or XmlMapper) and Jackson handles establishing an HTTP connection and retrieving the data.

An article on the Android Developer Blog article states that HttpURLConnection should be the most efficient connection type on Android. According to Jackson Best Practices, we should just pass in the URL and let Jackson handle the connection. But, we should keep in mind that these are suggestions targeted at desktop and server developers, and not mobile developers. As of v2.1, Jackson seems to just use the default FileInputStream connection from the normal Java platform. Given that Android is a specialized platform, it seems that the Android HttpURLConnection would be more efficient and would override any existing Jackson best practices that aren't targeted directly at the mobile platform.

For more discussion of Android's HTTP clients, please see http://android-developers.blogspot.com/2011/09/androids-http-clients.html

We hope to add future benchmarking results to this section evaluating which connection type is more efficient using the SiriRestClientUI app.

You can perform your own benchmarks using the SiriRestClientUI app, as the settings menu allows you to pick between the two HTTP connection types:

The code for both HTTP connection types is implemented in the SiriRestClient library.

Jackson ObjectReader vs. ObjectMapper for JSON parsing

There are two options for Jackson objects that can be used when parsing a JSON-formatted response:

  1. Use the ObjectMapper directly - the core class that must be instantiated before parsing JSON content in Jackson.
  2. Use the ObjectReader - this object is retrieved from the ObjectMapper after the ObjectMapper is instantiated, and can be used to parse JSON instead of using the ObjectMapper directly.

According to Jackson Best Practices, using the ObjectReader should be more efficient than the ObjectMapper, especially for Jackson versions 2.1 and later. Therefore, The ObjectMapper configuration is included only for benchmarking purposes.

We hope to add future benchmarking results to this section evaluating which connection type is more efficient using the SiriRestClientUI app.

You can perform your own benchmarks using the SiriRestClientUI app, as the settings menu allows you to pick between the ObjectMapper or ObjectReader classes:

Check out the class SiriJacksonConfig included in this project to see the instantiation and configuration of the ObjectMapper and ObjectReader, and the SiriRestClient.makeRequest() method for how the ObjectMapper and ObjectReader and then used to actually parse the JSON response.

Note: For parsing XML, there is only one option: XmlMapper.

JSON vs. XML response formats

Many web services include the option of sending a response in either JSON or XML formatting. If you're not familiar with the differences between the two formats, see a detailed discussion on the Parsing JSON and XML on Android page.

In short, JSON response tend to include far fewer characters than XML response, and look like this:

{
Siri: {
   ServiceDelivery: {
      ResponseTimestamp: "2012-08-21T12:06:21.485-04:00",
      VehicleMonitoringDelivery: [
         {
            VehicleActivity: [
               {
                  MonitoredVehicleJourney: {
                     LineRef: "MTA NYCT_S40",
                     DirectionRef: "0",
                     FramedVehicleJourneyRef: {
                        DataFrameRef: "2012-08-21",
                        DatedVehicleJourneyRef: "MTA NYCT_20120701CC_072000_S40_0031_S4090_302"
                     },
                     JourneyPatternRef: "MTA NYCT_S400031",
                     PublishedLineName: "S40",
                     OperatorRef: "MTA NYCT",
                     OriginRef: "MTA NYCT_200001"
                  }
               }
            ]
         }
      ]
   }
}

XML tends to be more verbose, and looks like this:

<Siri xmlns:ns2="http://www.ifopt.org.uk/acsb" xmlns:ns4="http://datex2.eu/schema/1_0/1_0" xmlns:ns3="http://www.ifopt.org.uk/ifopt" xmlns="http://www.siri.org.uk/siri">
   <ServiceDelivery>
      <ResponseTimestamp>2012-09-12T09:28:17.213-04:00</ResponseTimestamp>
      <VehicleMonitoringDelivery>
         <VehicleActivity>
            <MonitoredVehicleJourney>
               <LineRef>MTA NYCT_S40</LineRef>
               <DirectionRef>0</DirectionRef>
               <FramedVehicleJourneyRef>
                  <DataFrameRef>2012-09-12</DataFrameRef>
                     <DatedVehicleJourneyRef>MTA NYCT_20120902EE_054000_S40_0031_MISC_437</DatedVehicleJourneyRef>
               </FramedVehicleJourneyRef>
               <JourneyPatternRef>MTA NYCT_S400031</JourneyPatternRef>    
               <PublishedLineName>S40</PublishedLineName>
               <OperatorRef>MTA NYCT</OperatorRef>
               <OriginRef>MTA NYCT_200001</OriginRef>
            </MonitoredVehicleJourney>
         </VehicleActivity>
      </VehicleMonitoringDelivery>
   <ServiceDelivery>
</Siri>

The extra characters contained in the XML response, plus the additional complexity that XML parsers must negotiate to bind an XML document to a Java object, result in substantial negative impacts on mobile device performance, including slower responses and less battery life.

Our goal with the following experiments is to demonstrate the benefits of using JSON over XML, and also discuss some optimizations that can further improve the user experience of apps that fetch real-time transit data from web services such as a SIRI REST API.

Note: You can perform your own benchmarks using the SiriRestClientUI app, as the settings menu allows you to pick between JSON or XML responses:

Performance Benchmarks

The below section discuss the performance of the SiriRestClient (using Jackson for response parsing) for JSON and XML. Special optimizations to further improve the user experience are discussed in the next section.

Methodology

We used the SiriRestClientUI app to perform benchmarks of JSON vs. XML parsing using the SiriRestClient library on a Samsung Galaxy S3 (32GB USA Sprint CDMA) with Android 4.1.1, 1.5 GHz dual core processor, 2GB RAM (Power saving mode off). Jackson 2.1.2 with Aalto 0.9.8 was used. The Jackson Internal HTTP connection was used, as well as the ObjectReader for JSON parsing. These tests were performed on the USF WiFi network. Results from SpeedTest.NET Android app at time of test were 51353 kbps down, 49554 kbps up, and ping of 16 ms. 50 requests were performed back-to-back, without any time between requests. We implemented a timestamp recording feature to the SiriRestClientUI app and SiriRestClient library, which automatically captures how long a request took, from when the request was issued to when a Siri object became available from Jackson.

The detailed steps we used to perform the benchmarks are listed below:

IMPORTANT - Note that Step #9 below, which clears the existing process from memory to avoid back-to-back comparisons in the same app execution (i.e., warm starts), is extremely important to ensure fair test results across different configurations.

  1. Install the SiriRestClientUI from the APK (i.e., not installed via Eclipse deploy process). No obfuscation is used in the current app version.
  2. Connect your device to computer with Android DDMS running so you can view Logcat output.
  3. Start the app
  4. Set appropriate settings for the test via the 'Settings" menu item (e.g., Parsing XML vs. JSON, internal vs. Android HTTP connection, number of consecutive tests, time between tests, beep on test complete, etc.)
  5. Browse to the "Stop_Request" tab in the app.
  6. Use the following parameters, and then press the 'Submit" button:
  • key=add-your-key-here
  • OperatorRef=MTA
  • MonitoringRef=308214
  • StopMonitoringDetailLevel=normal
  • MaximumNumberOfCallsOnwards=1
  1. Check the LogCat output. If you executed just one test consecutively, you should see this "elapsed time" result at the end of the test. You can just copy/paste this into Excel file, and proceed to Step #9. However, if you execute multiple tests, when all tests are complete, you should see a comma-delimited list of elapsed response times in the log. Click on this, and copy and paste this into a new .CSV file that you create. You'll need to remove the beginning timestamp and info from the log, as well as the trailing bracket. For example, you'll paste the following text - 01-08 12:18:17.133: D/SiriRestClientUI(7957): [472.485884, 4981.10789, 5076.606135, 5520.280787, 5355.745459, 5243.094766, 5109.629177, 5228.170304, 6932.275292, 5249.198839, 4993.987486, 5397.466809, 5602.258507, 5281.977721, 7573.355714, 6665.862963, 6040.622616, 5530.230429, 5260.857622, 5797.375249] - but you should change it so its just the comma-delimited times, such as 472.485884, 4981.10789, 5076.606135, 5520.280787, 5355.745459, 5243.094766, 5109.629177, 5228.170304, 6932.275292, 5249.198839, 4993.987486, 5397.466809, 5602.258507, 5281.977721, 7573.355714, 6665.862963, 6040.622616, 5530.230429, 5260.857622, 5797.375249. Save this .CSV file with a name such as test1.csv.
  2. Open the CSV file in Excel. You should see the times each in their own row. Copy these values, then open the main spreadsheet you're using to track elapsed response times and click on the top cell of the column you want to paste the values in. Then, do Paste->Paste Special and check the Transpose option, and click Ok. This will give you a column of the response times that you can use to create a graph or do other analysis, next to columns from other tests you will run.
  3. Before switching to test another configuration (e.g., testing JSON instead of XML) and repeating Steps #3-8, please be sure to exit the app (i.e., press the "Back" button), and go to the main phone 'Settings->Application Manager' section. Here, there are typically at least two lists of apps/processes: "Running", and "Cached". To ensure fair performance comparisons due to cold vs. warm start differences (discussed in the following sections), you want to remove the app from both the "Running" and "Cached" lists. If you properly exited the app using the "Back" button, the app should already be removed from the "Running" list. For example, to access the "Cached" list on the Samsung Galaxy S3, you need to click on the "Show cached processes" button in the header of the "Running" application list. Then, tap on "Siri Rest Client" in the list of cached processes, and then tap on "Stop" to remove it from the cached process list. This ensures that the next application startup will be a cold start, which is a fair comparison against the initial startup of the app after installation, the state after a device reboot, and the state after the Android system automatically removes the app from the cached processes list (e.g., when memory is running low and you're using other applications).

Results

XML vs. JSON

The elapsed time from request to parsed response for 50 sequential requests is shown in Figure 1.

Figure 1 - XML vs. JSON Parsing - Elapsed Time from Request to Parsed Response for 50 Requests

There is a substantial difference between the "cold start" times for both JSON and XML (i.e., the first request). The time for the XML cold start response is almost 18 seconds, over 4 times as long as the time for the JSON cold start response (a little over 4 seconds). After the cold start, the differences between the response times for JSON and XML are much smaller.

Figure 2 shows the summary statistics for XML and JSON parsing time for this test.

Figure 2 - XML vs. JSON Parsing - Summary Statistics for the Elapsed Time of 50 Requests

JSON edges out XML in average response time of 401ms, vs. the XML average response time of 625ms. 95th percentile of elapsed times is closer, with JSON having a 95th percentile of 501ms and XML having a 95th percentile of 626ms. The increase in standard deviation for XML response time reflects the initial large cold start value that is substantially larger than the following warm starts.

Discussion

As mentioned above, the first execution of a request to the server (i.e., a cold start) typically takes much longer than subsequent requests (i.e., warm starts). This is because Jackson will dynamically construct Class model from Java class definitions the first time deserializers are needed. This typically occurs first time the readValue() Jackson method is called (i.e., when the application initiates the request). Here, JSON yields significant better performance than XML - JSON performance is over 4 times faster than XML with a time difference of 14 seconds. After this initial cold start, Jackson will typically parse subsequent responses (i.e., warm starts) more quickly for both JSON and XML. As stated above, JSON has a slight performance advantage for warm starts too - an average of 224ms faster than XML. Since user interfaces studies (TODO - need citation) have indicated that users perceive timespan periods greater than 100ms in duration as delays, JSON still yields a noticeable performance increase for warm starts from the user's perspective.

On Android, the warm start state can persistent even if the app is closed by the user (i.e., the "Back" button is pressed) and re-opened. Android devices will typically keep recently closed apps in memory as a cached background process to enhance future startup performance. In this case, when the user "starts" the app, it is actually loading the application from the cached process in memory, which loads all the Jackson data structures needed to perform quick parsing on warm starts without needing to re-initialize them from a cold start state. As a result, when comparing different app configurations (e.g., XML parsing time vs. JSON), its important to note that the first execution of the app (i.e., when the app is truly starting up for the first time without being restored from a cached process) will typically show significantly worse performance than subsequent warm starts.

While the warm start state provides a significant advantage in response time performance, it unfortunately cannot be reliable upon for consistent performance increases after an app is started on the device. Android may remove a cached process from memory if the operating system/framework is running low on memory. Given the multitasking that typically occurs on most cell phones, especially in a scenario where the user is waiting for a bus to arrive, performing tasks such as checking email, internet browsing, or using social networking apps may result in the real-time transit app being removed from the app cache. At this point, the app will revert to the cold start state and the there may be a significant delay in retrieving transit data. The size of the SiriRestClientUI cached process was observed to typically be between 24-31MB, which is large for a frequently used app. For comparison, on a Samsung Galaxy S3 following apps had the following cached sizes - Calendar app = 7.2MB, Clock = 16MB, Google+ = 17MB, Maps = 13MB. Since the largest non-system processes are typically the first targets for process cache eviction, it is likely that this app would frequently be restored to a cold start state.

The above observations lead us to pursue a manual caching strategy for Jackson objects on Android in an attempt to consistently reduce the cold start penalty for response times. The follow section discusses the results of these Jackson object manual caching optimizations.

Optimization using cached Jackson objects

To improve cold start performance of retrieving and parsing the SIRI responses using Jackson, we must gain further control over the caching process. To recap, warm starts have substantially shorter elapsed response/parsing times than cold starts. Our definition of cold and warm starts is again detailed below:

  • Cold start = Android app process is not cached and no requests have been executed during this app execution (e.g., first start up of app).
  • Warm start = The Android app already contains an initialized Jackson object from a previous request. This state occurs when the app is already running and has made previous requests during this execution session, or when the Android app process was cached from a previous execution and restored from that cached state by the Android OS.

One method to possibly improve cold start performance is to gain further control over the caching mechanism that makes warm starts performance substantially better than cold starts. Since an Android app can't directly control when its own process is cached (or evicted from the process cache) by the Android OS, we must look at alternative caching mechanisms that can save and retrieve this application state even after the application process is completely terminated and evicted from the process cache by the Android OS. We call this mechanism a "Pseudo-warm start," which we define as follows:

  • Pseudo-warm start = An artificial warm-start by the app, where the Jackson object is manually cached to persistent memory by the app and read from memory during app startup (in what would otherwise be a cold start).

Figure 3 shows the stages of application execution for A) Cold Starts, B) warm starts, and C) Pseudo-Warm Starts.

JacksonObjectCachingDiagram

Figure 3 - The Stages of App Execution for Cold, Warm, and Pseudo-warm Starts

The red-shaded blocks (i.e., the first block in A) and C)) indicate the overhead required to initialize Jackson (note that warm starts do not have this overhead). In C), we replace the normal Jackson initialization process with reading the cached Jackson objects that were initialized in a previous application execution and then written to a persistent cache - this is the Pseudo-Warm Start.

Our initial goal with our first set of tests, discussed next, was to evaluate whether the cache read used in Pseudo-Warm starts is faster than the normal Jackson initialization process in cold starts.

A final note on Figure 3 - With C) Pseudo-Warm Starts, we can actually start the cache read immediately on application start-up. Unlike the normal Jackson initialization on a cold start, we don't need to wait for the user to initiate a request before starting the initialization process via the cache read. This flexibility is indicated in Figure 3 via the "Request initiated" call out over the entire cache read period, as the request may be initiated by the user at any point during the cache read. The flexibility of when the cache read can be started is important in later discussions of this optimization.

Android cache implementation details - We implement cache writing in Android by serializing the Jackson objects that contain the state necessary to re-create a warm start to a private file in the application's package via the Context.openFileOutput() method and an ObjectOutputStream. We implement cache reading by reading the file from the cache and deserialize the Jackson objects on a cold-start via the Context.openFileInput() method and the ObjectInputStream. For JSON formatting, either the Jackson ObjectMapper or ObjectReader is serialized and deserialized, depending on the configuration of the SIRI Rest Client via the "Settings" menu. For XML formatting, the Jackson XMLMapper is serialized and deserialized.

Methodology

We again used the SiriRestClientUI app to perform benchmarks of JSON vs. XML parsing using the SiriRestClient library on a Samsung Galaxy S3 (32GB USA Sprint CDMA) with Android 4.1.1, 1.5 GHz dual core processor, 2GB RAM (Power saving mode off). Jackson 2.1.2 with Aalto 0.9.8 was used. The Jackson Internal HTTP connection was used, as well as the ObjectReader for JSON parsing. These tests were performed on the USF WiFi network. Results from SpeedTest.NET Android app at time of test were 52176 kbps down, 78721 kbps up, and ping of 15 ms. 30 requests were performed, taking steps outlined in the methodology below to reset to a cold start state between each cold start test, and to the pseudo-warm start state for the pseudo warm start tests..

An overview of the process of testing -

A) A cold start response time is measured,

B) We turn on caching in the app and make another request so the app caches the Jackson object used to make requests to persistent memory - we measure the cache write time as well as cached Jackson object size,

C) We manually remove the Android cached process from memory via the Application Manager to reset to a cold start state,

D) A pseudo-warm start response time is measured (=Time to read cached object + elapsed response time).

E) We turn off caching in the app, and we manually remove the Android cached process from memory via the Application Manager to reset to a cold start state, and then repeat again starting at Step A.

The detailed steps performed during this process are listed below:

  1. Install the SiriRestClientUI from the APK (i.e., not installed via Eclipse deploy process). No obfuscation is used in the current app version.
  2. Connect your device to computer with Android DDMS running so you can view Logcat output.
  3. Start the app
  4. Make sure in "Settings->Cache Jackson Objects" is set to false, and that "Number of consecutive requests" is set to 1.
  5. Browse to the "Stop_Request" tab in the app.
  6. Use the following parameters, and then press the "Submit" button:
  • key=add-your-key-here
  • OperatorRef=MTA
  • MonitoringRef=308214
  • StopMonitoringDetailLevel=normal
  • MaximumNumberOfCallsOnwards=1
  1. Check the LogCat output. You should see this "Elapsed Time" result at the end of the test. You can just copy/paste this into Excel file as the "Cold start time".
  2. Set "Settings->Cache Jackson Objects" is set to true, and press the "Submit" button again. Check the LogCat output. You should see a message Wrote ObjectReader.cache to cache (226526 bytes) in 2,924.493 ms. Record the time value as the "Time to write cache", and the number of bytes as the "Size of Cache."
  3. Exit the app (i.e., press the "Back" button), and go to the main phone 'Settings->Application Manager' section. Here, there are typically at least two lists of apps/processes: "Running", and "Cached". For example, to access the "Cached" list on the Samsung Galaxy S3, you need to click on the "Show cached processes" button in the header of the "Running" application list. Then, tap on "Siri Rest Client" in the list of cached processes, and then tap on "Stop" to remove it from the cached process list. Hit the "Back" button and wait for the Siri Rest Client" to be removed from the "Cached Process List"
  4. Start up the app again, and immediately look at the LogCat output. The Siri Rest Client should immediately read the cached object on app startup, and you should see a message Read ObjectReader.cache from cache (226526 bytes) in 3,505.692 ms. Record the time value as the "Time to read cache", and the number of bytes should match the previous cache write message.
  5. Repeat Steps #5 and #6 to make another request to the server, which will create a pseudo-warm start request using the cached Jackson object. Then, check the LogCat output. You should see this "Elapsed Time" result at the end of the test. You can just copy/paste this into Excel file as the "Elapsed Response Time (Using Cached Object)".
  6. After a few seconds delay, you should also see another cache write message, where the most recent Jackson object is being cached again. Compare the size of bytes of this cache write with the size recorded in Step #8. If the sizes are different, the contents of the SIRI response may have changed. Record this observation and new byte size in the "Notes" field of the spreadsheet.
  7. The spreadsheet will automatically calculate the "Total Pseudo-Warm Start Time" (based on the "Time to read cache" + the "Elapsed Response Time (Using Cached Object)" values), as well as the difference between the "Total Pseudo-Warm Start Time" and the cold start time in both milliseconds and percent difference ((Cold-PseudoWarm)/Cold).
  8. To reset for the next round of tests, perform Step #4 (Turning off caching) and then Step #9 (clearing the cached process from memory). Then, start the process over again by beginning at Step #3.

Results

XML - Cold vs. Pseudo-warm starts

First, we will look at the performance of cold vs. pseudo-warm starts when using XML to format the server response. Figure 4 shows the elapsed time of 30 cold and pseudo-warm start tests, and Figure 5 shows the summary of the results from these tests.

Figure 4 - Cold vs. Pseudo-Warm Start performance for XML responses from 30 requests

Figure 5 - Cold vs. Pseudo-Warm Start performance for XML responses - Summary

Because of the large cold start penalties, we are able to substantially improve the performance of XML parsing via pseudo-warm starts and caching. Cold starts had an average elapsed time of 17.7 seconds, and warm starts had an average of only 9.7 seconds, an 8 second improvement. Overall, pseudo-warm starts thereby yield an average of a 44% performance increase over cold starts, a dramatic improvement.

JSON - Cold vs. Pseudo-warm starts

Next, we will look at the performance of cold vs. pseudo-warm starts when using JSON to format the server response. Figure 7 shows the elapsed time of 30 cold and pseudo-warm start tests, and Figure 8 shows the summary of the results from these tests.

Figure 7 - Cold vs. Pseudo-Warm Start performance for JSON responses from 30 requests

Figure 8 - Cold vs. Pseudo-Warm Start performance for JSON responses - Summary Results

Pseudo-warm starts perform slightly better than cold starts, with an average elapsed time of 3,785ms vs. the cold start average of 3,963ms - a difference of 178ms on average, which may still be noticeable to the user, but is not nearly as dramatic as the improvement of the XML pseudo-warm start.

Overall, for JSON the pseudo-warm start amounted to an average 3.96% performance increase over the cold start.

Discussion

The dramatic improvement in XML parsing performance using pseudo-warm starts indicates that the time required to read a cached Jackson object from mobile device persistent memory is far less than the time required to newly instantiate that same object. Therefore, a huge 44% performance increase on average can be produced by using pseudo-warm starts.

JSON pseudo-warm start performance improvements (3.96% on average), however, are not nearly as impressive as their XML counterparts. This difference is partially due to the fact that XML cold starts are significantly larger than JSON cold starts to begin with (by a factor of 4), which gives the XML pseudo-warm start a much greater margin of potential improvement.

After reviewing these results, one may think that a pseudo-warm start implementation for JSON parsing isn't worth the effort. However, we haven't yet discussed a significant advantage of pseudo-warm starts over cold starts - the potential to hide part of the delay from the user by beginning the cache read when the app is first started.

Figure 9 shows how user interactions occur in context of A) cold starts compared with B) pseudo-warm starts.

JacksonObjectCachingDiagram-WithUserInteractions

Figure 9 - With A) cold starts, the user always observes the fully overhead delay, but with B) pseudo-warm starts the overhead delay can be hidden from the user

As mentioned earlier, the cache read used in pseudo-warm starts can be initiated immediately upon application start up and can execute in the background while the user is browsing within the application. Therefore, using pseudo-warm starts, a considerable amount of the overhead time may pass before the user actually triggers a request to the server (e.g., for real-time arrival data). In the best-case scenario, shown in Figure 9B i, the entire cache read finishes prior to the user initiating a request, and the user does not observe any delay. In this case, pseudo-warm starts are equivalent to warm starts in performance. An alternate pseudo-warm start scenario is shown in Figure 9B ii. Here, the user performs a few UI actions while the cache read starts, but initiates the request to the server before the cache read can complete. In this situation, the user would observe a partial delay, depending on how much time has elapsed and how long the cache read will take to complete. Cold starts, on the other hand, cannot hide any of this overhead wait time from the user - Jackson initialization must always start when the user initiates a server request - Figure 9A.

Figure 10 - If user interactions with the app hide the cache read latency, JSON pseudo-warm starts perform significantly better than cold starts

***Figure 11 - XML pseudo-warm start performance increases are even more significant if the cache read time can be hidden from the user***

Conclusions

TODO - polish this up

In general, JSON is a preferred data transfer format over XML on mobile devices. Average performance with warm starts is better. Creating pseudo-warm starts by caching Jackson objects typically results in faster responses than cold starts, even when including full cache read time. Even when pseudo-warm starts are slower than cold starts (when including both cache read time and elapsed response time), the user experience can be improved since often the cache read times can be hidden from the user via multithreading by performing the cache read on application startup in parallel with user interactions with the application. Therefore, by the time the user requests information on arrival times, the cache read is complete and the user only experiences the pseudo-warm start elapsed response time delay, which is much faster than the cold-start response time delay.

Acknowledgements

A big thanks to Tatu Saloranta from FasterXML, LLC for his work on various Jackson issues, as well as implementing the ability to (de)serialize Jackson objects, which made much of this work possible. The research described in this paper was funded by the National Center for Transit Research.