Flashlight User Guide

How to use and configure the Flashlight Eclipse client

The authors and publishers have taken care in the preparation of this documentation, but make no expressed or implied warranty of any kind and assume no responsibility for errors and omissions. No liability is assumed for incidental or consequential damages in connection with or arising out of the use of the information or programs herein.

Version 5.7.1—November 2015


Table of Contents

Preface
1. Audience
2. Contact information
1. Getting started
1.1. Introduction
1.2. Quick start: How to instrument your code and query Flashlight
1.3. Tutorials
1.3.1. Finding a thread-confinement problem in the PlanetBaron ChatTestClient with API specific analyses
1.3.2. Finding a race condition in the PlanetBaron server with lock set analysis
1.3.3. Finding a potential deadlock in the PlanetBaron player user interface with lock cycle detection
1.3.4. Scanning code using Ant
1.3.5. Finding a potential deadlock in a Java implementation of the Dining Philosophers problem
1.3.6. Finding a race condition in an Android application (Android only)
1.3.7. Using the Query Editor (Advanced)
2. Reference
2.1. The Flashlight menu
2.2. The Flashlight perspective
2.2.1. Switching to the Perspective
2.2.2. The Flashlight Runs view
2.2.3. The Query Menu view
2.2.4. The Query Results view
2.2.5. The Query Results Explorer view
2.2.6. The Querydoc view
2.2.7. The Historical Source Snapshot view
2.2.8. The Launched Run Control dialog
2.3. License management
2.4. Preferences
2.5. Flashlight launch configuration
2.5.1. Instrumentation
2.5.2. Data collection
2.5.3. Methods
2.5.4. Fields
2.6. Indirect access methods
2.6.1. Default list of indirect access methods
2.6.2. File format
2.7. Troubleshooting
2.8. Inference of Promise annotations
2.9. The Flashlight data directory
2.9.1. Per-run directories
2.9.2. Deleting Flashlight data
2.10. Queries
2.10.1. Identifiers
2.11. Using Flashlight with Android
2.11.1. Running Flashlight
2.11.2. Stopping Flashlight
2.11.3. Launching Packaged Android Applications (APK)
2.12. Using Ant
2.12.1. flashlight-instrument-archive task
2.13. Using Maven
2.14. Bugs and tips
3. Release notes
3.1. Flashlight version 5.6.0
3.1.1. New and Noteworthy
3.2. Flashlight version 5.5.0
3.2.1. New and Noteworthy
3.3. Flashlight version 5.4.0
3.3.1. New and Noteworthy
3.4. Flashlight version 5.1.0
3.4.1. New and Noteworthy
3.5. Flashlight version 5.0.0
3.5.1. New and Noteworthy
Bibliography

List of Figures

1.1. The menu option to install a license for Flashlight
1.2. The SureLogic license management dialog
1.3. Launching an instrumented Java program from the Flashlight menu
1.4. Launching an instrumented Java program from the Eclipse quick launch toolbar
1.5. Launching an instrumented Java program from the file context menu
1.6. Dialog that shows the state of all running Flashlight-instrumented applications
1.7. Showing the progress of collected data preparation for querying by the user
1.8. Dialog asking to change Eclipse to the Flashlight perspective
1.9. The Flashlight perspective
1.10. The Flashlight perspective
1.11. Menu item to install tutorial projects into your workspace
1.12. Adding the tutorial projects to your workspace
1.13. The PlanetBaron PlayerUI for Laurel
1.14. Using the ChatTestClient to shutdown the game server
1.15. Launching ChatTestClient with Flashlight instrumentation
1.16. Running ChatTestClient with Flashlight instrumentation monitoring in the Flashlight Launched Run Control dialog
1.17. Data preparation progress being monitored in the Flashlight Launched Run Control dialog
1.18. Prompting the user to switch to the Flashlight perspective
1.19. The Flashlight perspective
1.20. Mutable fields read by the AWT/Swing Event Dispatch Thread (EDT) and written in others
1.21. The API query where the "bad news" item originated in the Query Menu view
1.22. Fields accessed outside the Event Dispatch Thread in a ChatTestClient run
1.23. Drill-in queries that can be run on the f_connectDisconnectButton field
1.24. A ChatTestClient object containing the f_connectDisconnectButton field.
1.25. When and by what threads is the f_connectDisconnectButton field accessed?
1.26. The Query Results Explorer shows queries that have been run and their structure
1.27. Running a second top-level query on ChatTestClient
1.28. Looking at the accesses made to the f_connectDisconnectButton field
1.29. Drilling in to see the stack trace for this field access and a broken line of code
1.30. News about our new run of ChatTestClient
1.31. The broken line of code in ChatTestClient is remembered by the Historical Source Snapshot view
1.32. Deleting two Flashlight runs
1.33. Running Server with Flashlight instrumentation
1.34. The Launched Run Control dialog shows that data is being collected during our run of the PlanetBaron server
1.35. Running a PlayerUI without Flashlight instrumentation
1.36. Running three players at once on an instrumented server
1.37. The Flashlight perspective showing news about our PlanetBaron server run
1.38. Some shared fields are not protected by a common lock according to the Flashlight lock set analysis
1.39. An empty lock set in PlanetBaron
1.40. The default query in a context menu is marked with a The default query in a context menu is marked with a and can be invoked with a double-click and can be invoked with a double-click
1.41. All the locks observed to protect access to the state of a Ship instance
1.42. The offending line of code
1.43. Preparing data from a instrumented PlayerUI run for querying
1.44. Deadlock results about the PlayerUI in both the query menu and the bad news table
1.45. Lock cycles observed in our PlayerUI run
1.46. A potential deadlock in com.surelogic.planetbaron.client.PlayerUI
1.47. Code location where the ReentrantReadWriteLock-51 -> Object-42 lock edge occurs
1.48. Running a query to see the stack trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred
1.49. Stack trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred
1.50. Running a query to see the lock trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred
1.51. Lock trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred
1.52. First lock acquisition in this edge occurs in endCurrentTurn in the GameMap class
1.53. Second lock acquisition in this edge occurs in the endOfTurn callback in the MapView class
1.54. Directly selecting the What are the lock edges for this lock cycle? result in the Query Results Explorer view re-displays that queries result
1.55. Code location where the Object-42 -> ReentrantReadWriteLock-51 lock edge occurs
1.56. Stack trace of how the Object-42 -> ReentrantReadWriteLock-51 lock edge occurred
1.57. Lock trace of how the Object-42 -> ReentrantReadWriteLock-51 lock edge occurred
1.58. The last lock acquisition in this edge occurs in the getPlanetAt "getter" method in the GameMap class
1.59. Where the call to the getPlanetAt "getter" method occurs during this edge
1.60. The scan in the PlayerUI shows information about the planet the mouse is hovering over
1.61. A "self" lock cycle in the PlayerUI where a single lock is used as both an intrinsic and dynamic lock
1.62. Lock objects in the PlayerUI that were observed to be used as both a dynamic lock and an intrinsic lock
1.63. News item that lock objects in the PlayerUI that were observed to be used as both a dynamic lock and an intrinsic lock
1.64. Console output from scanning PlanetBaron with Ant inside Eclipse
1.65. Successful scan import
1.66. Launching Counter Race
1.67. The Counter Race application
1.68. Tap the checkbox to start and stop the counters
1.69. Terminating data collection for FlashlightTutorial_CounterRace using the Flashlight Launched Run Control dialog
1.70. Potential Race Conditions in Counter Race
1.71. Looking at f_sharedCounter
1.72. No locks acquired when f_sharedCounter was accessed
1.73. What threads read and write f_sharedCounter?
1.74. Looking at f_threadLocalCounts
1.75. Four instances of f_threadLocalCounts
1.76. What threads read and write f_threadLocalCounts
1.77. When and by what threads was f_threadLocalCounts accessed?
1.78. The happens before edges from the main thread to write of f_threadLocalCounts by the main thread.
1.79. What is the stack trace for this edge's source?
1.80. Initialization of f_threadLocalCounts in CounterRaceActivity
1.81. The happens before edge to main from the counter thread
1.82. What is the stack trace for this edge's source?
1.83. Access of f_threadLocalCounts by the main thread after Thread-4574 has ended
1.84. What fields (non-static) are shared?
1.85. Result of running What fields (non-static) are shared?
1.86. Creating our new query
1.87. Adding a new sub-query to What fields (non-static) are shared?
1.88. The sub-queries of What fields (non-static) are shared?
1.89. Exporting the results of What methods directly access this field?
1.90. Importing the results of What methods directly access this field?
2.1. The Flashlight menu
2.2. The Flashlight Runs view
2.3. The Flashlight Runs view toolbar
2.4. The Flashlight Runs view menu
2.5. The Flashlight Runs view context menu
2.6. The Query Menu view
2.7. The Query Menu view toolbar
2.8. The Query Menu view menu
2.9. The Query Menu view context menu
2.10. The Query Results view showing good and bad news about a run
2.11. The Query Results view showing query results and allowing sub-queries on a selected row
2.12. The Query Results view toolbar
2.13. The Query Results view menu
2.14. The Query Results view context menu lists "drill-in" queries that can be run on a selected row
2.15. The Query Results Explorer view showing the tree of queries the tool user has run
2.16. The Query Results Explorer view toolbar
2.17. The Query Results Explorer view menu
2.18. The Querydoc view showing Javadoc-like information about a Flashlight query
2.19. The Historical Source Snapshot view showing the field access selected in the Query Results view
2.20. The SureLogic license management dialog
2.21. Dialog warning that the installed Flashlight license is about to expire
2.22. The Flashlight preference page
2.23. The Flashlight launch configuration Instrumentation pane.
2.24. The Class Selection Dialog
2.25. The Data Collection Pane
2.26. The Methods Pane
2.27. The Fields Pane when Instrument all field accesses is selected
2.28. The Fields Pane when Instrument all field accesses is not selected
2.29. Infer JSure Annotations
2.30. Infer JSure Annotations
2.31. Configure the application's permissions
2.32. Launch Flashlight from the Flashlight As menu
2.33. Create and manage a run configuration from the Flashlight Configuration View
2.34. Terminating data collection the Flashlight Launched Run Control dialog
2.35. Terminating the application from the Application Monitor
2.36. Terminating Flashlight Instrumentation from the Runtime Console
2.37. Launching a packaged Android application (binary APK) from the Flashlight main menu
2.38. Menu items to send bugs and tips to SureLogic
2.39. Dialog allowing the user to enter a tip to improve Flashlight
2.40. Dialog allowing the user to enter a problem report about Flashlight
2.41. Eclipse preferences for network connections within the IDE

Preface

1. Audience

This document is intended for Java developers who want to use the Flashlight tool within the Eclipse Java IDE. We assume that the reader understands both the Java programming language and the use of Eclipse for Java development.

2. Contact information

For technical support or other questions, please contact:

5808 Forbes Avenue, Pittsburgh, PA 15217-1602

Chapter 1. Getting started

1.1. Introduction

What is Flashlight? Flashlight is a dynamic analysis tool that helps you to understand the concurrency within your Java software. It is similar to a profiler in the sense that it collects data from a program execution and presents information about that run to the tool user. Flashlight casts light on issues related to performance, concurrency, and code safety. The Flashlight dynamic analysis tool is designed so that even one run can reveal information regarding a relatively much larger universe of runs, and thus enable developers to address potential issues earlier. The tool is also designed to afford developers and evaluators a visibility that enables them to develop models to support a "more complete" analysis by a sound static analysis tool like SureLogic's JSure.

At a more technical level, Flashlight is designed to scale to very large amounts of collected instrumentation data. It accomplishes this through a unique pipeline/buffering approach that rapidly moves data out of the instrumented program's process heap and into secondary storage. It is designed to interact cleanly with garbage collection and object finalization.

Flashlight use imposes an overhead cost, in terms of time and memory, on your running program. Flashlight is a much more invasive analysis than a typical Java profiler. Roughly, an instrumented program will require two to three times the memory it normally uses and will run from 20 times to 80 times slower than it normally runs. A dual- or quad-core CPU is recommend to reduce the overhead Flashlight imposes on the instrumented program because Flashlight is able to take advantage of the available hardware. Flashlight uses a large amount of disk space to store the data it collects, thus 50 to 100 Gigabytes of free disk space is recommended.

Flashlight has a highly effective query capability, wherein the database of program run data is queried using a hierarchy of queries that enable the results of one query to be used as a basis for "drill in" using sub-queries.

1.2. Quick start: How to instrument your code and query Flashlight

This section assumes that you have installed Flashlight. If you see a Flashlight menu item on your Eclipse main menu then you can assume Flashlight has been properly installed.

You need to install a license to use Flashlight. If you do not have a license file visit http://surelogic.com to obtain one. To install the license select Manage SureLogic Licenses from the Flashlight menu as shown in Figure 1.1.

Figure 1.1. The menu option to install a license for Flashlight

The menu option to install a license for Flashlight

This will cause the Manage SureLogic Licenses to appear as shown in Figure 1.2. Highlight the Flashlight row and select the Install License button to install your license file.

Figure 1.2. The SureLogic license management dialog

The SureLogic license management dialog

Flashlight will not disrupt your Eclipse installation if a license for it is not installed, however, it will not allow you to use Flashlight functionality. We will assume from this point on that you have installed your license.

Flashlight is a dynamic analysis tool which means that you have to run your program to use it. Flashlight instruments your program when it starts up and uses that instrumentation to collect data about your program. By default, data resides in your workspace under a directory named .flashlight-data.

To run your program with Flashlight instrumentation is similar to launching it normally in the Eclipse IDE. There are three ways to do this which we illustrate below using the ChatTestClient Java program (from a tutorial).

  • Using the Flashlight menu as shown in Figure 1.3.

  • Using the Flashlight quick launch icon in the Eclipse toolbar as shown in Figure 1.4.

  • Using the context menu of a launchable Java file as shown in Figure 1.5.

Figure 1.3. Launching an instrumented Java program from the Flashlight menu

Launching an instrumented Java program from the Flashlight menu

Figure 1.4. Launching an instrumented Java program from the Eclipse quick launch toolbar

Launching an instrumented Java program from the Eclipse quick launch toolbar

Figure 1.5. Launching an instrumented Java program from the file context menu

Launching an instrumented Java program from the file context menu

To obtain useful information about your program from the tool you should exercise it in a realistic manner. Typically, long program runs are not required, however simply running unit test code or isolated cases can create poor data. Try to run you program in a manner were its concurrency is exercised to the fullest extent possible.

When your program launches the Flashlight Launched Run Control Dialog appears. An example of this dialog is shown in Figure 1.6. Each running Flashlight-instrumented program gets a listing in this dialog—it can be though of as being similar to a web browser download monitor dialog. This dialog is fully described in Section 2.2.8

Figure 1.6. Dialog that shows the state of all running Flashlight-instrumented applications

Dialog that shows the state of all running Flashlight-instrumented applications

It is possible to stop data collection and disconnect Flashlight from the running application by pressing the icon to the far right of each dialog entry. When the application completes or Flashlight is disconnected from the running application. The collected data is prepared for querying by the tool. Data preparation may take some time and its progress is reported in the Flashlight Launched Run Control Dialog as shown in Figure 1.7.

Figure 1.7. Showing the progress of collected data preparation for querying by the user

Showing the progress of collected data preparation for querying by the user

When data is prepared querying is done in a special Eclipse perspective called the Flashlight perspective. If data preparation of any run completes and Eclipse is not currently in the Flashlight perspective. The tool prompts the user to change to this perspective. This prompt is shown in Figure 1.8.

Figure 1.8. Dialog asking to change Eclipse to the Flashlight perspective

Dialog asking to change Eclipse to the Flashlight perspective

When you open the Flashlight perspective in Eclipse it will look similar to Figure 1.9. The views in this perspective are described fully in Section 2.2 but the purpose and use of each view is sketched below.

Figure 1.9. The Flashlight perspective

The Flashlight perspective

The Flashlight Runs view (upper-left in the above image) lists all the instrumented program runs you have done using Flashlight. This view lists executions of programs, so a single program may be listed several times. Each run includes the name of the program and the time of the run. Runs of Android applications are listed with a icon. In the image above FlashlightTutorial_CounterRace is an Android application that has been run on a Nexus 4 phone. Standard Java applications, both desktop and server-side, are listed with a icon. In the image above ChatTestClient is a Java desktop (Swing) application.

The Query Results view (middle-right in the above image) shows either (a) an overview of the run currently selected in the Flashlight Runs view or (b) query results as a table, tree or tree-table. The image above shows the run overview. This lists good and bad news about the selected run. These news items are not definitive, because they represent information from a single run of the program—hence the name news instead of results. Some news items are underlined. These underlined news items may be selected with the mouse to invoke a query and show the news item's corresponding results. Some news items are not underlined because they indicate that no information was observed during the run—in these cases no results indicates something newsworthy. These items that are not underlined have no associated results.

When results are shown in the Query Results view you can select a row and "drill-in" to a particular row of the result that is of interest. Hence, you can run queries based upon the results of previous queries. This "drill-in" tree of queries is tracked in the Query Results Explorer view (upper-right in the above image). You can move up and down within a particular "drill-in" tree of query results by using the forward and back arrows in the toolbar of both results views or by selecting a particular result in the Query Results Explorer view. To run a "drill-in" query you bring up the context menu for the selected result in the Query Results view (for example, using a right-click of the mouse) or double-click that query in the Query Menu view.

The Query Menu view (middle-left in the above image) lists the queries that you can run. At the top level these queries are categorized to help you determine what results are of interest to you. These categories can be seen in the image above. If you have selected a particular result then the Query Menu view lists the possible "drill-in" queries, which we also call sub-queries, you can invoke.

The Java editor is shown in the Flashlight perspective to the lower-left. This view will highlight lines of code when results that link to code are selected in the Query Results view. In addition to the Java editor a Historical Source Snapshot view exists to the lower-right that will highlight selected lines of code. This view shows the code as it existed when the instrumented program run was made. This helps to avoid user confusion if the program's source code has been modified.

The final view in the perspective is the Querydoc this view shows detailed reference documentation about a particular query. This view can help explain the benefits and limitations of each query that Flashlight supports.

To conclude this section we remind you that Flashlight is focused on helping improve the performance and safety of concurrent Android and Java programs. But what happens if you run a program that is not concurrent? You will get a big red bar in the overview warning you that no shared data was observed during the program run. This is shown for the traditional Java "Hello, world!" program in Figure 1.10.

Figure 1.10. The Flashlight perspective

The Flashlight perspective

If you get a No Shared Data Warning you should try to exercise the concurrent portions of your program more fully. Also you may need to change what libraries are instrumented during your program run which is discussed in Section 2.4. Finally, it could be the case that your code is not concurrent.

1.3. Tutorials

This section contains a series of Flashlight tutorials.

  • PlanetBaron – Investigating a client-server real-time strategy game that has some concurrency problems we'll use Flashlight to uncover and fix. This tutorial is presented in Section 1.3.1 (a GUI thread-confinement bug), Section 1.3.2 (a race condition), and Section 1.3.3 (a potential deadlock).

  • Dining Philosophers – Using Flashlight to investigate a Java implementation of the classic dining philosophers problem that may deadlock. This tutorial is presented in Section 1.3.5.

  • (Android Only) Counter Race – Fixing a troubled implementation of a concurrent counting Android application. This tutorial focuses on how to launch and collect data from Android applications using Flashlight. If you do not have the Android Developer Tools (ADT) installed in your Eclipse as well as the Android plug-ins for Flashlight then this tutorial cannot be loaded and run. This tutorial is presented in Section 1.3.6.

  • (Advanced/Optional) Using the Flashlight query editor – This is an advanced tutorial that shows how to change queries in the Flashlight tool. This tutorial is presented in Section 1.3.7.

It is recommended that you go through these tutorials in order. It is also recommended that these tutorials be performed "hands-on" at your computer. You might want to create a new Eclipse workspace to use for these tutorials. In addition, if you run into any difficulties as you step through the tutorials please consider sending us a tip for improvement as described in Section 2.14.

Figure 1.11. Menu item to install tutorial projects into your workspace

Menu item to install tutorial projects into your workspace

These tutorials assume that you have installed Flashlight. If you see a Flashlight menu item on your Eclipse main menu than you can assume it has been installed properly. To follow along with the tutorials you will also need to add the tutorial projects to your workspace. From the Eclipse main menu, choose FlashlightRun Flashlight Tutorials and add all the listed projects) to your workspace as displayed in Figure 1.11 and Figure 1.12. All the projects should be checked when you open the dialog.

Figure 1.12. Adding the tutorial projects to your workspace

Adding the tutorial projects to your workspace

[Note]FlashlightTutorial_CounterRace is an Android application

The FlashlightTutorial_CounterRace project requires that both the Android Developer Tools (ADT) and the Android plug-ins for Flashlight be installed in your Eclipse. If they are not this project will not appear in Figure 1.12. If you do not use Android missing this project is no problem. Simply skip that portion of the tutorial.

[Note]FlashlightTutorial_DiningPhilosophersJava8 is a Java 8 only application

The FlashlightTutorial_DiningPhilosophersJava8 project requires Java 8. If your Eclipse and your JDK support Java 8 you can load this project and use it for the tutorial presented in Section 1.3.5. If you do not yet develop Java 8 code then the FlashlightTutorial_DiningPhilosophers project is the one to select. You do not need both projects, simply uncheck the one you don't need, but can load both if you are using Java 8.

1.3.1. Finding a thread-confinement problem in the PlanetBaron ChatTestClient with API specific analyses

PlanetBaron is a network-based real-time strategy game. It contains three programs that we will run during this tutorial. The first is a server program that manages the distributed game state. The second is a graphical program that allows a player to interact with the game. The third program, called the chat-test client, allows direct interaction with the server for the purpose of debugging and management. For example, the chat-test client is used to shutdown a server.

Flashlight is a dynamic analysis tool. To get any useful results from Flashlight we have to collect data while a program is running. We will start below by describing how to run and play a PlanetBaron game. After we understand a bit about how to run the game we will return to using Flashlight to analyze it.

Let's run a PlanetBaron game. Select Server.java in the com.surelogic.planetbaron.server package. Right-click and select Run AsJava Application. You should see following output in the console which indicates that the server has started successfully:

    [INFO "server-main"] PlanetBaron game server listening for clients on port 8693 and playing on a 15x15 map
  

Now we need to add some players. Select PlayerUI.java in the com.surelogic.planetbaron.client package. Right-click and select Run AsJava Application. You will see a Window appear has a blank grid and the title PlanetBaron. In the lower right-hand-corner enter a player name, Laurel, and press Connect.

The screen will change to contain several planets and one ship with "Laurel" as its label. By moving your mouse around the grid you can direct your ship. Place your mouse over a planet and left-click. This action will cause your ship to move slowly to that planet. When your ship arrives you will become the owner of that planet. This is called "taking ownership" of a planet. Go ahead an take ownership of a few planets. Note that while your ship is moving you are not allowed to change its destination. Once it arrives at the destination you selected you can then select a subsequent destination.

If you look at the console for the server you will see the commands that have come in from the Laurel PlayerUI. For example, your server console might look similar to the below:

    [INFO "server-main"] PlanetBaron game server listening for clients on port 8693 and playing on a 15x15 map [com.surelogic.planetbaron.server.Server.startListening()]
    [INFO "server-ch10"] client handler thread started [com.surelogic.planetbaron.server.ClientHandler.run()]
    [INFO "server-ch10 (Laurel)"] "play "Laurel"" processed GameStateUpdate from ch10 (Laurel) [com.surelogic.planetbaron.server.ClientHandler.run()]
    [INFO "server-ch10 (Laurel)"] "moveship "Laurel" to (12,11)" processed Ok from ch10 (Laurel) [com.surelogic.planetbaron.server.ClientHandler.run()]
    [INFO "server-ch10 (Laurel)"] "moveship "Laurel" to (9,13)" processed Ok from ch10 (Laurel) [com.surelogic.planetbaron.server.ClientHandler.run()]
    [INFO "server-ch10 (Laurel)"] "moveship "Laurel" to (8,10)" processed Ok from ch10 (Laurel) [com.surelogic.planetbaron.server.ClientHandler.run()]
  

Now, go back to Eclipse and start a second instance of PlayerUI.java. In the lower right-hand-corner enter a player name, Hardy, and press Connect.

The game supports as many players as you choose to connect to the server. Notice that the planets that Laurel owns are red in the Hardy PlayerUI while they are white in the Laurel PlayerUI. Moving back and forth between the two PlayerUIs move the ships to play the game. Note that the idea of the game is to own as many planets as you can. A game screenshot is shown in Figure 1.13.

Figure 1.13. The PlanetBaron PlayerUI for Laurel

The PlanetBaron PlayerUI for Laurel

To finish the game press Disconnect in both PlayerUI instances and then terminate the programs by closing the application windows as usual. This action ends both player user interfaces but the server is still running. To terminate the server we need to use the chat-test client program. Select ChatTestClient.java in the com.surelogic.planetbaron.client package. Right-click and select Run AsJava Application. You will see a window appear with the title ChatTest - PlanetBaron. This program allows you to directly control the game server via text commands. We want to use it to shutdown the game server. To do this press Connect to connect to the game server and enter shutdown as the command. Your screen should now look like the one shown in Figure 1.14.

Figure 1.14. Using the ChatTestClient to shutdown the game server

Using the ChatTestClient to shutdown the game server

Press Send to shutdown the server. A dialog will appear stating that the server has disconnected from the ChatTestClient that you may dismiss. You can now terminate the ChatTestClient by closing the application window. Back in the Eclipse console for the server you should see the following message at the bottom:

    [INFO "server-main"] PlanetBaron game server shutdown complete
  

We are now ready to use Flashlight to help us understand the concurrency in the PlanetBaron game. Let's start with the ChatTestClient. To run the ChatTestClient with Flashlight instrumentation we select it from the Flashlight launch tab in the Eclipse toolbar as shown in Figure 1.15.

Figure 1.15. Launching ChatTestClient with Flashlight instrumentation

Launching ChatTestClient with Flashlight instrumentation

Two windows will appear on your screen. First, the Flashlight Launched Run Control dialog (to the right in Figure 1.16) will appear to monitor the instrumented program run. This dialog automatically appears when an instrumented program is launched in Eclipse. It tracks the program run from launch, execution, termination, and data preparation. It can be though of as being similar to a web browser download monitor dialog.

Figure 1.16. Running ChatTestClient with Flashlight instrumentation monitoring in the Flashlight Launched Run Control dialog

Running ChatTestClient with Flashlight instrumentation monitoring in the Flashlight Launched Run Control dialog

Second, the ChatTestClient window will appear on your screen (to the left in Figure 1.16). Click the Connect button in the ChatTestClient window to try and connect to a game server. This will fail and the application will show a dialog to you which you may dismiss. The reason it fails is that we did not start a game server. At this point we have exercised the ChatTestClient enough to see some Flashlight results. Go ahead and close the ChatTestClient application window (on Windows use the red-X to the upper-right, or the equivalent functionality on your operating system) to terminate the program. After a few seconds, Flashlight will note that the instrumented ChatTestClient application has finished running and begin data preparation. Data preparation gets the collected run data ready for you to query. The Flashlight Launched Run Control dialog monitors the progress of data preparation as shown in Figure 1.17.

Figure 1.17. Data preparation progress being monitored in the Flashlight Launched Run Control dialog

Data preparation progress being monitored in the Flashlight Launched Run Control dialog

When data preparation is completed the tool will prompt you to switch to the Flashlight perspective as shown in Figure 1.18.

Figure 1.18. Prompting the user to switch to the Flashlight perspective

Prompting the user to switch to the Flashlight perspective

Press Yes and the Flashlight perspective will appear as shown in Figure 1.19. At this point you can dismiss the Flashlight Launched Run Control dialog or leave it up. The Flashlight Run Control dialog can be brought up at any time by selecting FlashlightLaunched Run Control... from the Eclipse main menu.

Figure 1.19. The Flashlight perspective

The Flashlight perspective

The Flashlight perspective is used to manage and query data collected from instrumented programs. The Flashlight Runs view in the upper-left manages the instrumented runs of programs. This view allows you to prepare data to be queried, select a prepared run for querying, and delete runs from the disk.

The Query Results view is showing an overview of our ChatTestClient run which is currently selected in the Flashlight Runs view. The overview lists good and bad news about the selected run. These news items are not definitive, because they represent information from a single run of the program—hence the name news instead of results. Some news items are underlined. These underlined news items may be selected with the mouse to invoke a query and show the news item's corresponding results. Some news items are not underlined because they indicate that no information was observed during the run—in these cases no results indicates something newsworthy. These items that are not underlined have no associated results.

The "Bad News" reports a single item for this run. Let's examine this report to see if it is significant. Click on the underlined news item Fields read by the AWT Event Dispatch Thread were modified outside of it. You should see the Query Results view change to a result similar to the one shown in Figure 1.20. Your result may be slightly different because the data reflects what occurred in your particular run of the program. For example, the counts under the Reads and Writes column may be different than what is shown in Figure 1.20.

Figure 1.20. Mutable fields read by the AWT/Swing Event Dispatch Thread (EDT) and written in others

Mutable fields read by the AWT/Swing Event Dispatch Thread (EDT) and written in others

Clicking on this news item ran the query What mutable fields are read by the AWT Event Dispatch Thread and written in others? This query also appeared in the Query Menu view. But, it doesn't show this view right now because the view is now showing sub-queries that can be run on the query result we just brought up. When at the top level, however, the Query Menu view for this run is shown in Figure 1.21. This top level menu is where all the news items about a run come from. If a query is empty it can result in a good news report or bad news report. The same goes for a query with results, however, if a news item has results then the tool allows the query to be run directly from the news item. That is how we ran the What mutable fields are read by the AWT Event Dispatch Thread and written in others? query in this example.

Figure 1.21. The API query where the "bad news" item originated in the Query Menu view

The API query where the "bad news" item originated in the Query Menu view

Let's return our attention to the Query Results view. Selecting fields in the query result causes these fields to be highlighted in two views at the bottom of the Flashlight perspective. The view to the left is the normal Java editor and represents the current state of the source code. The view to the right is an Historical Source Snapshot view that shows you the code as it existed when the program was executed. This view helps you to understand if the code has evolved since the run you are querying was made. To see this, click on the row of the query result that lists information about the f_connectDisconnectButton field. You will see the two code views change to the field's f_connectDisconnectButton declaration as shown in Figure 1.22. In this example the code is exactly the same, which is what we would expect because we just made the run and haven't made any changes since that time.

Figure 1.22. Fields accessed outside the Event Dispatch Thread in a ChatTestClient run

Fields accessed outside the Event Dispatch Thread in a ChatTestClient run

Flashlight can do more than run a single query. It is designed to allow you to "drill-in" to understand the details about what occurred during a run. Select the f_connectDisconnectButton and right-click. This brings up a menu of queries that can be run on this result. In this case there is one as shown in Figure 1.23.

Figure 1.23. Drill-in queries that can be run on the f_connectDisconnectButton field

Drill-in queries that can be run on the f_connectDisconnectButton field

Select What instances contain this field when it is read by the AWT Event Dispatch Thread and written in others? You should see a table with a single entry, as in Figure 1.24. If any other ChatTestClient objects had been created and shared their f_connectDisconnectButton with more than one thread, we would see entries for them here as well. Note that while our object is called ChatTestClient-10, the number after the dash may be different for you. In general, the suffix of an object will be different from run to run, as it is randomly assigned at runtime when the object is instantiated.

Figure 1.24. A ChatTestClient object containing the f_connectDisconnectButton field.

A ChatTestClient object containing the f_connectDisconnectButton field.

Right click on the single row and select When and by what threads is this field accessed? The results should look something like Figure 1.25. In the case of f_connectDisconnectButton we see that the main thread and AWT-EventQueue-0, known as the event dispatch thread (EDT), shared this field. This result indicates, by the No in the Happens-Before column that the field is not safely passed from the first thread to the second. Flashlight can show whether or not a happens-before relationship exists between two threads in a run of an instrumented program. For example, whether a write of a volatile field in one thread and a subsequent read in a second thread created a happens-before edge between the two threads. These queries help the user better understand if the shared state in their Java program respects the details of the Java memory model — and is therefore able to obtain high performance with safety.

Figure 1.25. When and by what threads is the f_connectDisconnectButton field accessed?

When and by what threads is the f_connectDisconnectButton field accessed?

Before we continue our analysis of the problem with the shared f_connectDisconnectButton field let's learn to navigate query results in the user interface. Flashlight remembers all queries you run until you explicitly delete them. At this point you have run three queries—each a drill in of the previous. This structure can be seen to the upper-right of the Eclipse window in the Query Results Explorer view. That view should appear as shown in Figure 1.26.

Figure 1.26. The Query Results Explorer shows queries that have been run and their structure

The Query Results Explorer shows queries that have been run and their structure

Each entry lists the name of the query executed. To the right of the name the number of rows returned is listed. If the query is a top-level query on a run then the name of the run and the time it was launched is listed so that query trees made on multiple runs can be distinguished. The tree structure of this view reflects if one query was a "drill-in" result from another.

Click on the What instances contain this field when it is read by the AWT Event Dispatch Thread and written in others? result in the Query Results Explorer view. This causes the display of the Query Results view to change to show this queries results. You can click on any result in the Query Results Explorer view to see its results. In addition to directly clicking on a result you can use and icons in the toolbar of either the Query Results Explorer view or the Query Results view to "drill-back" or "drill-in" along a line of query results. Try this now.

You can also start a new line of queries about a run by going back to the root query menu for a run. There are two ways to do this. The first is to click on the run in the Flashlight Runs view. The second is to click the icon in the toolbar of the Query Menu view.

To try this out let's run another root query. Select the ChatTestClient run with the mouse in the Flashlight Runs view. This will change the Query Menu view back to the top level. Find the query What fields (static) are shared? (under the Shared State category) and double-click on this query to run it. You should get a result similar to the one shown in Figure 1.27.

Figure 1.27. Running a second top-level query on ChatTestClient

Running a second top-level query on ChatTestClient

Now we have two "lines of inquiry" about the ChatTestClient run. The query result about shared static state that a single static field tells us that only LOG was observed as being shared between two or more threads. We are now done with this line of inquiry about static state. To clear a single query result you press the in the toolbar of either the Query Results Explorer view or the Query Results view. To clear out all query results you press the in the toolbar of either the Query Results Explorer view or the Query Results view. But we only want to clear out a single result. So, now press the toolbar button to delete the query result about the LOG field. Next, to get us back to our original line of inquiry select the When and by what threads was this field accessed? result in the Query Results Explorer view.

We can get a better idea of when we are writing to f_connectDisconnectButton by drilling in and looking at each access that was made. Right click on the main entry, and run Show every access of this field in this time range. The result of this query should look like Figure 1.28 and will show you each read and write of the field that was observed by the instrumentation as the program executed. It shows the time at which the event occurred and the thread it happened within.

Figure 1.28. Looking at the accesses made to the f_connectDisconnectButton field

Looking at the accesses made to the f_connectDisconnectButton field

Now, select the second access by the main thread and right-click. Drill-in again by selecting What is the stack trace for this access?.

Figure 1.29. Drilling in to see the stack trace for this field access and a broken line of code

Drilling in to see the stack trace for this field access and a broken line of code

This will result in a stack trace for the selected access as shown in Figure 1.29. Selecting each row of the result will link to line of code in the ChatTestClient program. The bottom row is, in fact, a bug in the program. This line is shown in the figure above at line 52.

What is wrong? To understand this problem we quote from Haase and Guy's Filthy Rich Clients[1]:

Swing's threading model is based on a single rule: The EDT is responsible for executing any method that modifies a component's state. This includes any component's constructor. According to this rule, and despite what you can read in many books and tutorials about Swing, the main() method in the previous code example is invalid and can cause deadlock.

The concurrency policy that Swing uses is called 'thread confinement.' A thread confinement policy doesn't use any sort of explicit locking, but instead demands that all modifications made to the library's internal state happen in the same thread. Because Swing component constructors can and do make modifications to Swing's internal state, they must be created from the Swing Event Dispatch Thread (EDT). To fix this problem we need to call the ChatTestClient constructor from the EDT. We can do this by changing the main() method to look like the code below.


public static void main(String[] args) {
  // run the application
  SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
      new ChatTestClient();
    }
  });
}

  

Save this change and launch ChatTestClient using the Flashlight launch shortcut again. Perform the same actions that you did during the first run:

  1. Try to connect.
  2. Dismiss the dialog.
  3. Exit.

You can watch the progress of data preparation in the Flashlight Launched Run Control dialog. When data preparation is complete on the new ChatTestData run you can dismiss the Flashlight Launched Run Control dialog. The new ChatTestClient run will appear in the Flashlight Runs view.

Delete all our previous query results by clicking the in either the Query Results Explorer view or the Query Results view. This action clears out previous queries we have done.

Select the new ChatTestClient run in the Flashlight Runs and your workspace should look similar to the one shown in Figure 1.30.

Figure 1.30. News about our new run of ChatTestClient

News about our new run of ChatTestClient

Note that the bad news item is gone. This is a good sign that we have fixed the problem of keeping access to AWT/Swing object thread confined to the AWT Event Dispatch Thread. For ChatTestClient, this result indicates that no fields were observed being accessed in both the AWT Event Dispatch Thread and the main thread. This run provides some evidence that we have fixed the bug discovered in ChatTestClient. We carefully say some evidence, rather than proves, because a dynamic analysis tool does not investigate all possible executions of the ChatTestClient—it can only report on what it observed.

Before we move on let's examine the old run in the Flashlight Runs view one final time.Select the first ChatTestClient run and double-click the What fields are read by the AWT Event Dispatch Thread and written in others? query. Select f_connectDisconnectButton and right-click to select the What instance contain this field when it is read by the AWT Event Dispatch Thread and written in others? query. Select the single ChatTestClient object instance, right-click, and run the When and by what threads was this field accessed? query. Next select the main thread row, right-click, and run the Show every access of this field in this time range. query. Select the second access by the main thread and right-click to select the What is the stack trace? query. By selecting the bottom row of the stack trace you can see that, while the Java editor code might prove confusing, because we changed the code, the Historical Source Snapshot view remembers what the code looked like in this previous run. This difference is shown in Figure 1.31.

Figure 1.31. The broken line of code in ChatTestClient is remembered by the Historical Source Snapshot view

The broken line of code in ChatTestClient is remembered by the Historical Source Snapshot view

We are finished with our examination of these runs, so let's delete them. First, clear out all the queries we ran by pressing the icon in either the Query Results view or the Query Results Explorer view. Next, in the Flashlight Runs view select both runs and right-click to bring up the view's context menu. Select Delete from the context menu as shown in Figure 1.32.

Figure 1.32. Deleting two Flashlight runs

Deleting two Flashlight runs

You will be prompted to ensure that you really want to delete this Flashlight run data. Press OK. After a short delay the Flashlight Runs view should be empty. It is important to delete old runs to ensure that you free up disk space on your computer. As you can see in the first column of the figure above, two short runs of ChatTestClient used roughly 23 MB of disk space.

1.3.2. Finding a race condition in the PlanetBaron server with lock set analysis

ChatTestClient was a simple Swing application that let us get started analyzing a program's concurrent behavior with Flashlight. From this we uncovered a thread confinement bug that could easily be overlooked in a code inspection or even during testing. We now turn our attention to a more complex multi-threaded program, the PlanetBaron server, to illustrate several more complex queries that Flashlight is capable of. The basic user interaction with the Flashlight tool remains the same:

  1. Run an instrumented program.
  2. Prepare the data for querying.
  3. Query the data.
  4. Analyze and drill into the query results.
  5. Change/fix code.

Run a PlanetBaron server using the Flashlight launch tab the Eclipse toolbar as shown in Figure 1.33. We are assuming you ran the server and player applications earlier in the tutorial so that the Server and PlayerUI launch configurations will still be present in the Eclipse launch menus.

Figure 1.33. Running Server with Flashlight instrumentation

Running Server with Flashlight instrumentation

You will see that data collection being tracked in the Flashlight Launched Run Control dialog. This is shown in Figure 1.34.

Figure 1.34. The Launched Run Control dialog shows that data is being collected during our run of the PlanetBaron server

The Launched Run Control dialog shows that data is being collected during our run of the PlanetBaron server

Next start three PlayerUI instances. We don't want to instrument these programs, so use the normal launch tab as shown in Figure 1.35.

Figure 1.35. Running a PlayerUI without Flashlight instrumentation

Running a PlayerUI without Flashlight instrumentation

Go ahead and connect into the game as Laurel, Hardy, and Groucho. Exercise the game by having each player take several planets. Have one planet be owned by each player at one time. To do this click on the same planet in all three PlayerUI instances. This is shown in Figure 1.36.

Figure 1.36. Running three players at once on an instrumented server

Running three players at once on an instrumented server

When you have exercised the three players, terminate the three PlayerUI instances by closing the application windows. Run a ChatTestClient without instrumentation and use it to shutdown the server. Connect to the server and send a "shutdown" command.

In the Flashlight Launched Run Control dialog you can watch the progress as the tool prepares the data collected from the server for querying. This process will take a few minutes to complete. Once data preparation is completed you can switch to the Flashlight perspective and dismiss the Flashlight Launched Run Control dialog. The Flashlight perspective should look similar to Figure 1.37.

Figure 1.37. The Flashlight perspective showing news about our PlanetBaron server run

The Flashlight perspective showing news about our PlanetBaron server run

What you see Figure 1.37 may or may not be identical to what you see at your computer. The program we are examining is a multi-threaded network-based game server. Therefore, it is impossible to duplicate a run—even for tutorial purposes. You should, however, see results similar to what we present. If not, we suggest you try another run of the PlanetBaron server.

We'll use a couple of analyses performed by Flashlight during the prep phase to investigate the PlanetBaron server. The first of these is a lock set analysis. A lock set analysis examines each access of a field in the program and intersects the set of locks held. If shared state has a lock set it is a good thing—this state was observed to be protected consistently by at least one lock. This isn't a guarantee that this field will always be protected in every run of the program (to make this determination a sound verification tool like SureLogic JSure is required), but it was observed to be true for the particular run of the program being queried in Flashlight. If shared state has no lock set then this could be a problem—it may mean that your program contains a race condition.

This run has bad news about the results of Flashlight's lock analysis, click the Shared fields have no common lock held for each access in the bad news column as shown in Figure 1.38.

Figure 1.38. Some shared fields are not protected by a common lock according to the Flashlight lock set analysis

Some shared fields are not protected by a common lock according to the Flashlight lock set analysis

The bad news item we clicked on runs the What fields (non-static) have an empty lock set after object construction? query. The results of this query are shown in Figure 1.39. The lock set analysis ignores state accesses during object construction because, typically, Java objects are constructed in the context of a single thread and only later is a reference to the object shared. By ignoring construction the lock set the analysis is more precise and Flashlight has other queries that can detect if object construction is not thread confined, i.e., it violates the normal Java convention.

Figure 1.39. An empty lock set in PlanetBaron

An empty lock set in PlanetBaron

The query result in Figure 1.39 lists all objects that were observed to have at least one instance where a non-static field had an empty lock set. The screenshot above shows that three ship instances—one ship for each player we connected—contained an f_location field that had an empty lock set. It is possible that in your run one or two of the three instances had a non-empty lock set. How could this happen? This could occur, for example, if the one instance was not exercised enough to make the lock set become empty, or put another way, the bad code was never called on that Ship instance.

Before we investigate this potential locking problem in the PlanetBaron server code. We want to introduce the idea of a default query. Most, but not all, query results in Flashlight allow you to double-click on a row of the result and run a pre-selected or default query. This query has been selected by the tool to "make sense" to be invoked on that row of data. You can tell which query will be invoked with a double-click by selecting the row and then examining its context menu. The query that is the default is marked with a . To see this select f_location in the current query result and bring up the context menu. You will see that What instances contain this field and have an empty lock set? is marked as the default query. This is shown in Figure 1.40.

Figure 1.40. The default query in a context menu is marked with a The default query in a context menu is marked with a and can be invoked with a double-click and can be invoked with a double-click

The default query in a context menu is marked with a and can be invoked with a double-click

Let's run this default query by double-clicking on the f_location row in the query result. You should obtain a list of Ship instances that have an empty lock set. We want to keep drilling in to this result. (We obtained two instances but this number will vary.) So now double click on any Ship instance listed in the result to run the How often is a lock held when this field is accessed? query. This query shows all the locks that were observed protecting any access to the state of the Ship instance we double-clicked on in the prior query result. Your results will vary but should be similar to what is shown in Figure 1.41.

Figure 1.41. All the locks observed to protect access to the state of a Ship instance

All the locks observed to protect access to the state of a Ship instance

The data presented in Figure 1.41 may be somewhat of a surprise to you. How can so many locks protect the f_location field in one Ship instance? This occurs in the PlanetBaron server because the Ship class is part of the game model and is accessed from many places within the code. The code that invokes Ship class methods is holding locks as required by its concurrency policy—but holding these locks is not related to the concurrency policy of the Ship class. This results in Flashlight noting many locks being held when the f_location is accessed. Notice, by examining the reported % Held column, that most of these locks are not held all that often.

The lock that is held the most in Figure 1.41 is an instance of ReentrantReadWriteLock this is a dynamic lock defined by java.util.concurrent. Flashlight watches both intrinsic lock acquisitions (via synchronized blocks and methods) and dynamic locking (java.util.concurrent.Lock instances). Intrinsic lock use is indicated with a icon and the object instance name. Dynamic lock acquisition is indicated with a icon and the object instance name.

Some analysis of this query result points to a likely problem in the PlanetBaron server implementation. The same object, a instance of ReentrantReadWriteLock, is being used as both a dynamic and an intrinsic lock—this is indicated by the same lock name appearing, one with an icon (intrinsic) and the other with a (dynamic) icon. It is confusing and bad coding practice to do this in a Java program, but it can occur when a locking scheme is "converted" from using intrinsic locks to dynamic locks, and, in fact, this was done to the PlanetBaron server code. It could also happen if a programmer doesn't understand how to acquire a dynamic lock, e.g., l.lock(), and instead synchronizes on it, e.g., synchronized(l).

Let's investigate this further. Double-click on the top entry in the query result to run the Where is this field accessed while this lock is not held?. This query shows us the points in the code where this field was accessed and the dynamic ReentrantReadWriteLock was not held. This result also includes accesses during object construction, so we want to ignore these accesses.

The result is shown in Figure 1.42 Two of them are in the constructor, and don't appear to be a problem. The final line, on the other hand, is an unprotected access of f_location, and the source of our problem. Figure 1.42 shows the unprotected access of the f_location field at line 156 of the Ship.java compilation unit. This looks like a coding mistake. We have boxed (in yellow) the scope where the lock is held. It appears that the scope of code holding the lock in this method was just made too narrow to include this access. Clearly the method implementation wants a predicate (not asking to move to your current location) to hold, but the lock is not held when predicate is checked. In fact, this type of bug is called a check-then-act concurrency problem

Figure 1.42. The offending line of code

The offending line of code

Fortunately, the fix is straightforward: we acquire the write lock before the access of f_location in the condition of the if statement. This requires changing the scope of the tryfinally block as well. This change fixes the check-then-act concurrency bug.

  public void moveTo(Location destination) {
    if (isMoving())
      throw new IllegalStateException(
          "a moving ship can't change its destination");

    f_lock.writeLock().lock();
    try {
      if (f_location.equals(destination)) {
        LOG.log(Level.WARNING,
            "ignored attempt to move ship to its current location");
      } else {
        f_isMoving = true;
        f_turnsMoving = 0;
        f_destination = destination;
        f_moveDistance = f_location.distanceTo(f_destination);
        f_percentageMoved = 0.0;
        sendReport(); // OK to invoked holding a write lock
      }
    } finally {
      f_lock.writeLock().unlock();
    }
  }

Change the method to appear like the one above, and run Flashlight on the PlanetBaron server again. Once you have completed the new run and it is ready to be queried, you can run What fields (non-static) have a non-empty lock set after object construction? to see that all observed Ship instances that contain of f_location now have a non-empty lock set.

1.3.3. Finding a potential deadlock in the PlanetBaron player user interface with lock cycle detection

In addition to a lock set analysis, Flashlight provides an analysis that detects potential deadlock scenarios. It does this by constructing a directed graph of all lock acquisitions in the program. Each edge in the graph points from a lock that is already held to a lock being acquired. Cycles in the graph indicate that the program sometimes acquires a set of locks in more than one order, a behavior that can cause two or more threads to deadlock. To investigate this further, we will instrument the PlanetBaron PlayerUI this time around.

In the previous section we started up a server through the Flashlight launch tab and three instances of PlayerUI through the normal launch tab. For this experiment, we only need one instance of PlayerUI, and we will instrument it instead of the server. Go ahead and run com.surelogic.planetbaron.server.Server as a normal Java application, and then launch one instance of com.surelogic.planetbaron.client.PlayerUI through the Flashlight launch tab. As in the previous tutorial, go ahead and connect into the game (type in a player name and then press Connect), and move your ship to a planet or two. Then terminate your instance of PlayerUI by closing the application window, and stop the server from the Flashlight console. You should see progress in the Flashlight Launched Run Control dialog as shown in Figure 1.43.

Figure 1.43. Preparing data from a instrumented PlayerUI run for querying

Preparing data from a instrumented PlayerUI run for querying

If you are not already in it, switch into the Flashlight perspective so that we can begin to query the data from the PlayerUI run that you just completed.

As seen in Figure 1.44 Flashlight has observed lock cycles that may cause the program to deadlock.

Figure 1.44. Deadlock results about the PlayerUI in both the query menu and the bad news table

Deadlock results about the PlayerUI in both the query menu and the bad news table

This doesn't mean that the run actually deadlocked. In fact, in our run it didn't—but it may have in yours, if the user interface froze while you were running the game, then that's likely what occurred. What the tool has observed is that different threads acquired two or more locks in a different order—which could result in a deadlock if the timing of this is just right. For example, if one thread acquires lock-1 roughly at the same time a second thread acquires lock-2, and then (still holding both locks) the first thread tries to acquire lock-2 and the second thread tries to acquire lock-1 the program has reached a deadlock. Progress cannot be made in either of these threads unless one "gives up" trying to acquire both locks. But, in Java "giving up" is not expressible with intrinsic locks (e.g., synchronized statements) and most of the java.util.concurrent locks—both threads just stop their progress. Therefore, if two or more locks need to be acquired by a system then the order that the lock acquisitions are made should be kept consistent in the entire codebase. Deadlock can be difficult to test for, but Flashlight helps make it easier by not noticing inconsistent lock orderings without an actual deadlock having to occur. With traditional testing, the deadlock would actually have to occur during the test run to catch this problem. Further, the failure may not contain enough trace information to diagnose the problem. This can be maddening if you can only get the test failure to occur rarely, and, as is often the case, never in the debugger.

Click on the bad news item Lock cycles were observed that could cause the program to deadlock. This runs the query What lock cycles could potentially cause deadlock? as indicated in Figure 1.44. The query result you get should look similar to the one in Figure 1.45.

Figure 1.45. Lock cycles observed in our PlayerUI run

Lock cycles observed in our PlayerUI run

Go ahead and double-click on both cycles and take a look. Let's focus on the two lock cycle between a ReentrantReadWriteLock and an Object. This was the first cycle in our run, but it might be the second in yours. This result is shown in the Figure 1.46.

Figure 1.46. A potential deadlock in com.surelogic.planetbaron.client.PlayerUI

A potential deadlock in com.surelogic.planetbaron.client.PlayerUI

This query result uses a graphical display, in addition to a table to better convey the lock cycle. The result displays a two-lock cycle. This potential deadlock occurs whenever you connect a PlayerUI to the PlanetBaron server. You can manipulate the graph by clicking and dragging nodes if the layout is cluttered. You can also move the whole graph by clicking and dragging on the background of the graph.

In our run the locks involved are Object-42 and ReentrantReadWriteLock-51, and each appears to be acquired at some point while the other is already held. Notice from the icons that Object-42 is used as an intrinsic lock and ReentrantReadWriteLock-51 is used as a dynamic lock. Your lock numbers may be different, but they should correspond to the same locks identified in our run.

Notice that the result shown Figure 1.46 has all the criteria needed for the program to deadlock. One thread, Thread-4, holds ReentrantReadWriteLock-51 and then acquires Object-42 (138 times in our run). A second thread, AWT-EventQueue-0, holds Object-42 and then acquires ReentrantReadWriteLock-51 (80 times in our run). We just got lucky that the deadly embrace didn't occur and deadlock the PlayerUI—our program worked properly by luck of the scheduler. As we noted above, this problem in the code occurs whenever you connect a PlayerUI to the PlanetBaron server. There is a lock ordering problem with the PlayerUI code.

To figure out where in the code the implementation problem lies, we'll have to look at both lock edges in the cycle one at a time. Select the ReentrantReadWriteLock-51 -> Object-42 row in the table and run the Where and in what threads does this lock edge occur?. The result will be similar to the one shown in Figure 1.47.

Figure 1.47. Code location where the ReentrantReadWriteLock-51 -> Object-42 lock edge occurs

Code location where the ReentrantReadWriteLock-51 -> Object-42 lock edge occurs

The only location in the code where this edge occurred is at line 424 of the MapView compilation unit. Flashlight lets us understand how we got to this location with two kinds of traces: stack and lock traces. The stack trace is a traditional debugger trace. To see this select the code location in the result and run the What is the stack trace? as shown in Figure 1.48. The query result is shown in Figure 1.49.

Figure 1.48. Running a query to see the stack trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred

Running a query to see the stack trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred

Figure 1.49. Stack trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred

Stack trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred

You can select each row in the resulting stack trace to have the Java editor and Historical Source Snapshot view jump to that code location. Here the stack trace tells us that the lock acquisitions originated from the run method in our ServerProxy class. The ServerProxy class extends java.lang.Thread, and an instance of it is created and started when we connect to a server. Going to the bottom of the stack trace can often help us understand what Thread-4 was in terms of the program design. In this case, Thread-4 handles the background network communication with the PlanetBaron server. A limitation of a stack trace is that it doesn't directly show where the lock acquisitions occurred, that's what Flashlight uses a lock trace to do.

To show where locks were acquired in the code Flashlight uses a lock trace. Similar to a stack trace, the lock trace shows where locks were acquired by a thread in order from most recently acquired to least recently acquired. Go back up to the previous query result by pressing the toolbar button in the Query Results view. Select the code location again and pick the What is the lock trace? query from the context menu as shown in Figure 1.50 (you could alternatively double-click on the row because as indicated by the obtaining the lock trace is the default query). The query result is shown in Figure 1.51.

Figure 1.50. Running a query to see the lock trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred

Running a query to see the lock trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred

Figure 1.51. Lock trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred

Lock trace of how the ReentrantReadWriteLock-51 -> Object-42 lock edge occurred

Like the stack trace, you can select each row in the resulting lock trace to have the Java editor and Historical Source Snapshot view jump to that code location. If we inspect the two entries reported in the trace from bottom to top, we see that the edge first acquires a write lock on f_lock in GameMap as shown in Figure 1.52., followed by a lock on m_cursorLocationLock in MapView as shown in Figure 1.53.

Figure 1.52. First lock acquisition in this edge occurs in endCurrentTurn in the GameMap class

First lock acquisition in this edge occurs in endCurrentTurn in the GameMap class

Figure 1.53. Second lock acquisition in this edge occurs in the endOfTurn callback in the MapView class

Second lock acquisition in this edge occurs in the endOfTurn callback in the MapView class

The dynamic lock first acquired protects the model of the game map. This code and its locking policy is shared by the PlayerUI and the PlanetBaron server. The second lock is used to protect the location of the mouse cursor in terms of the game map grid within the PlayerUI. Apparently the designer of this code thought these two locks did not interact—but it appears that they do.

Now let's turn our focus to the other edge of the lock cycle to see what occurred in the program to have the locks occur in the other order. We need to go back up the the graphical view that showed the edges. To do this directly, select the What are the edges for this lock cycle? result in the Query Results Explorer view as shown in Figure 1.54. This action will change the Query Results view to show the results for the What are the edges for this lock cycle? query.

Figure 1.54. Directly selecting the What are the lock edges for this lock cycle? result in the Query Results Explorer view re-displays that queries result

Directly selecting the What are the lock edges for this lock cycle? result in the Query Results Explorer view re-displays that queries result

Select the Object-42 -> ReentrantReadWriteLock-51 row in the table and run the Where and in what threads does this lock edge occur?. The result will be similar to the one shown in Figure 1.55.

Figure 1.55. Code location where the Object-42 -> ReentrantReadWriteLock-51 lock edge occurs

Code location where the Object-42 -> ReentrantReadWriteLock-51 lock edge occurs

From the result above we see that this lock edge occurs at two points in the code: lines 299 and lines 463 of the GameMap compilation unit. Both seem to occur with the same frequency and both are within the AWT Event Dispatch Thread (EDT) so we'll arbitrarily pick the first and drill-in to it. Select the location at line 299 in the Query Results view and from the context menu run the What is the stack trace? query. The result is shown in Figure 1.56.

Figure 1.56. Stack trace of how the Object-42 -> ReentrantReadWriteLock-51 lock edge occurred

Stack trace of how the Object-42 -> ReentrantReadWriteLock-51 lock edge occurred

Again we are very interested in the bottom of the stack trace to figure out the thread context this edge occurred in. In this case the trace that led to the edge began in the mouseMoved method of the MapView class. This is a callback from the Swing user interface library about changes to where the mouse is pointing on the user's screen. Now go back up to the previous query result by pressing the toolbar button in the Query Results view. Select the first code location again and pick the What is the lock trace? query from the context menu (you could alternatively double-click on the row because as indicated by the obtaining the lock trace is the default query). The query result is shown in Figure 1.57.

Figure 1.57. Lock trace of how the Object-42 -> ReentrantReadWriteLock-51 lock edge occurred

Lock trace of how the Object-42 -> ReentrantReadWriteLock-51 lock edge occurred

The bottom two lock acquisitions are of the same lock, the lock that protects the location of the mouse cursor in terms of the game map grid within the PlayerUI. This is not surprising because the callback is telling the program that the mouse pointer location has changed on the screen. Select the top lock acquisition and in the Java editor you can see where in the code the last lock in this edge was acquired as shown in Figure 1.58.

Figure 1.58. The last lock acquisition in this edge occurs in the getPlanetAt "getter" method in the GameMap class

The last lock acquisition in this edge occurs in the getPlanetAt "getter" method in the GameMap class

This call to getPlanetAt is the problem. But what code called this method? Switch back to the stack trace result and select the entry just below the location in getPlanetAt—the second row in the trace. The result is shown in Figure 1.59.

Figure 1.59. Where the call to the getPlanetAt "getter" method occurs during this edge

Where the call to the getPlanetAt "getter" method occurs during this edge

The call to setScanInformation is the root cause of this edge. This method updates the information in the scan box part of the user interface as shown in Figure 1.60. The scan box displays information about the planet the mouse is currently hovering over. This image also visually shows the "logical" mouse location that is being protected by m_cursorLocationLock as a white outline around square on the game map.

Figure 1.60. The scan in the PlayerUI shows information about the planet the mouse is hovering over

The scan in the PlayerUI shows information about the planet the mouse is hovering over

Fixing a potential deadlock may not straightforward because it often points to a design problem. However, in this case narrowing the scope of use of m_cursorLocationLock is a good starting place. In particular, two changes would probably address this problem. First, the operation of checking if the cursor has moved, and if so saving the last location and updating the current location should be moved into a method—as opposed to being directly done in the mouseMoved method. Second, the call to notifyCursorListeners in setCursorLocation should not be made holding the lock.


private void setCursorLocation(Location l) {
  synchronized (m_cursorLocationLock) {
    m_cursorLocation = l;
    notifyCursorListeners(l); // BAD - Don't do this!
  }
}

  

Note that the call to notifyCursorListeners within the synchronized block. This call "calls back" to client code that has registered with the MapView class. This, from a best practice point of view, is really the root cause of the potential deadlock. It violates Joshua Bloch's Item 67: Avoid excessive synchronization from the book Effective Java (2nd edition, Addison-Wesley 2008). The item states To avoid liveness and safety failures, never cede control to the client within a synchronized method or block.. However, this is exactly what the current implementation of setCursorLocation does. For the purposes of this tutorial we will not go through the code changes necessary to fix this in the PlanetBaron code. We finish up by noting two things: (1) This deadlock does really occur in real use of the PlayerUI program, and (2) until Flashlight was used to investigate the problem, several experienced programmers were unable to track down what was causing the intermittent deadlock.

Before we move on, let's turn our attention to the second lock cycle in the program. Clear out all your query results by pressing icon in the toolbar of the Query Results view. Next double-click on the What lock cycles could potentially cause deadlock? query in the Query Menu view (it should be the first query listed). Next bring up the lock cycle we didn't just investigate to get a result similar to the one shown in Figure 1.61.

Figure 1.61. A "self" lock cycle in the PlayerUI where a single lock is used as both an intrinsic and dynamic lock

A "self" lock cycle in the PlayerUI where a single lock is used as both an intrinsic and dynamic lock

This is a "self" lock cycle where the same lock is being used as both an intrinsic and dynamic lock. Notice from the icons that ReentrantReadWriteLock-1565 is used as an intrinsic lock and same object ReentrantReadWriteLock-1565 is used as a dynamic lock. This troublesome code was most likely caused by a bad conversion to the use of the util.concurrent read-write lock from simple intrinsic locking in the PlanetBaron code—a change made in the second year of this software's existence. We will not step through this problem in detail, however, please feel free to investigate it fully on your own. To make this more concrete, we note that if you drill-into this result you will find muddled methods like the one listed below.

public void doTurn() {
  f_lock.writeLock().lock();  // dynamic lock acquisition
  try {
    synchronized (f_lock) {   // BAD - Don't synchronize on a dynamic lock object!
      f_sendReport_lastTurn = f_sendReport_thisTurn;
      f_sendReport_thisTurn = false;
    }
  } finally {
    f_lock.writeLock().unlock();
  }
}

  

Notice that f_lock is acquired as both a dynamic lock, the call to lock() and unlock(), and an intrinsic lock, the synchronized (f_lock) block. It is considered bad practice to synchronize on a util.concurrent lock object, but Java cannot stop you from doing this. This is a mistake that can effect program performance, and in this case, worse, cause a deadlock.

In fact, Flashlight has a special query to help track down this kind of intrinsic/dynamic use problem—even if it didn't result in a lock cycle as in the case of the example above. Let's run this query now. Clear out all your query results by pressing icon in the toolbar of the Query Results view. Next double-click on the What objects were used as both a dynamic and an intrinsic lock? query in the Query Menu view (it should be the last query listed in the Lock Use section of the menu). The result should be similar to the one shown in Figure 1.62.

Figure 1.62. Lock objects in the PlayerUI that were observed to be used as both a dynamic lock and an intrinsic lock

Lock objects in the PlayerUI that were observed to be used as both a dynamic lock and an intrinsic lock

This query can be helpful to track down this particular locking problem. In fact, there is a bad news item for this that you will receive if it is observed as shown in Figure 1.63.

Figure 1.63. News item that lock objects in the PlayerUI that were observed to be used as both a dynamic lock and an intrinsic lock

News item that lock objects in the PlayerUI that were observed to be used as both a dynamic lock and an intrinsic lock

1.3.4. Scanning code using Ant

This tutorial will demonstrate how to use the Flashlight Ant task to instrument and launch a PlanetBaron server in a script and load the resulting data into your Eclipse. The Flashlight Ant task is used to automate scans as part of a QA or nightly build process. This tutorial assumes you have run the previous tutorial. You may skip the previous tutorial but you will need to load the FlashlightTutorial_PlanetBaron project into your workspace.

First you will need to download and unzip the Flashlight Ant task from this location on the SureLogic web site. This will create a jsure-ant directory on your machine at the location you unzip the file.

In the PlanetBaron project create a file at the root of the project called flashlight-server.xml with the below contents.

<?xml version="1.0" encoding="UTF-8"?>
<project name="FlashlightTutorial_PlanetBaron" default="server" basedir=".">

  <!-- (CHANGE) path to the unzipped the Flashlight Ant task -->
  <property name="flashlight.ant.home" location="C:\\Users\\Tim\\flashlight-ant" />

  <!-- (COPY) Flashlight Ant task setup stuff -->
  <property name="flashlight.runtime"
    location="${flashlight.ant.home}\\lib\\runtime\\flashlight-runtime.jar" />
  <path id="flashlight-ant.classpath">
    <fileset dir="${flashlight.ant.home}" includes="lib/**/*.jar" />
  </path>
  <taskdef name="flashlight-instrument-archive" classname="com.surelogic.flashlight.ant.InstrumentArchive">
    <classpath refid="flashlight-ant.classpath" />
  </taskdef>

  <target name="server">
    <!-- First create working jar of your program -->
    <jar destfile="server.jar" basedir="bin">
      <manifest>
        <attribute name="Main-Class" value="com.surelogic.planetbaron.server.Server" />
      </manifest>
    </jar>
    <!-- Next instrument this JAR to collect information during a run -->
    <flashlight-instrument-archive srcfile="server.jar"
      destfile="flserver.jar" runtime="${flashlight.runtime}" />

    <echo>Flashlight instrumentation complete...launching...</echo>
    <!-- Next run the program from Ant -->
    <!-- Note the flashlight runtime MUST be before the instrumented JAR -->
    <java classname="com.surelogic.planetbaron.server.Server" fork="yes">
      <classpath>
        <pathelement location="${flashlight.runtime}" />
        <pathelement location="flserver.jar" />
      </classpath>
      <!-- Name of the run (when loaded in the IDE) -->
      <jvmarg value="-DFL_RUN=Server" />
      <!-- Place the output in a 'data' subdir under the project -->
      <jvmarg value="-DFL_RUN_FOLDER=data" />
    </java>
  </target>
</project>

You will have to modify the setting for flashlight.ant.home to reference where you located the flashlight-ant directory on your machine.

Within Eclipse run this as an Ant task by selecting the XML file and selecting Run As | Ant Build. Output from the running task will appear in the console as seen in Figure 1.64.

Figure 1.64. Console output from scanning PlanetBaron with Ant inside Eclipse

Console output from scanning PlanetBaron with Ant inside Eclipse

In the server run logged above I stared one PlayerUI and used the ChatTestClient to terminate the server when I was done playing. The output data is located in the FlashlightTutorial_PlanetBaron/data directory and is called Server-2015.10.16-at-15.24.41.361. Of course, your timestamp will be different in the directory name. You can change the output directory by changing the -DFL_RUN_FOLDER sent to the java task.

It is possible to launch the program from the command line. Under Windows this looks like the below command

java -cp "C:\Users\Tim\flashlight-ant\lib\runtime\flashlight-runtime.jar;flserver.jar" -DFL_RUN=Server -DFL_RUN_FOLDER=data com.surelogic.planetbaron.server.Server

Mac and Linux are similar (separate classpath entries with a semicolon not a colon). Depending upon what you are doing launching with Ant or via another script may be useful to you.

[Note]The Flashlight runtime JAR must be before the instrumented JAR in your classpath

In the example Ant script and command line java command above the flashlight-runtime.jar is placed ahead of flserver.jar in the program's classpath. This is required, and the program will fail to execute if it is not done. Any other JARS your project needs may come in the usual order. It is a good idea to always put the flashlight-runtime.jar first.

We can import this run into Eclipse when we are ready to look at the results. To do this we choose FlashlightImport Ant/Maven Scan.... The tool will then notify you once the run has finished importing. At this point you need to double-click the run in Flashlight Runs view to have it prepared for querying in Eclipse.

Figure 1.65. Successful scan import

Successful scan import

This tutorial has introduced the use of the Flashlight Ant task. You now know how to use the Ant tasks to add Flashlight to your QA process or nightly build. Reference documentation for the Flashlight Ant task is found in Section 2.12.

1.3.5. Finding a potential deadlock in a Java implementation of the Dining Philosophers problem

This tutorial explores Java implementation of the classic Dining Philosophers problem. Five philosophers sit down at a table. Five plates are laid out, one in front of each philosopher. Five forks are set down, one between each plate. A bowl of spaghetti sits in the middle. While dinner takes place, each philosopher alternates between states of thinking or eating. They must acquire the two forks on either side of their plate to eat from the bowl of spaghetti, and after eating they relinquish their forks to think again. The philosophers never speak to each other.

[Note]Which project should I use for this project?

Either of the two tutorial projects may be used: FlashlightTutorial_DiningPhilosophers or FlashlightTutorial_DiningPhilosophersJava8. The second requires Java 8. If you develop using Java 8 it is recommended that you use use the Java 8 project, if not the other project supports Java 6 or Java 7.

[Note]Delete the project you are not going to use from your workspace

Linking to code is somewhat heuristic in Eclipse. So it is a good idea to delete the project you are not going to use for this tutorial. Delete either FlashlightTutorial_DiningPhilosophers or FlashlightTutorial_DiningPhilosophersJava8. This will help to make sure that links from a Flashlight query result highlight the correct line of Java code in Eclipse (and do not point to the wrong project).

1.3.5.1. Running the program

To run the program select the DiningPhilosophers class and launch it. In the Eclipse console you should see the below prompt.

What strategy should the philosophers use to choose the order to pick up their forks?
1. Left fork followed by right fork (may deadlock)
2. Right fork followed by left fork  (may deadlock)
3. Randomly choose order each time (may deadlock)
4. Order all the forks on the table and have all philosophers pick them up in that order
Enter number your choice: 
  

The program lets you pick a strategy that all the philosophers use to pick up their forks. All but the last may deadlock the program. As the dining takes place you see output about what the five philosophers are doing: thinking, picking up a fork, eating, putting down a fork. Each philosopher tries to eat 10 times during the meal.

Except for the global order strategy, which is choice 4, the program may deadlock. We say may because you might be able to run the examples several times successfully before you encounter a hang. The unpredictable nature of the program failure makes deadlock difficult to test for, and tricky to diagnose. It all too often occurs at bad times—such as in production. Flashlight can help because, as we shall see a bit later in this tutorial, it detects lock ordering which may lead to deadlock, but does not require the deadlock to occur. In the example screenshot below picking up the left fork followed by the right fork led to deadlock—we'll have to manually terminate the program.

To summarize, if when you are running the program and the output hangs but the program is still running—deadlock has occurred. Press the red terminate button on the console toolbar (highlighted in the screenshot above) to terminate the deadlocked run. If the program completes successfully you will see a final log message as shown below.

Before we use Flashlight on this program let's sketch how it is implemented.

1.3.5.2. The Java implementation

The Java implementation represents each philosopher as a separate thread, and picking up and holding a fork is represented by holding a java.util.concurrent Lock instance. A philosopher must hold both nearby forks in order to eat. While dining the philosopher eats ten times. Using two enums, the implementation defines five forks, the Fork enum, and five philosophers, the Philosopher enum. Two forks are assigned to each philosopher to serve as the fork on their left and right. The first philosopher, Kant, Will have forks ONE and TWO, Diogenes will have TWO and THREE, and this goes on until we reach Russell, who has forks FIVE and ONE.

The Fork enum is listed below. It defines the five forks: ONE, TWO, THREE, FOUR, and FIVE. A util.concurrent dynamic lock is used by the program to represent holding a lock, so the getLock() method provides access to the lock. The isHolding() method is used by the program to check if the lock is held—in particular by several logging methods in the Philosopher enum that check that a particular fork of interest is held (or not held) using this method. The getGlobalOrder() method passes out the built-in enum ordinal value. This is used by the global order strategy to order fork pick-up across all philosophers (establishing a global order to lock acquisition is an effective deadlock avoidance technique).

The Philosopher enum is listed below. It defines five philosophers: Kant, Diogenes, Descartes, Goethe, and Russell. The constructor orders the group around the table with regard to the five forks. The getLeft() and getRight() methods provide access to the forks near each philosopher. For example, to get the fork to the right of Descartes you would use Descartes.getRight().

The Philosopher enum also has several methods that log what is being done and check the state of holding a fork is correct. These methods are listed below. These methods simply double-check fork state and log, they do not perform the actions. In particular they do not acquire the locks that indicated a philosopher is holding a particular fork. Doing this and running the simulation of philosopher dining is discussed below and is done by the PhilosopherStrategy type.

The PhilosopherStrategy type drives the simulation of the dining philosophers. This type is different depending upon if you are using the Java 8 version of the code or not. The Java 8 version is listed below. It uses an interface with default methods as well as a lambda (at line 47). The pre-Java 8 version of the code is so similar that we don't list it. That version uses an abstract class and replaces the lambda with an anonymous class.

The dine() method is how the main program starts the dining philosophers. It creates a separate thread of execution for each of the five philosophers and calls pickupBothForksAndEat ten times. A latch is used to have all the philosopher threads start the meal together. The chooseForkPickUpOrder is the method implemented by an actual strategy implementation. It returns a pair of forks. The first value is the fork that should be picked up (locked) first, the second value is the fork that should be picked up (locked) second. The pickUpBothForksAndEat method is where it all happens. This key method is listed below.

The implementation of this method is unsurprising. It locks on the forks in the passed order and calls the various philosopher methods to log the state of the simulation as it proceeds.

The PhilosopherStrategy type strips down the implementation of any strategy to simply defining what order the forks are picked up. The type hierarchy of concrete strategy implementations is shown below.

These map directly to the four choices the program gives you when it starts. The LeftThenRight class is listed below. It simply constructs a new pair (to define the pickup order) with the left fork first and the right fork second.

We don't list the RightThenLeft class because its implementation is exactly like the one listed above with one rather obvious change. The RandomOrder class is more interesting and is listed below.

The above implementation flips a coin to decide if it should return an order of left then right or an order of right then left. This might seem like a way to avoid deadlock, but it turns out it doesn't work and we will investigate its behavior with Flashlight below. A way to avoid deadlock is to define a global order on all the forks and have each philosopher respect that order. That is what the GlobalOrder strategy does and it is listed below.

This implementation uses the ordinal on each Fork to have the philosopher pick up (lock) the fork with the lower value first. This strategy will not deadlock.

1.3.5.3. Using Flashlight to uncover the potential for deadlock

Let's go ahead and make a run with Flashlight and see how it can help us detect that a program may deadlock. Right click on the DiningPhilosophers class in the Package Explorer and choose Flashlight AsJava Application. Alternatively, you can use the Flashlight launch icon in the Eclipse toolbar as shown below. Either approach will get the run started.

When the program runs go to the Console view and choose choice 3, Randomly choose order each time (may deadlock), for the run strategy. See if the program completes or deadlocks. If it completes Flashlight should automatically begin to prepare the data. If it hangs press the Terminate button to kill the run and, within a few seconds, Flashlight should detect the program was terminated and begin to prepare the data.

The run used to create the description below completed, however, your run may be different. Switch to the Flashlight perspective now if you have not been prompted to do so already, and select the DiningPhilosophers run in the Flashlight Runs view if it is not selected. You should see some bad news in the Query Results view.

Go ahead and click on the Lock cycles were observed that could cause the program to deadlock link. You should see two lock cycles displayed, as shown below. It is possible, but unlikely, that you may only get one–recall we selected random order as our strategy which results in a cycle going one way around the table and another going the other way around the table.

What is going on? The program didn't deadlock? Let's drill in to the first cycle by selecting that row in the Query Results view and selecting What are the edges for this lock cycle? from the context menu.

A lock acquisition order graph will be displayed that should look something like the screenshot below.

Each node in the graph is a lock observed at runtime being acquired by a thread of the program. In this case that means the five ReentrantLock objects that we created to be within the Fork objects. Each edge represents a time in the program that we held the lock at the source of the edge and tried to acquire the lock at the edge's destination. You can manipulate the graph by clicking and dragging nodes if the layout is cluttered. You can also move the whole graph by clicking and dragging on the background of the graph.

The tabular part to the right of the graph helps you to understand what threads actually performed the acquisitions of more than one lock and when. This can help diagnose if the cycle could have actually deadlocked. In this case it clearly could have. The occurrence counts in the Threads column are a bit confusing—this run completed wouldn't we expect the occurrences to add to ten? Ten being the number of times each philosopher ate during the meal holding two forks (locks). However this is only one direction, and we selected the random strategy. Go back and bring up the lock cycle graph for the second cycle. It should look something like the screenshot below.

Notice that if you add up the counts in the Threads columns for both lock cycles they do sum to ten—the number of times each philosopher ate during the meal. If you examine the graph the cycle is similar but goes in the other direction. This is a result of the random order strategy, which doesn't really work to avoid deadlock. The program could have deadlocked in either direction (perhaps your run did!).

Flashlight tries to ensure there is always a path from a result to the code. To show this for this example select the first entry in the table, ReentrantLock-28 -> ReentrantLock-19 in thread Russell), and from the context menu select the query Where and in what threads does this lock edge occur? as shown below.

The result of this query shows where in the code the edge occurs, to be precise, it shows where the lock was acquired that is pointed to by the directed edge in the graph while already holding the lock the directed edge emerged from. If you select the deepest entry the code jumps to the correct line number. Recall the Historical Source Snapshot shows what the code looked like when the run was made. It can help you avoid confusion if the code has changed since the run was made.

If we want to understand how the program got to this state use the context menu to display the stack trace. Choose What is the stack trace? as shown in the image below.

This brings up the stack trace leading up to the edge. The lock trace query shows you the order locks were acquired up to the edge, which is also interesting in some cases. However, in this case we can see the dual lock acquisition right in the method where the edge occurs.

The image below shows the Java 8 trace which begins in a lambda expression passed to a new thread. If you are running the Java 6 version will show a nested class that was passed to a new thread. In more complex code being able to get to the stack and lock traces can be invaluable to understand how a potential deadlock might occur—and help you to understand how to repair the problem.

This example illustrates how Flashlight tracks and reports on lock ordering and can help you understand, and eliminate, the potential for your system to deadlock—without having to produce a run that does deadlock.

Flashlight has another, albeit less precise, query to help uncover lock ordering issues. If you clear out your chain of queries you will see a Where does a thread hold a lock and acquire another? This is a good query to uncover all the places where two or more locks were acquired in your code—even if no lock cycles were observed.

Go ahead and run this query. The result you obtain should be similar to the image below.

Notice that the point where the second lock is acquired by a philosopher thread is the location reported as the result of this query. This query does not mandate that a lock cycle be observed. It simply finds all places a lock was acquired while holding one or more other locks. It can be useful to audit that all multiple lock acquisitions are intended—not accidental.

1.3.5.4. Using Flashlight to "check" the global lock order implementation

We stated earlier that the global lock order approach was deadlock-free. We can check this, to a degree, with Flashlight. Run the program again and choose choice 4. When it completes and is prepared you will see a news result similar to the one shown below.

The "good news" report, No lock cycles were observed that could cause the program to deadlock is a good sign that the approach works. However, Flashlight cannot prove anything about all possible runs of the program—it can only provide positive evidence about what it observes. This, however, is useful to gain confidence in the concurrency and locking policies of complex software system.

Finally, go ahead and run the Where does a thread hold a lock and acquire another? from the Query Menu for this run. Notice that you obtain the same result we did for the previous run. This is because, as we discussed above, this query doesn't consider lock cycles.

This completes the dining philosophers tutorial.

1.3.6. Finding a race condition in an Android application (Android only)

The following tutorial is intended to get you up and running with Android. You can try this on your Android phone or tablet if you have one. If you don't, you can still do this tutorial using the emulator provided by Google's Android Development Tools (ADT) — See Android's documentation on Managing Virtual Devices if you need to setup an emulator. If you do not have the Android SDK and ADT installed, you should do so at this time by following the instructions here. The tutorial project references the Android 2.3.3 libraries, so you can install them or you can choose a version (e.g., 5.1.1) that you have (and your device supports). If you need to do this right-click on the project and choose Properties. Next select Android to the left and choose a project build target at or above 2.3.3. The project should now compile.

[Note]This tutorial assumes you are an experienced Android developer

This tutorial is not intended to teach Android development. It assumes you have some experience developing software for an Android device. In particular, it focuses on Flashlight use within the ADT and doesn't explain in any detail how the code in the tutorial project interacts with the Android device and its operating system.

After you have installed ADT in Eclipse, go ahead and add the tutorial project, called FlashlightTutorial_CounterRace, to your workspace. To do this choose FlashlightRun Flashlight Tutorials from the Eclipse main menu. In the dialog that opens, ensure that FlashlightTutorial_CounterRace is checked and click OK. This will install the project into your workspace.

Counter Race is a simple program we developed to demonstrate that, despite being less powerful than today's generation of desktop processors, concurrency remains an issue that must be dealt with correctly on Android devices. Counter Race demonstrates this by running several threads, all of which increment two shared counters. The first counter is a static field that is incremented without any protection from locking or the volatile keyword. The second counter is implemented as a collection of thread-local counters. When the user checks a box, several threads are spawned. Each thread increments both the static counter and its own thread-local counter. Once the box is unchecked and the threads finish, the values of the thread-local counters are safely added up and presented as the total count. This count is compared to the value of the static counter and the results are displayed to the user.

Now let's run the Counter Race using with Flashlight. Right-click on the FlashlightTutorial_CounterRace project in the Package Explorer and choose Flashlight AsAndroid Application. This is shown in the image below.

Figure 1.66. Launching Counter Race

Launching Counter Race

If you are using an emulator, the emulator will take a while to start up. Once Counter Race has been deployed on the phone, the application should launch automatically. You should see a screen on the phone similar to the image below.

Figure 1.67. The Counter Race application

The Counter Race application

To start the threads, tap the checkbox once. After allowing it to run for a few seconds, you can tap the checkbox again to see the results. Your results should look similar to the image below.

Figure 1.68. Tap the checkbox to start and stop the counters

Tap the checkbox to start and stop the counters

Once you have exercised the program, you can go ahead and stop it in order to look at your data. Pressing the Home or Back buttons on your phone will close the Counter Race application, but most devices will keep the process running in the background. In order to stop the instrumentation so that we can collect our data, we do this using the Flashlight Launched Run Control dialog.

[Note]Do not terminate the tutorial application too quickly

The data collection infrastructure flushes data off the Android device roughly every three seconds. Therefore, it is a good idea to let the application sit for several seconds before you close it on the phone and then terminate it. Note that if f_threadLocalCounts does not appear as described below you may have terminated the application too quickly. Try running it again.

Open or switch to the Flashlight Launched Run Control dialog. This will not stop the application on the Android device or emulator but will stop data collection and prepared the data for querying. Stop data collection by pressing the to the far right of FlashlightTutorial_CounterRace row in the dialog.

Figure 1.69. Terminating data collection for FlashlightTutorial_CounterRace using the Flashlight Launched Run Control dialog

Terminating data collection for FlashlightTutorial_CounterRace using the Flashlight Launched Run Control dialog

Once you terminate the process, back in Eclipse, the data will start being prepared for querying. The Flashlight Launched Run Control dialog will show you the progress made.

If you are not in the Flashlight perspective, when the prepare job completes a dialog will ask you if you want to move to the Flashlight perspective to query your data. Select Yes to move to the Flashlight perspective.

After the data preparation completes you should see the Run Overview for the run of Counter Race, as shown in Figure 1.70. There are three articles of bad news: Shared fields have no common lock held for each access, Shared static fields have no common lock held for each access, and Shared static fields have writes that do not happen-before subsequent reads. If you don't see all three of these items of bad news, it is likely that you did not uncheck the checkbox on your smartphone when you were running the CounterRace application. If that is the case, you will want to perform another run of the CounterRace with Flashlight, this time making sure to both check and uncheck the checkbox.

Figure 1.70. Potential Race Conditions in Counter Race

Potential Race Conditions in Counter Race

We'll look at the potential problems with static fields first, so go ahead and click on Shared static fields have no common lock held for each access, which brings up the results of What fields (static) have an empty lock set? The query indicates that f_sharedCounter has an empty lock set. Click on f_sharedCounter in the view. This opens the code to the declaration of the field. We can see from the code that f_sharedCounter is a static, non-volatile field in the CounterThread class. We can look to see if f_sharedCounter was supposed to be protected by a lock of some sort, by running How often is a lock held when this static field is accessed? The results indicate that no locks were ever held when f_sharedCounter was accessed, though, so it is unlikely that the field was supposed to be protected by some sort of locking strategy.

Figure 1.71. Looking at f_sharedCounter

Looking at f_sharedCounter

Figure 1.72. No locks acquired when f_sharedCounter was accessed

No locks acquired when f_sharedCounter was accessed

Since there were no locks held when f_sharedcounter was accessed, let's examine the f_sharedCounter field to determine how it is shared by threads in the program. Reselect the What fields (static) have an empty lock set? query in the Query Results Explorer, then run What threads read and write this static field? The results should resemble the image below.

Figure 1.73. What threads read and write f_sharedCounter?

What threads read and write f_sharedCounter?

We can see from the query results that f_sharedCounter is indeed read from and written to by multiple threads. From this and our knowledge of the program, we can conclude that there is a race condition on f_sharedCounter. The detected race condition on f_sharedCounter was expected—it was engineered into the tutorial.

What about the other potential race condition, which was indicated in the Overview by the Shared fields have no common lock held for each access under Bad News? Get ready to start a new line of inquiry by clearing out our previous query results. To do this press the icon in the toolbar of Query Results view. Next, click on Shared fields have no common lock held for each access under the Bad Use section of the Overview for FlashlightTutorial_CounterRace. The Query Results view should display the f_threadLocalCounts field, similar to the image below.

Figure 1.74. Looking at f_threadLocalCounts

Looking at f_threadLocalCounts

As this query result reports, there should be four instances of f_threadLocalCounts in the program—one for each counter thread (or a multiple of four if you checked and unchecked the check box multiple times in your run). Select f_threadLocalCounts in the Query Results view and run (by double click or right click) the What instances contain this field and have an empty lock set? query.

Figure 1.75. Four instances of f_threadLocalCounts

Four instances of f_threadLocalCounts

Now select the first instance of f_threadLocalCounts to investigate more closely. Right click and select (run) the What threads read and write this field? query.

Figure 1.76. What threads read and write f_threadLocalCounts

What threads read and write f_threadLocalCounts

We can see from the query result that most accesses of f_threadLocalCounts by the program are in one thread, as should be the case for a thread-confined field. In our case, the thread that uses this instance of f_threadLocalCounts is Thread-4574, which is one of the four counter threads in the program.

There is one access made from the main thread while the object is under construction, and another made after object construction. It is common for fields that are thread confined, such as f_threadLocalCounts, to be written to during construction in a parent thread but subsequently accessed solely by another thread created by that parent. As long as a happens-before relationship is established between the parent thread and its child thread on creation, this is thread-safe. Similarly, it is common for a parent thread to create a child thread with the purpose of doing some work outside of the parent thread. The results of that work are then inspected once the child thread is finished. As long as a happens-before relationship is established between the child thread's termination and its parent, this is thread-safe too. Flashlight can these happens-before relationships, so let's verify for our self that they exist. We'll do that by taking a look at where in the main thread f_threadLocalCounts is initialized. Go up one query level, back to What instances contain this field and have an empty lock set? by clicking on the icon in the toolbar of Query Results view. Then run When and by what threads was this field accessed?

Figure 1.77. When and by what threads was f_threadLocalCounts accessed?

When and by what threads was f_threadLocalCounts accessed?

Your results should resemble the image above. This query tells us that the main thread first wrote to f_threadLocalCounts, then Thread-4391 wrote and read from it repeatedly while incrementing f_threadLocalCounts, for several seconds, and finally the main thread accessed f_threadLocalCounts again to read the result. The Happens-Before column indicates that there was indeed a Happens-Before relationship in between every time that f_threadLocalCounts was accessed by two different threads. This means that with respect to the Java memory model this field was accessed in a thread-safe manner.

If we want, we can drill in even further and look at where these happens-before events occurred to get a better idea of the program behavior. Go ahead and select the second entry (the entry not in the main thread), then run What happens before edges allow these field reads to see the previous write? There are two entries in this case: one from the thread start and one from the count down latch. Click on the Thread start entry and run What is the stack trace for this edge's source?

Figure 1.78. The happens before edges from the main thread to write of f_threadLocalCounts by the main thread.

The happens before edges from the main thread to write of f_threadLocalCounts by the main thread.

Figure 1.79. What is the stack trace for this edge's source?

What is the stack trace for this edge's source?

We can see from the figure above that f_threadLocalCounts is written to during the construction of CounterThread. If we click on first row, where the go method of class CounterRaceActivity is called, we jump to that line of code in the source code and can see the context where CounterThread is initialized. Following along with the code, we can see that all of the CounterThread objects are constructed first, then started from the main thread. When Thread.start is called, a happens-before relationship is created between the main thread and the counter threads. Because Flashlight observed that there is a happens-before relationship in between the write to f_threadLocalCounts from the main thread and the read/writes occurring in the counter thread, we can be satisfied that there is no race condition here.

Figure 1.80. Initialization of f_threadLocalCounts in CounterRaceActivity

Initialization of f_threadLocalCounts in CounterRaceActivity

Now we need to go back and look at the other access outside of the counter thread — the read of f_threadLocalCounts by the main thread. In the Query Results Explorer view, click on When and by what threads was this field accessed? and select the final row. Run What happens before edges allow these field reads to see the previous write? You should see something similar to the figure below.

Figure 1.81. The happens before edge to main from the counter thread

The happens before edge to main from the counter thread

Notice that the very last access of this field occurred in the main thread. Select the last access of f_threadLocalCounts, and run What is the stack trace for this edge's source?

Figure 1.82. What is the stack trace for this edge's source?

What is the stack trace for this edge's source?

Click on the first line of the stack trace to get an idea of what is happening at this point in time. We see that, in the stop method of CounterThread, the program iterates over each CounterThread and joins to it. The Thread.join method creates a happens-before relationship from the termination of each counter thread to the main thread. Because Flashlight observed that f_threadLocalCounts is read by the main thread after the happens-before relationship is established with its counter thread, we can be certain that the access is free of any race conditions.

Figure 1.83. Access of f_threadLocalCounts by the main thread after Thread-4574 has ended

Access of f_threadLocalCounts by the main thread after Thread-4574 has ended

This concludes the Android tutorial.

1.3.7. Using the Query Editor (Advanced)

The set of queries that ship with Flashlight are intended to be sufficient for the task of inspecting the results. If you have suggestions for queries that you think would be useful, please submit them using the Send Tip for Improvement command (see Section 2.14) or by emailing . You may nevertheless encounter a situation where you wish to create a custom query or modify an existing one, perhaps with the intention of exporting the data to a spreadsheet. You can use the Query Editor view to accomplish this. This tutorial won't explore the editor in detail, but should give you enough information to get started.

[Note]This tutorial assumes knowledge of SQL

Understanding the material in this tutorial is not critical for typical use of Flashlight. It covers an advanced approach to change or add to the tools capabilities. To use this approach, a non-trivial understanding of SQL is required.

From the Flashlight perspective, add the Query Editor view using WindowShow ViewOther… and selecting FlashlightQuery Editor. You should see a view that contains a list of queries on the left. Click on What fields (non-static) are shared? On the right side of this view, as shown in Figure 1.84, you can see the actual SQL statement that is executed whenever we run this query. Figure 1.85 shows an example of what this query looks like when run. You can reproduce this by selecting the prepared run of PlayerUI we created in the previous tutorial from the Flashlight Runs view and double-clicking on the name of the query in the Query Editor view.

Figure 1.84. What fields (non-static) are shared?

What fields (non-static) are shared?

Figure 1.85. Result of running What fields (non-static) are shared?

Result of running What fields (non-static) are shared?

The above figure displays a standard SQL query that displays some summary information about shared fields in a Flashlight-instrumented program. It does this by selecting information from the embedded database created when a Flashlight run is prepared. For a complete reference as to what Derby—the database Flashlight uses—accepts as valid SQL, see the Derby Reference Manual. You may have noticed that the column labels in this query are a little odd, and that they don't quite match up with what the labels look like in the query results. Flashlight allows you to provide formatting clues to the Query Results view by adding suffixes to your column labels. These suffixes begin with __ (two underscore characters) followed by any number of special tokens, including (amongst others)

  • (l) to left justify the text in the column.

  • (r) to right justify the text in the column.

  • (c) to center justify the text in the column.

  • | to make a tree-table. Everything preceding the | is considered to be part of the tree portion. In the above example, the package, class, and field names are considered part of the tree. You may also place a ] on any of the columns comprising the tree to tell the Query Results view to keep part of the tree collapsed by default when it displays the results.

  • (prefix 'str') or (suffix 'str') where str is a (possibly empty) string. The prefix or suffix string is placed at the beginning or end of every column.

  • (add-commas) makes a numeric value comma-delimited.

  • (human-readable-duration converts a duration of time into a human readable value. The default is to assume the time is specified in nanoseconds, but you can also say (human-readable-duration unit 'SECONDS') to indicate the value is in seconds. Any enum value of java.util.concurrent.TimeUnit will work for this purpose.

  • (op on column1, …, columnn), where op is one of sum, count, or max, to display the sum, count, or maximum of the collapsed values in each specified column in a tree-table. For example, (count on 2,3) would display the number of rows underneath each node in the second and third columns of the tree-table.

  • (hide) to prevent the selected database field from being displayed in the results. Sometimes the children of a query need an identifier that cannot be displayed prettily. For example, What are the individual instances of this non-static field? is a sub-query of What fields (non-static) are shared?, and it needs the numeric id of the field to run. The latter query displays the field name, and hides the field id using the (hide) token.

  • (blank-if 'value' will change the contents of the column to blank if value is the data for a particular row.

  • ('image name') to display an image next to the row's text. Flashlight uses ('package.gif') and ('class.gif') extensively.

  • (icon) to display an image next to the row's text based on a code. A full explanation of (icon) is outside the scope of this tutorial, but we will use the codes associated with class names and method names in the query we construct.

Now that we've got a handle on what a query looks like, let's go ahead and write our own. We'll construct a query that takes a field id as input, and produces a list of all of the methods that directly access the field. We will then export this list to a document. In the Query Editor view, click the button to create a new query. Edit the Description: We'll call this query What methods directly access this field? Leave the identifier as it is. Flashlight generates a new one every time you create a new query, and there isn't generally a need to change it. Go ahead and check the box to indicate that we want to be able to see this in the query menu, but don't check the box to show it at the root level. Insert the following SQL code into the editor box:

SELECT DISTINCT 
   CO.PACKAGENAME "Package__('package.gif')", 
   CO.CLASSNAME   "Class", 
   CO.CLASSCODE   "Class__(icon)",
   S.LOCATION     "Method",
   S.LOCATIONCODE "Method__(icon)",
   S.ATLINE       "Line__|"
FROM ACCESS A, TRACE T, SITE S, OBJECT CO
WHERE A.FIELD = ?FieldId? AND
      T.ID = A.TRACE AND
      S.ID = T.SITE AND
      CO.ID = S.INCLASS
ORDER BY 1,2,3

Figure 1.86. Creating our new query

Creating our new query

We now have a fully working query. We can now double-click the entry in the Queries tab of the Query Editor view and get a pop-up asking us to fill in a FieldId as seen in Figure 1.87. Manually typing in a field id isn't very useful, though. What we really want is to call this from another query that can fill it in for us. Go ahead and select What fields (non-static) are shared? again and click on its Sub-Queries tab. You should see a list of two queries here. We are going to add another. Click on the button in this tab and check our new query, What methods directly access this field? The Sub-Queries tab should now look like Figure 1.88

Figure 1.87. Adding a new sub-query to What fields (non-static) are shared?

Adding a new sub-query to What fields (non-static) are shared?

Figure 1.88. The sub-queries of What fields (non-static) are shared?

The sub-queries of What fields (non-static) are shared?

To wrap up, let's try out our new query. Choose the run we prepared from the PlayerUI tutorial in the Run View again, and run the query What fields (non-static) are shared? Now pick a field from the query results, and run What methods directly access this field? We'll go ahead and export these results to a file we can later import into a spreadsheet. Choose Export… in the Query Results view menu, and export a CSV file to a location of your choice. Shown in Figure 1.89 is a picture of the list of methods that access m_cursorLocationLock in com.surelogic.planetbaron.client.MapView being exported. You can then import the file into your favorite spreadsheet editor.

Figure 1.89. Exporting the results of What methods directly access this field?

Exporting the results of What methods directly access this field?

Figure 1.90. Importing the results of What methods directly access this field?

Importing the results of What methods directly access this field?

Chapter 2. Reference

2.1. The Flashlight menu

Figure 2.1. The Flashlight menu

The Flashlight menu

The Flashlight menu appears as an item on the Eclipse workspace main menu. This menu provides direct access to common commands. The menu is divided into four sections. The top section contains command to launch and load instrumented programs (in Eclipse or via Ant) and a command to show the launched run control dialog and the Flashlight perspective. The second section allows access to the JSure inference capabilities of Flashlight. The third section contains commands to report problems about or suggest improvements to Flashlight directly to SureLogic. The bottom section allows access to the license management dialog.

The commands on the Flashlight menu are:

  • FlashlightLets a user rerun a recent Flashlight run configuration or create a new one using the Flashlight Configurations view.

  • Open Flashlight PerspectiveOpens the Flashlight perspective. This perspective is useful for examining and querying collected run data. This perspective may also be opened via the normal Eclipse menus and toolbars for perspectives.

  • Import Ant/Maven run... Allows the user to copy a Flashlight run created from one of the Flashlight Ant tasks into the data directory. This allows the run to be prepared and inspected in the Eclipse tool user experience. For more information about using Ant with Flashlight please see Section 2.12.

  • Save Documentation As... Saves the HTML-formatted documentation for Flashlight to a directory of your choice.

  • Install Tutorial ProjectsOpens a dialog to allow the user to import tutorial projects into their workspace and open the Flashlight help to the step by step tutorials. For more information please see Section 1.3.

  • Flashlight Android APK... Opens a dialog that allows the user to select an APK file, which is a packaged Android application (binary), and launch an instrumented run on an Android device or emulator. Optionally you can associated a workspace project with the APK, but this is only useful if you have the application's source code, and is rarely needed because the Android project can be launched directly with Flashlight. For more information please see Section 2.11.3.

  • Infer JSure Annotations... Opens a dialog that allows the user to infer JSure annotations for a project, based on a completed Flashlight run. For more information see Section 2.8.

  • Send Tip for ImprovementOpens a dialog to allow entry of a suggestion by the user to improve Flashlight. For more information please see Section 2.14.

  • Send Problem ReportOpens a dialog to allow entry of a problem report by the user about Flashlight. For more information please see Section 2.14.

  • Manage SureLogic LicensesOpens the SureLogic license management dialog. This dialog allows the user to install, view, and uninstall licenses for Flashlight and other SureLogic tools. For more information see Section 2.3.

2.2. The Flashlight perspective

The Flashlight perspective organizes the Eclipse workbench to show views which will help you to interact with data from program runs.

This perspective is useful for beginning use of the Flashlight tool. Its "canned" organization can help you to understand the capabilities of the tool. Advanced users may want to reconfigure the screen layout and save a custom perspective.

Each of the views shown in the screenshot above is discussed in the following sections. These views include

Finally, we also discuss the Flashlight Launched Run Control dialog in Section 2.2.8 because it tracks launched Flashlight-instrumented applications and allows control over data collection.

2.2.1. Switching to the Perspective

The Flashlight perspective can be enabled in several ways:

  • By selecting FlashlightOpen Flashlight Perspective.

  • By choosing to switch to the perspective when data preparation for a run completes:

  • By selecting WindowOpen PerspectiveOther…, and then choosing Flashlight from the Open Perspective dialog box. Or by using any other standard Eclipse mechanism to switch perspectives, such as clicking the the perspective’s icon () in the shortcut bar.

2.2.2. The Flashlight Runs view

The Flashlight Runs view lists information about all of the completed runs of programs launched from the Flashlight launch tab. An example of this view is shown in Figure 2.2. This view only shows runs that have completed their execution. To examine runs that are still running, and were been launched within Eclipse, you use the Launched Run Control dialog as described in Section 2.2.8

Figure 2.2. The Flashlight Runs view

The Flashlight Runs view

The list below describes each column of the table that appears in this view.

  • Size. The size of the the run and its current state. The size is of the disk space being used by the run. The state of the run is indicated by the icon displayed in this column. There are three icons

    • – The run has finished and its data is prepared for querying. Selecting this run will populate the Query Menu with queries and the Query Results view with good and bad news about the run.

    • – The run has completed data collection and is in the process of being prepared for querying.

    • – The run has completed data collection but has not started data preparation or its prepared data has been manually been deleted from the disk. Selecting this run will allow you to prepare it for querying (so will a double-click on the run).

  • Run. The name of the program run. This is the same name that you see when launching a program from the Flashlight launch tab. The icon indicates what type of program the run represents. There are two icons

    • – The run is from a Java desktop or server application.

    • – The run is from an Android application launched on a phone, tablet, or emulator.

  • Time. The time the program was launched.

  • Duration. The duration of the program execution.

  • Processors. The number of CPU's that the JVM ran on when this program was executed.

  • Max Memory. The maximum amount of computer memory allotted to the program.

  • Java. The version of the JVM that ran the program.

  • Java Vendor. The JVM vendor.

  • OS. The operating system the program ran under.

  • Host. The hostname of the computer the program ran on.

  • By. The user the program ran under.

Figure 2.3. The Flashlight Runs view toolbar

The Flashlight Runs view toolbar

The view’s toolbar has two command icons; see Figure 2.3.

  •  This button opens the Launched Run Control dialog. This dialog, which lists still running Flashlight-instrumented programs, is described in Section 2.2.8.

  •  This button scans the disk and refreshes the list of completed Flashlight runs. This can be useful if an Ant scan was added to the Flashlight scan directory.

Figure 2.4. The Flashlight Runs view menu

The Flashlight Runs view menu

The view’s menu has six commands; see Figure 2.4.

  • PrepareSelecting this menu item causes selected runs to be prepared for querying. If the run has already been prepared, the prepared data is deleted and prepared again from the "raw" collected run data.

  • Show LogThis button opens a dialog that shows the log for the run. This includes information about the instrumentation, execution, and data preparation. An example of the dialog is shown in the image below.

  • Infer JSure Annotations... Selecting this menu item opens a dialog that allows the user to infer JSure annotations for a project, based on a completed Flashlight run. For more information see Section 2.8.

  • DeleteSelecting this menu item deletes the selected runs from the disk.

  • Run ControlSelecting this menu item opens the Flashlight Launched Run Control dialog. This dialog lists all instrumented programs launched during this Eclipse session. It allows collection of data to be stopped at any time.

  • RefreshSelecting this menu item scans from the disk and shows updates the view contents to reflect the current disk state. This is useful if runs are manually deleted or Ant runs are manually copied into the run directory.

Figure 2.5. The Flashlight Runs view context menu

The Flashlight Runs view context menu

The view’s context menu has five commands; see Figure 2.5. These commands match the view menu commands described above.

2.2.3. The Query Menu view

The Query Menu view lists the queries that you can do on a Flashlight run. An example of this view is shown in Figure 2.6. At the top level these queries are categorized to help you determine what results are of interest to you. These categories can be seen in the image below. If you have selected a particular result in the Query Results view then the Query Menu view lists the possible "drill-in" queries, which we also call sub-queries, you can invoke.

Figure 2.6. The Query Menu view

The Query Menu view

During data preparation Flashlight checks if each top-level query has results. Normally queries with empty results are not shown in the menu (however a setting below can change this and shown them in gray). If, however, all queries in a section are empty then a message is shown for that category to inform the user of this situation. In Figure 2.6 this is the case for the API Use category at the bottom of the view.

Figure 2.7. The Query Menu view toolbar

The Query Menu view toolbar

The view’s toolbar has one command icon; see Figure 2.7.

  •  This button brings the query menu back up to the top level for the currently selected run. It keeps all previous query results.

Figure 2.8. The Query Menu view menu

The Query Menu view menu

The view’s menu has three commands; see Figure 2.8.

  • Back to Top-Level QueriesSelecting this menu item brings the query menu back up to the top level for the currently selected run. It keeps all previous query results.

  • Show Empty QueriesChecking this menu item causes empty queries at the top level of the query menu to be shown in gray. If it is not checked these queries are not shown in the view. All the gray queries listed in the menu below can be run, but will result in no row of data returned.

    This preference is for advanced users and developers. It is rarely useful for normal tool use.

  • Show Unrunnable QueriesChecking this menu item causes unrunnable sub-queries to be shown in gray. If it is not checked these queries are not shown in the view. The gray sub-query in the image below cannot be run for the selected row in the Query Results view.

    This preference is for advanced users and developers. It is rarely useful for normal tool use. This preference also shows unrunnable queries in the context menu of the Query Results view.

Figure 2.9. The Query Menu view context menu

The Query Menu view context menu

The view’s context menu has two commands; see Figure 2.9.

  • RunSelecting this menu item causes selected query to be invoked and its results displayed to the tool user. A double-click can also be used to invoke a query.

  • Show QuerydocSelecting this menu item causes the documentation for the selected query to be shown in the Querydoc view. Also, selecting the query with the mouse causes its documentation to appear in the Querydoc view. The Querydoc view is described in Section 2.2.6.

2.2.4. The Query Results view

The Query Results view shows either (a) an overview of news about the run currently selected in the Flashlight Runs view or (b) query results as a table, tree or tree-table. We now consider examples of both.

Figure 2.10. The Query Results view showing good and bad news about a run

The Query Results view showing good and bad news about a run

Showing good and bad news about a run: An example of news about a run is shown in Figure 2.10. In this mode the view lists good and bad news about the selected run. These news items are not definitive, because they represent information from a single run of the program—hence the name news instead of results. Some news items are underlined. These underlined news items may be selected with the mouse to invoke a query and show the news item's corresponding results. Some news items are not underlined because they indicate that no information was observed during the run—in these cases no results indicates something newsworthy. These items that are not underlined have no associated results.

The "news" version of this view is only shown if a run is selected and no query result about that run is selected. If a query has been run the view shows the results of the query.

Figure 2.11. The Query Results view showing query results and allowing sub-queries on a selected row

The Query Results view showing query results and allowing sub-queries on a selected row

Showing results and allowing "drill-in" queries: When results are shown in the Query Results view you can select a row and "drill-in" to a particular row of the result that is of interest. An example of news about a run is shown in Figure 2.11. Hence, you can run queries based upon the results of previous queries. This "drill-in" tree of queries is tracked in the Query Results Explorer view. You can move up and down within a particular "drill-in" tree of query results by using the forward and back arrows in the toolbar of both results views or by selecting a particular result in the Query Results Explorer view. To run a "drill-in" query you bring up the context menu for the selected result in the Query Results view (for example, using a right-click of the mouse) or double-click that query in the Query Menu view.

The result of a query is displayed as either a tree, table, or tree-table, depending on the specific query. Section 2.10 describes the different queries and the shapes of their results.

Figure 2.12. The Query Results view toolbar

The Query Results view toolbar

The view’s toolbar has five command icons; see Figure 2.7.

  •  This button collapses all opened nodes in a tree or tree-table query result.

  •  This button changes the selected query to the immediate parent query of the currently selected query. The tree of queries that has been run by the user is shown in the Query Results Explorer view.

  •  This button changes the selected query to the first child query of the currently selected query. The tree of queries that has been run by the user is shown in the Query Results Explorer view.

  •  This button removes the selected query from this view and the Query Results Explorer view. If the query has any child sub-queries they are removed as well. The immediate parent query of the removed query, if one exists, becomes the selected query.

  •  This button removes all queries the user has run from this view and the Query Results Explorer view. The tree of queries that has been run by the user is shown in the Query Results Explorer view.

Figure 2.13. The Query Results view menu

The Query Results view menu

The view’s menu has six commands; see Figure 2.13. This menu is exactly the same as the view menu for the Query Results Explorer view.

  • Show Defined Variable Values... Selecting this menu item brings up a dialog that shows the variable values that defined the context of the query result being shown in the view. Selecting rows in a query result defines variables that are used to set a context to run subsequent sub-queries. As the user drills-in to the collected results more and more variables are used to define the context. The dialog lists the variable names in blue and their values in black.

    This menu item is for advanced users and developers. It is rarely useful for normal tool use.

  • Show SQL... Selecting this menu item brings up the SQL query run to create the result being displayed in this view. The dialog shows the SQL query with all variable value substitution completed. The original query may be examined in the Query Editor.

    This menu item is for advanced users and developers. It is rarely useful for normal tool use.

  • Export... Selecting this menu item allows you to export the query result being shown in this view to a file. A dialog comes up that lets you select the desired output format.

  • Back to Top-Level QueriesThis button brings the query menu back up to the top level for the currently selected run. It keeps all previous query results.

  • RemoveSelecting this menu item removes the selected query from this view and the Query Results Explorer view. If the query has any child sub-queries they are removed as well. The immediate parent query of the removed query, if one exists, becomes the selected query.

  • Remove AllSelecting this menu item removes all queries the user has run from this view and the Query Results Explorer view. The tree of queries that has been run by the user is shown in the Query Results Explorer view.

Figure 2.14. The Query Results view context menu lists "drill-in" queries that can be run on a selected row

The Query Results view context menu lists "drill-in" queries that can be run on a selected row

The view’s context menu lists "drill-in" or sub-queries that can be run on a selected result row; see Figure 2.14. The particular list of sub-queries is dependent upon the result that is selected. The query in the menu that is decorated with a is called the default query and can be run using a double-click on the row. For example, in Figure 2.14 the default query is What fields are protected by this lock, and how often?

2.2.5. The Query Results Explorer view

This view allows you to select any of the queries run previously during the session and display it in the Query Results view. You can also delete any or all of the results from here.

Figure 2.15. The Query Results Explorer view showing the tree of queries the tool user has run

The Query Results Explorer view showing the tree of queries the tool user has run

Figure 2.16. The Query Results Explorer view toolbar

The Query Results Explorer view toolbar

The view’s toolbar has four command icons; see Figure 2.16.

  •  This button changes the selected query to the immediate parent query of the currently selected query.

  •  This button changes the selected query to the first child query of the currently selected query.

  •  This button removes the selected query from this view and the Query Results view. If the query has any child sub-queries they are removed as well. The immediate parent query of the removed query, if one exists, becomes the selected query.

  •  This button removes all queries the user has run from this view and the Query Results view. The tree of queries that has been run by the user is shown in the Query Results Explorer view.

Figure 2.17. The Query Results Explorer view menu

The Query Results Explorer view menu

The view’s menu has six commands; see Figure 2.17. This menu is exactly the same as the view menu for the Query Results view.

  • Show Defined Variable Values... Selecting this menu item brings up a dialog that shows the variable values that defined the context of the query result being shown in the view. Selecting rows in a query result defines variables that are used to set a context to run subsequent sub-queries. As the user drills-in to the collected results more and more variables are used to define the context. The dialog lists the variable names in blue and their values in black.

    This menu item is for advanced users and developers. It is rarely useful for normal tool use.

  • Show SQL... Selecting this menu item brings up the SQL query run to create the result being displayed in this view. The dialog shows the SQL query with all variable value substitution completed. The original query may be examined in the Query Editor.

    This menu item is for advanced users and developers. It is rarely useful for normal tool use.

  • Export... Selecting this menu item allows you to export the query result being shown in this view to a file. A dialog comes up that lets you select the desired output format.

  • Back to Top-Level QueriesThis button brings the query menu back up to the top level for the currently selected run. It keeps all previous query results.

  • RemoveSelecting this menu item removes the selected query from this view and the Query Results Explorer view. If the query has any child sub-queries they are removed as well. The immediate parent query of the removed query, if one exists, becomes the selected query.

  • Remove AllSelecting this menu item removes all queries the user has run from this view and the Query Results Explorer view. The tree of queries that has been run by the user is shown in the Query Results Explorer view.

The Query Results Explorer view does not have a context menu.

2.2.6. The Querydoc view

Each query in Flashlight has Javadoc-like documentation that is displayed in the Querydoc view. Selecting a query in the Query Menu causes its "querydoc" to appear in this view.

Figure 2.18. The Querydoc view showing Javadoc-like information about a Flashlight query

The Querydoc view showing Javadoc-like information about a Flashlight query

The documentation about each query includes a concise description about what its results display. Some pointers on how to read and understand the query's results—including any limitations the tool user should be aware of—are included in the querydoc text.

2.2.7. The Historical Source Snapshot view

When a Flashlight run is performed, a snapshot of the project source code is collected. The Historical Source Snapshot view shows the source code as it appeared when the run was performed. When results are selected in the Query Results view the tool highlights any associated line of code in this view.

Figure 2.19. The Historical Source Snapshot view showing the field access selected in the Query Results view

The Historical Source Snapshot view showing the field access selected in the Query Results view

The snapshot of the source code as of the program launch and this view help the user if the code has changed significantly since the run occurred. If the results only linked to the Java editor in Eclipse the tool user may be confused if the linked code has been changed. This view helps avoid confusion with regard to code change since the run.

2.2.8. The Launched Run Control dialog

This section describes the Flashlight Launched Run Control dialog. This dialog automatically appears when an instrumented program is launched in Eclipse. It tracks the program run from launch, execution, termination, and data preparation. It can be though of as being similar to a web browser download monitor dialog. The image below shows an example of this dialog.

In the example above three instrumented launches are being tracked. The PlayerUI run has launched and is collecting data. The ChatTestClient and Server runs have finished collecting data and are having their data prepared for querying. The progress of data preparation is tracked in this dialog.

It is possible to stop data collection and disconnect Flashlight from the running application by pressing the icon to the far right of each dialog entry. When the application completes or Flashlight is disconnected from the running application.

It is also possible to filter the list of launches shown by typing text into the box at the lower-right of the dialog. For example if "Play" is typed into the filter box then all other launches except those that begin with Play will be filtered out. This is shown in the image below.

To clear any filter you can either erase the text using backspace / delete or press the (which will erase the text all at once)

There are two ways to remove runs from the dialog that are ready for the user to query. First, you can clear an individual run by pressing the to its right. Second, you can press the Clear List button to the lower-left of the dialog. The Clear All Completed button clears all runs from the list that have completed data preparation. These two approaches are highlighted in the image below.

Press the Close button to close the dialog at any time. You can also use the operating system close button as well.

2.3. License management

Flashlight is commercial software and a license is required to use it. Licenses are obtained from SureLogic and expire after some period of time. Lack of a license will prohibit you from running queries or creating new Flashlight runs. Selecting Manage SureLogic Licenses from the Flashlight menu brings up the license management form as seen in Figure 2.20. (It is also possible to bring this dialog up from the main Flashlight preferences pane by pressing the Manage SureLogic Licenses button.) For Flashlight to operate properly either a Flashlight or All Tools license must be installed.

Figure 2.20. The SureLogic license management dialog

The SureLogic license management dialog

License installation does not require internet access, but at some point the license will need to be activated. Activation does require internet access. Further use of the product does not require internet access. If a manual uninstall is done before license expiration, internet access is also required. SureLogic tracks the number of times a particular license is installed and uninstalled. We stress that Flashlight does not, unlike other plug-ins such as MyEclipse, "talk-back" to SureLogic each time Eclipse is started.

The installed license expires after a period of time (clearly visible to the user) and a new license has to be installed to continue to use Flashlight.

Licenses can be installed more than once. Thus, one license can be used for all of an organization or SureLogic can issue one per location or one per organizational entity.

If the Flashlight Eclipse plug-in does not have a valid license it will not affect the Eclipse installation that Flashlight is installed into. The IDE will load and function normally, but when Flashlight functions are executed they will fail noting the lack of a license. Serviceability functions of the tool (e.g., sending problem reports to SureLogic, installing and uninstalling licenses) function properly without a license. The unlicensed Flashlight plug-in can be uninstalled or disabled within Eclipse.

A license can be installed from a file or copy/pasted from the clipboard. To install the license, click Install From File and choose a file, or click Install From Clipboard and, if it has not happened automatically, paste the license data into the text window. Once the tool verifies that the license is valid, an entry displaying information about the license is placed in the license management view. This entry also indicates whether or not the license has been activated. A license can be activated by clicking the Activate button. Most licenses must be activated within a certain time limit or they will cease to work. The license file is not examined by the tool after the activation is completed unless you install the license again (after an uninstall).

To uninstall a license, select the row in the license table and press the Uninstall License. You will be asked if you are sure you want to uninstall the license. If you confirm the uninstall then the license is removed. This may take a minute as SureLogic is informed that your license has been uninstalled.

When a license is nearing expiration the tool warns the user with the dialog shown in Figure 2.21.

Figure 2.21. Dialog warning that the installed Flashlight license is about to expire

Dialog warning that the installed Flashlight license is about to expire

When a license does expire it disappears from the dialog. The tool is considered unlicensed at that point. To fix this situation install a new license (it is not required to install a new version of Flashlight).

2.4. Preferences

Figure 2.22. The Flashlight preference page

The Flashlight preference page

Flashlight lets you adjust the way it instruments, records, and prepares data. You do not have to change any preferences for Flashlight to work correctly, but changing some of these parameters may improve performance or convenience.

Data directory The directory where flashlight places all recorded and prepared data. All data for a run is placed under a folder in this directory; see Section 2.9 for a description of the contents of this directory. This location is relative to your workspace and cannot be changed.

Action on instrumented launch These options affect what additional actions occur when you launch an instrumented application using the menu.

  • The first checkbox controls whether the JVM used for the launched program is allocated the maximum amount of memory possible for its heap. By default, this is checked. Generally, you want to leave this checked because the data collection process creates a lot of objects and needs a lot of heap space.
  • The second checkbox controls if Eclipse should ask whether to switch to the Flashlight perspective when an instrumented application finishes executing. This is true by default.
  • The third checkbox controls what happens when Eclipse should not prompt to change the perspective: If checked, Eclipse will automatically switch to the Flashlight perspective when an instrumented program terminates.

Instrumentation These options control how the instrumentation collects and logs events from the running program:

  • Collect data for postmortem analysis determines whether or not Flashlight should be collecting data to be used by the postmortem tool. If this box is not checked monitoring will still be performed at runtime, but data cannot be prepped after the program terminates.
  • Console port (counts up if this port is in use) specifies the port that the instrumentation will listen on. You can telnet to this port and issue a 'stop' command if you want to shut down the instrumentation and leave your program up and running. Alternatively, a 'quit' or 'exit' command will terminate the program as well.
  • Collection type determines whether all or some events, such as field accesses; object and class instantiations; and lock acquisitions, attempts, and releases should be considered by Flashlight. The default is to record all events, but the user can choose to focus only on locking events if they wish. Doing so will eliminate most analyses from the Flashlight postmortem tool, but lock cycle detection and lock contention information will still be available.
  • Output type determines whether the recorded information should be stored as an XML file, or as binary data.
  • Flashlight has a 'refinery' component that attempts to remove data known to be local to a single thread, such as an object that is created and garbage collected within a single method invocation. Use refinery to remove thread-local fields turns the refinery off and on, and you can also adjust the queue sizes that it uses to hold onto events.
  • Use a spy thread to detect program termination causes Flashlight to spawn a thread on program start-up that periodically checks to see if any non-daemon threads are running and terminates the program when none are. It is not always necessary to run the spy thread, as Flashlight also listens to the run time shutdown event. Programs that do not explicitly terminate, for example by calling System.exit() may need it, though.

Preparing run data A sufficiently large Flashlight run may contain millions of objects. Scan window size determines how many of these objects we look at in one pass of the data file. Decreasing this number may allow you to prep a run with lower memory utilization at the cost of a slightly longer prep time. You can also specify whether or not you want to automatically prepare data once a running program has terminated.

Result querying Maximum rows returned lets you specify how many results you want to see returned by a single query. You may also change whether you are prompted once you have run enough queries to use up a significant amount of memory.

2.5. Flashlight launch configuration

Applications are executed with Flashlight instrumentation by using a special Eclipse "flashlight" run mode. Like executing your application using the Eclipse debugger, a special parallel set of "run" menus is used for this purpose. These menus are in three places in the Eclipse UI:

  • RunFlashlight in the Eclipse main menu.
  • The icon in the Eclipse toolbar.
  • Flashlight As in the Package Explorer context menu.

The Flashlight menu and the toolbar menu are identical. They show the last several application launches, which serve as shortcuts for rerunning those applications using Flashlight. They also provide menu items for explicitly editing Flashlight launch configurations.

The Flashlight As in the Package Explorer context menu is the same as the Flashlight As sub menu that appears under the Flashlight menu and the toolbar menu. When a class is selected in the Package Explorer that contains a public static void main(String[]) method, the menu item Java Application appears below Flashlight As. This executes the application defined by the class using Flashlight.

Flashlight presents a customized launch configuration dialog when the Open Flashlight Dialog… command is selected from any one of the Flashlight menus. The Flashlight launch configuration dialog is based on the standard Java launch dialog, but with four additional configuration panes between the standard Arguments and JRE panes:

  1. Instrumentation
  2. Data Collection
  3. Methods
  4. Fields

2.5.1. Instrumentation

The settings in the Instrumentation pane control which classes are actually rewritten by Flashlight to contain instrumentation. The pane is divided into three sections, see Figure 2.23:

  1. Classpath entries to instrument
  2. Bootpath entries to instrument
  3. Classes not to be instrumented

Figure 2.23. The Flashlight launch configuration Instrumentation pane.

The Flashlight launch configuration Instrumentation pane.

2.5.1.1. Classpath and Boothpath Entries to Instrument

The first section lists the entries on the application's classpath. The second section lists the entries on the application's boot classpath. These entries are taken directly from the settings in the standard Java Classpath configuration pane. When a new launch configuration is created, all the classpath entries are selected for instrumentation, while all the boot classpath entries, if any, are not selected for instrumentation. You can change these settings by checking or unchecking the items in the two lists. You might want to alter this settings, for example, if you do not want to instrument any library JAR files used by your application.

2.5.1.2. Classes Not to Be Instrumented

The third section lists those classes that should not be instrumented, even if they are located in a classpath/boot classpath entry whose contents are otherwise selected for instrumentation. Generally, you should not have to add any classes to this list. We have only found one case so far where adding a class to this was necessary: When the system class loader is changed by setting the system property java.system.class.loader as a JVM argument. For example, if -Djava.system.class.loader=com.aelitis.azureus.launcher.classloading.PrimaryClassloader is passed to the JVM, then you would have to add the class com.aelitis.azureus.launcher.classloading.PrimaryClassloader to the list of classes not to be instrumented.

To add a class to the list, click on the Add… button to bring up a class selection dialog. To remove one or more classes from the list, select the classes and click on the Remove button.

The class selection dialog is shown in Figure 2.24. To select a type, first enter a search pattern into the search field. By default the all the packages in the application will be searched, unless you include part of the package name as part of the pattern. The character * may be used a wildcard to represent zero or more elided characters. Press return to begin the search. The matching type names appear in the list below the Search status section. A long-running search can be cancelled by pressing the Cancel next to the status bar; on Mac OS X press the cancel icon on the search field instead. To choose a type, select a type from the list and press the OK button. Pressing Cancel closes the dialog without choosing a type.

Figure 2.24. The Class Selection Dialog

The Class Selection Dialog

2.5.2. Data collection

The settings in the Data Collection pane, see Figure 2.25, control how the collected data is saved to disk and how the collected data is processed before it is written to disk. The three sections of the pane, Store options, Data file options, and Data collection options, contain settings identical to those in the Instrumentation section of the Flashlight preferences pane. In fact, when a new Flashlight launch configuration is created, the initial values for these settings are taken from the corresponding settings in the preferences.

Figure 2.25. The Data Collection Pane

The Data Collection Pane

2.5.3. Methods

The settings in this pane specify the methods that Flashlight considers to be indirect access methods: methods that alter complex arrangements of state that should be considered to be part of an object passed as one of their parameters. The classic examples are the java.util collections classes. For example, the add() method of a Set object is usually implemented by adding the element to an underlying array, hash table or tree structure. But we are interesting in capturing the abstract effects of the operation, in particular that the state of the Set object used as the method receiver is accessed.

Flashlight uses a list of methods to identify those methods that indirectly access state of their object parameters. This list is maintained in two parts:

  1. A default list containing methods from the java.util collections classes, and several other standard library classes.
  2. User-specified lists of methods that identify additional indirect access methods that may be part of user-written code or library code.

The Methods pane, see Figure 2.26, accordingly has two parts:

  1. A checkbox indicating whether the default list of methods should be used.
  2. A list of files that declare additional indirect access methods. The format of these files is described in Section 2.6.

A new file is added to the list by clicking on the Add… button and selecting the file using the file browser. One or more files can be removed from the list by selecting the files in the list and clicking on the Remove button.

Figure 2.26. The Methods Pane

The Methods Pane

2.5.4. Fields

The settings in this pane control which field accesses in classes instrumented by Flashlight are actually instrumented to collect data. By changing these settings you can enable a more focused data collection by only collecting a subset of the field access information. This allows you to focus on the part of the application that is of interest at the moment without cluttering up the data file with information you are not interested in. This yields a smaller data file which, in turn, yields a faster data preparation time.

This pane has two sections, although the visibility of the second section depends on the setting in the first section. The first section, Instrument fields, see Figure 2.27, controls whether or not all field accesses are instrumented. There are three possible settings:

  • Instrument all field accessesFlashlight instruments all the field accesses in classes that have instrumentation.

  • Instrument accesses to fields declared in the selected packages onlyFlashlight instruments only those field accesses that refer to a field declared in a class declared in one of the selected packages. When selected, the second section of the pane that allows you to select packages is visible.

  • Instrument accesses to fields used in the selected packages onlyFlashlight instruments only those field accesses that occur in a class declared in one of the selected packages. When selected, the second section of the pane that allows you to select packages is visible.

Figure 2.27. The Fields Pane when Instrument all field accesses is selected

The Fields Pane when Instrument all field accesses is selected

The second section, Select packages, see Figure 2.28, is visible only if a choice other than Instrument all field accesses is selected. This section contains a list of the packages in the application. Select a package by clicking on its checkbox. The row of buttons above the list provide shortcuts for manipulating the selection:

  • Select AllCauses all of the packages to be selected.

  • Select NoneCauses none of the packages to be selected.

  • Invert SelectionCauses the selection to be inverted: those packages that were not selected become selected, and those that were selected become deselected.

Figure 2.28. The Fields Pane when Instrument all field accesses is not selected

The Fields Pane when Instrument all field accesses is not selected

2.6. Indirect access methods

Flashlight generates special access events when a method call has the capability of accessing state that is aggregated into one of its object parameters. This mostly comes into play with the methods of collection-style classes. Consider classes that implement Set. The Set methods read and write the contents of the abstract set represented by the object, but the semantics of these activities are generally lost on the analysis:

  • It is not usually desirable to instrument the classes from the standard Java library.
  • Even if you did, Flashlight would record events describing the manipulation of the arrays internal to the implementation of the set.

What you really want to know is that the method calls are causing accesses to the abstract contents of the set, so that you can determine if multiple threads are touching the set contents in a safe way.

Flashlight deals with this by generating one or more indirect access events when a method is called that utilizes a collection-like object. Flashlight knows which methods do this my consulting a list of what we call indirect access methods. The Flashlight distribution comes with a standard list the includes methods from the collection classes from java.util and a few other JDK classes. Flashlight can also read in additional user-defined lists of methods, see Section 2.5.3.

An indirect access method is identified based on the class in which it is declared. This class is compared against the class in the method call operation based on the "is assignable to" relationship: if the class in the method call operation is considered to be assignable to the class containing the indirect access method, then the classes match.

2.6.1. Default list of indirect access methods

ClassMethodIndirectly accesses the object(s) referenced by
java.lang.Iterableiterator()this
java.lang.Systemarraycopy(java.lang.Object src, int srcPos, java.lang.Object dest, destPos, int len)src, dest
setProperties(java.util.Properties p)p
java.util.AbstractListremoveRange(int from, int to)this
java.util.ArrayListArrayList(java.util.Collection c)c
clone()this
ensureCapacity(int c)this
trimToSize()this
java.util.ArraysasList(java.lang.Object[] a)a
binarySearch(byte[] a, byte k)a
binarySearch(char[] a, char k)a
binarySearch(double[] a, double k)a
binarySearch(float[] a, float k)a
binarySearch(int[] a, int k)a
binarySearch(java.lang.Object[] a, java.lang.Object k)a
binarySearch(java.lang.Object[] a, java.lang.Object, java.util.Comparator c)a
binarySearch(long[] a, long k)a
binarySearch(short[] a, short k)a
deepEquals(java.lang.Object[] a, java.lang.Object[] a2)a, a2
deepHashCode(java.lang.Object[] a)a
deepToString(java.lang.Object[] a)a
equals(boolean[] a, boolean[] a2)a, a2
equals(byte[] a, byte[] a2)a, a2
equals(char[] a, char[] a2)a, a2
equals(double[] a, double[] a2)a, a2
equals(float[] a, float[] a2)a, a2
equals(int[] a, int[] a2)a, a2
equals(java.lang.Object[] a, java.lang.Object[] a2)a, a2
equals(long[] a, long[] a2)a, a2
equals(short[] a, short[] a2)a, a2
fill(boolean[] a, boolean v)a
fill(boolean[] a, int from, int to, boolean v)a
fill(byte[] a, byte v)a
fill(byte[] a, int from, int to, byte v)a
fill(char[] a, char v)a
fill(char[] a, int from, int to, char v)a
fill(double[] a, double v)a
fill(double[] a, int from, int to, double v)a
fill(float[] a, float v)a
fill(float[] a, int from, int to, float v)a
fill(int[] a, int v)a
fill(int[] a, int from, int to, int v)a
fill(java.lang.Object[] a, java.lang.Object v)a
fill(java.lang.Object[] a, int from, int to, java.lang.Object v)a
fill(long[] a, long v)a
fill(long[] a, int from, int to, long v)a
fill(short[] a, short v)a
fill(short[] a, int from, int to, short v)a
hashCode(boolean[] a)a
hashCode(byte[] a)a
hashCode(char[] a)a
hashCode(float[] a)a
hashCode(double[] a)a
hashCode(int[] a)a
hashCode(java.lang.Object[] a)a
hashCode(long[] a)a
hashCode(short[] a)a
sort(byte[] a)a
sort(byte[] a, int from, int to)a
sort(char[] a)a
sort(char[] a, int from, int to)a
sort(double[] a)a
sort(double[] a, int from, int to)a
sort(float[] a)a
sort(float[] a, int from, int to)a
sort(int[] a)a
sort(int[] a, int from, int to)a
sort(java.lang.Object[] a)a
sort(java.lang.Object[] a, int from, int to)a
sort(java.lang.Object[] a, java.util.Comparator c)a
sort(java.lang.Object[] a, int from, int to, java.util.Comparator c)a
sort(long[] a)a
sort(long[] a, int from, int to)a
sort(short[] a)a
sort(short[] a, int from, int to)a
toString(boolean[] a)a
toString(byte[] a)a
toString(char[] a)a
toString(float[] a)a
toString(double[] a)a
toString(int[] a)a
toString(java.lang.Object[] a)a
toString(long[] a)a
toString(short[] a)a
java.util.BitSetand(java.util.BitSet s)this, s
andNot(java.util.BitSet s)this, s
cardinality()this
clear()this
clear(int i)this
clear(int from, int to)this
clone()this
equals(java.lang.Object o)this, o
flip(int i)this
flip(int from, int to)this
get(int i)this
get(int from, int to)this
hashCode()this
intersects(java.util.BitSet s)this, s
isEmpty()this
length()this
nextClearBit(int from)this
nextSetBit(int from)this
or(java.util.BitSet s)this, s
set(int i)this
set(int i, boolean v)this
set(int from, int to)this
set(int from, int to, boolean v)this
size()this
toString()this
xor(java.util.BitSet s)this, s
java.util.Collectionadd(java.lang.Object o)this
addAll(java.util.Collection c)this, c
clear()this
contains(java.lang.Object o)this
containsAll(java.util.Collection c)this, c
equals(java.lang.Object o)this, o
hashCode()this
isEmpty()this
remove(java.lang.Object o)this
removeAll(java.util.Collection c)this, c
retainAll(java.util.Collection c)this, c
size()this
toArray()this
toArray(java.lang.Object[] a)this, a
toString()this
java.util.CollectionsaddAll(java.util.Collection c, java.lang.Object[] a)c, a
binarySearch(java.util.List l, java.lang.Object o)l
binarySearch(java.util.List l, java.lang.Object o, java.util.Comparator c)l
copy(java.util.List l, java.util.List l2)l, l2
disjoint(java.util.Collection c1, java.util.Collection c2)c1, c2
enumeration(java.util.Collection c)c
fill(java.util.List l, java.lang.Object v)l
frequency(java.util.Collection c, java.lang.Object o)c
indexOfSubList(java.util.List l, java.util.List target)l, target
lastIndexOfSubList(java.util.List l, java.util.List target)l, target
list(java.util.Enumeration e)e
max(java.util.Collection c)c
max(java.util.Collection c, java.util.Comparator cmp)c
min(java.util.Collection c)c
min(java.util.Collection c, java.util.Comparator cmp)c
replaceAll(java.util.List l, java.lang.Object oldVal, java.lang.Object newVal)l
reverse(java.util.List l)l
rotate(java.util.List l, int d)l
shuffle(java.util.List l)l
shuffle(java.util.List l, java.util.Random r)l
sort(java.util.List l)l
sort(java.util.List l, java.util.Comparator c)l
swap(java.util.List l, int i, int j)l
java.util.Dictionaryelements()this
get(java.lang.Object k)this
isEmpty()this
keys()this
put(java.lang.Object k, java.lang.Object v)this
remove(java.lang.Object k)this
size()this
java.util.EnumerationhasMoreElements()this
nextElement()this
java.util.EnumMapEnumMap(java.util.EnumMap m)this
EnumMap(java.util.Map m)this
put(java.lang.Enum e, java.lang.Object v)this
java.util.EnumSetclone()this
complementOf(java.util.EnumSet s)s
copyOf(java.util.Collection c)c
copyOf(java.util.EnumSet s)s
of(java.lang.Enum e, java.lang.Enum[] a)a
java.util.HashMapHashMap(java.util.Map m)m
java.util.HashSetHashSet(java.util.Collection c)c
java.util.HashtableHashtable(java.util.Map m)m
clone()this
contains(java.lang.Object o)this
rehash()this
java.util.IdentityHashMapIdentityHashMap(java.util.Map m)this
java.util.IteratorhasNext()this
next()this
remove()this
java.util.LinkedHashMapLinkedHashMap(java.util.Map m)m
removeEldestEntry(java.util.Map$Entry e)this
java.util.LinkedListLinkedList(java.util.Collection c)c
addFirst(java.lang.Object o)this
addLast(java.lang.Object o)this
clone()this
getFirst()this
getLast()this
removeFirst()this
removeLast()this
java.util.Listadd(int i, java.lang.Object o)this
addAll(int i, java.util.Collection c)this, c
get(int i)this
indexOf(java.lang.Object o)this
lastIndexOf(java.lang.Object o)this
listIterator()this
listIterator(int i)this
remove(int i)this
set(int i, java.lang.Object o)this
subList(int begin, int end)this
java.util.ListIteratoradd(java.lang.Object o)this
hasPrevious()this
nextIndex()this
previous()this
previousIndex()this
set(java.lang.Object o)this
java.util.Mapclear()this
containsKey(java.lang.Object k)this
containsValue(java.lang.Object v)this
entrySet()this
equals(java.lang.Object o)this, o
get(java.lang.Object k)this
isEmpty()this
keySet()this
put(java.lang.Object k, java.lang.Object v)this
putAll(java.util.Map m)this, m
remove(java.lang.Object o)this
size()this
toString()this
values()this
java.util.Map$Entryequals(java.lang.Object o)this, o
getKey()this
getValue()this
hashCode()this
setValue(java.lang.Object v)this
java.util.PropertiesProperties(java.util.Properties p)p
getProperty(java.lang.String k)this
getProperty(java.lang.String k, java.lang.String d)this
list(java.io.PrintStream ps)this
list(java.io.PrintWriter pw)this
load(java.io.InputStream is)this
loadFromXML(java.io.InputStream is)this
propertyNames()this
save(java.io.OutputStream os, java.lang.String c)this
setProperty(java.lang.String k, java.lang.String v)this
store(java.io.OutputStream os, java.lang.String c)this
storeToXML(java.io.OutputStream os, java.lang.String c)this
storeToXML(java.io.OutputStream os, java.lang.String c, java.lang.String e)this
java.util.Queueelement()this
offer(java.lang.Object o)this
peek()this
poll()this
remove()this
java.util.SortedMapfirstKey()this
headMap(java.lang.Object to)this
lastKey()this
subMap(java.lang.Object from, java.lang.Object to)this
tailMap(java.lang.Object from)this
java.util.SortedSetfirst()this
headSet(java.lang.Object to)this
last()this
subSet(java.lang.Object from, java.lang.Object to)this
tailSet(java.lang.Object from)this
java.util.Stackempty()this
peek()this
pop()this
push(java.lang.Object o)this
search(java.lang.Object o)this
java.util.TreeMapTreeMap(java.util.Map m)m
TreeMap(java.util.SortedMap m)s
java.util.TreeSetTreeSet(java.util.Collection c)c
TreeSet(java.util.SortedSet s)s
clone()this
java.util.VectorVector(java.util.Collection c)c
addElement(java.lang.Object o)this
capacity()this
clone()this
copyInto(java.lang.Object[] a)this, a
elementAt(int i)this
elements()this
ensureCapacity(int c)this
firstElement()this
indexOf(java.lang.Object o, int i)this
insertElementAt(java.lang.Object o, int i)this
lastElement()this
lastIndexOf(java.lang.Object o, int i)this
removeAllElements()this
removeElement(java.lang.Object o)this
removeElementAt(int i)this
setElementAt(java.lang.Object o, int i)this
setSize(int s)this
trimToSize()this
java.util.WeakHashMapWeakHashMap(java.util.Map m)m

2.6.2. File format

A list of indirect access methods is maintained as an XML file defined by the following DTD:

<!ELEMENT classes (class+)> 

<!ELEMENT class (method+)>
<!ATTLIST class name CDATA #REQUIRED>

<!ELEMENT method (arg+)>
<!ATTLIST method 
  isStatic (true|false) "false"
  signature CDATA #REQUIRED> 

<!ELEMENT arg (#PCDATA)>

The root element of each file is the classes element. This element has no attributes. It has one or more nested class elements.

Each class element represents a class that contains at least one indirect access method. The element has a required attribute name whose value is the fully qualified name of the class. The element has one or more nested method elements. A class names methods that it declares only. There is no need to name a method that is inherited or overridden. Those methods are declared in a class element for the ancestor class.

Each method element identifies a method that makes indirect access to state encapsulated in at least one of its parameters. The element has an optional Boolean-valued isStatic attribute, whose default value is false, that indicates whether the method is static or not. The element has a mandatory signature attribute, whose value is the name and signature of the method. The format of the signature is

TypeReturn name(Type1, …, Typen)

Where

  • Each Type must be a Java primitive type (boolean, byte, char, short, int, long, float, or double) or the fully qualified name of a Java class/interface.
  • name is the name of the method. Constructors are named "<init>", written "&lt;init&gt;".

The element has one or more nested arg elements.

Each arg element contains a single a integer value representing the index of an argument to the method whose aggregated state may be accessed indirectly by the method. The index is zero based:

  • If the method is not static then 0 refers to the method's receiver and 1 refers to the first explicit argument.
  • If the method is static then 0 refers to the method's first explicit argument.

2.6.2.1. Example

The following is a fragment of the default list of methods showing methods from the ArrayList class and the System class:

<classes>
  ...
  <class name="java.util.ArrayList">
    <method signature="void &lt;init&gt;(java.util.Collection)">
      <arg>1</arg>
    </method>

    <method signature="void trimToSize()">
      <arg>0</arg>
    </method>

    <method signature="void ensureCapacity(int)">
      <arg>0</arg>
    </method>

    <method signature="java.lang.Object clone()">
      <arg>0</arg>
    </method>
  </class>
  ...
  <class name="java.lang.System">
    <method signature="void arraycopy(java.lang.Object, int, java.lang.Object, int, int)" isStatic="true">
      <arg>0</arg>
      <arg>2</arg>
    </method>

    <method signature="void setProperties(java.util.Properties)" isStatic="true">
      <arg>0</arg>
    </method>
  </class>
</classes>

2.7. Troubleshooting

This section contains several tips on solving problems when using Flashlight that are due to odd or unusual configuration or API use within the program you are trying to collect data about.

  1. Nested Class Folders. It is possible to construct a classpath that, while it may compile in Eclipse, is too ambiguous for Flashlight to correctly instrument. In this case, Flashlight will display something like the following message:

    Classpath entry workspace/project is instrumented and nests the instrumented classpath directory entry workspace/project/foo  
       Plug-in Vendor: SureLogic, Inc.
       Plug-in Name: SureLogic Non-User Interface Eclipse Common Code
       Version: 4.0.0.qualifier
       Plug-in ID: com.surelogic.common.core
              

    This happens when the Eclipse .classpath contains one or more entries that are nested directories of another entry. It would be difficult or impossible for Flashlight to instrument the project's classfiles correctly in this situation, so it complains about the problem instead. You can fix this problem by altering your project's classpath, or by selectively instrumenting the code from the instrumentation tab of the Flashlight Launch Configuration view.

  2. Unexpected Stack or Stack Trace.  Flashlight works hard to transform your program while preserving its original behavior. A program that makes extensive use of reflection may notice Flashlight, however. Programs that make use of java.lang.SecurityManager.getClassContext() or similar method calls that work by inspecting the current execution stack can run into trouble, as Flashlight wraps many method calls in the classes that it instruments. Methods such as java.lang.SecurityManager.checkAccess() should still work, however, as Flashlight does not instrument the standard library by default.

2.8. Inference of Promise annotations

Flashlight can make it easier to get started assuring your program in JSure. The data from one or more runs can be used to generate a basic set of annotations. This can be done by selecting FlashlightInfer JSure Annotations from the main menu, as shown in Figure 2.29. Alternatively, you can select one or more runs in the Flashlight Runs view and then choose Infer JSure Annotations from the context menu.

Figure 2.29. Infer JSure Annotations

Infer JSure Annotations

You will then be prompted to choose a project, and one or more runs belonging to that project. Flashlight will then crawl through the run, looking for regions of data that are always protected by a lock. Once it has these collected, it generates the appropriate @Region and @RegionLock annotations. The refactored code is then presented as shown in Figure 2.30.

Figure 2.30. Infer JSure Annotations

Infer JSure Annotations

If JSure is installed, Flashlight will also focus verification on the chosen project and prompt you to add the promises jar to the project, if it does not exist already.

2.9. The Flashlight data directory

The Flashlight Eclipse plug-in writes the flashlight profile data files and other information in a location known as the "Flashlight Data Directory." This directory location is shown in the Flashlight preferences pane, as described in Section 2.4. The directory is called .flashlight-data and is located in the root of your current Eclipse workspace.

2.9.1. Per-run directories

Each run of an instrumented application in Eclipse creates a new "per-run directory" in the Flashlight data directory. The name of each per-run directory is given by the template fully-qualified-main-class-name-yyyy.MM.dd-'at'-HH.mm.ss.SSS-Platform, where

  • fully-qualified-main-class-name is the fully qualified class name of the class that contains the main method of the application.
  • -yyyy.MM.dd-'at'-HH.mm.ss.SSS is a Java date format template. The date template is filled in using the time the application was executed.
  • Platform is the platform the run happened on, either Java or Android.

For example, an instrumented run of the main class com.surelogic.fluid.javac.Util might yield the per-run directory com.surelogic.fluid.javac.Util-2008.09.30-at-14.16.55.411-Java.

Each per-run directory contains

  • Files generated during the instrumentation process.

  • Zip archives of the source code of the application.

  • JAR files of the instrumented class files.

  • The Flashlight data file gathered during execution, and any additional log file it may have generated.

More specifically, at the top-level, each per-run directory runDir contains the files

  • checkpoint.xxxxxx.fl.gz The checkpoint files contain collected data from the run of the program, and are sequentially numbered.

  • checkpoint.xxxxxx.complete Once a checkpoint file has been recorded completely, a .complete file is created to indicate that it is valid.

  • instrumentation.logLog file from the instrumentation process.

  • runtime.logLog file from the running, fully instrumented program.

The per-run directory also contains three top-level directories

  • instrumentationThis directory contains the collected output of the instrumentation process. This includes the following files and folders:

    • fields.txtThe fields database file generated by the instrumentation process. This is a text file that associates each field declared in one of the instrumented classes with a unique identifier. Each line is of the format

      <32-bit integer id> <fully-qualified-class-name> <field name> <isStatic> <isFinal> <isVolatile>

    • sites.txt.gzThe gzipped sites database file generated by the instrumentation process. This is a text file that assigns a unique identifier to each program location where something of interest to Flashlight occurs. Each line of the file is of the format

      <64-bit integer id> <source file name> <class name> <method name> <source line number>

    • class_hierarchy.txt.gzThe gzipped class hierarchy database file generated by the instrumentation process. This is a text file that assigns a unique identifier to each program location where something of interest to Flashlight occurs. Excepting the first line of the file, which indicates how many entries there are, each line of the file is of the format

      <class name id> <number of parents> <parent classes>...

    • external.  This directory contains instrumented JAR files corresponding to JAR files that are normally located outside of any project in the Eclipse workspace. These arise from Eclipse class path variables that are used to refer to things like ANT_HOME, which would normally be a directory in the user's file system, or JUNIT, which refers to a JAR file in an Eclipse plug-in.

    • projects. This directory contains JAR files holding the instrumented class files of the instrumented application.

  • prepThis directory contains data produced by the postmortem tool during the prep phase, including the database supporting the Eclipse query tool.

  • sourceThis directory contains zip files of the source code of the instrumented application.

2.9.2. Deleting Flashlight data

After using Flashlight for a while, you may find that your Flashlight data directory is getting quite large. The easiest way to reduce the size of your data directory is to delete runs you no longer need from the Flashlight Runs view. A run can also be removed by deleting the directory directly from the Flashlight data directory. Both methods will remove all prepared data from this run as well, so make sure that you are completely done with the run before deleting it.

2.10. Queries

Flashlight ships with a large number of queries accessible through the Flashlight perspective. For more information about how to use the Flashlight perspective, see Section 2.2. Documentation for all queries can also be found in the Flashlight perspective, using the Querydoc view documented in Section 2.2.6. For a tutorial on how to use the provided queries effectively, see Section 1.3.

2.10.1. Identifiers

The Flashlight queries identify declared and run-time Java entities using the following conventions:

  • Packages. Packages are referred to exactly as they are declared in a Java source file. The default unnamed package is referred to as (default).

  • Classes. Classes are referred to using their unqualified name, based on the name of the class file generated by the Java compiler. More specifically, top-level Java classes are referred to just as they appear in the class declaration. Nested types are prefixed by their parent class name and the $ character. Anonymous classes are numbered in the order they appear in the declaring file. As an example, the following compilation unit declares three classes: Foo, Foo$Bar, and Foo$1, all of them in package (default).

    import java.util.Comparator;
    
    public class Foo {
    	static class Bar {
    	}
    	Comparator<String> baz = new Comparator<String>() {
    		@Override
    		public int compare(String o1, String o2) {
    			return o1.compareTo(o2);
    		}
    	};
    }

  • Objects and Locks. Every object created in an instrumented Java program is assigned a numeric identifier which is used to refer to it for the duration of the program. In query results, objects are referred to using their numeric identifier prefixed by their class name. For example, if the Comparator in the above listing of code was assigned the number 5, then the object would be referenced as Foo$1-5. Because locks are just regular Java objects, Flashlight refers to locks using their object identifiers.

  • Threads. Threads are referred to by their name, as returned by Thread.getName(). If more than one thread in the program has the same name, then they are disambiguated by assigning a sequence number and referring to them by that as well. For instance, if a program has two threads named WorkerThread then Flashlight would refer to them as WorkerThread and WorkerThread (1).

  • Methods. Methods are referred to by their declared name. Flashlight also displays object and class initializers as methods in stack traces and the like. Constructors are named <init>; class initializers are named <clinit>.

2.11. Using Flashlight with Android

You can use Flashlight in collaboration with version 21.0.0 of Google's Android Development Tools (ADT). If you do not have the Android SDK and ADT installed, you can get it by following the instructions here.

[Note]Do not terminate Android applications too quickly

The data collection infrastructure flushes data off the Android device roughly every three seconds. Therefore, it is a good idea to let the application sit for several seconds before you close it on the phone and then terminate it.

2.11.1. Running Flashlight

Enable Network Access. In order for Flashlight to collect data from your Android application, you will need to give your application permission to access your phone's network. You can do this by adding the following to your AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET"/>

The Android Manifest Editor also allows you to add this permission in the Permissions tab.

Figure 2.31. Configure the application's permissions

Configure the application's permissions


Launch The Application.  The simplest way to launch the application is to right-click on the project and choose Flashlight AsAndroid Application. Launch Android Application.

Figure 2.32. Launch Flashlight from the Flashlight As menu

Launch Flashlight from the Flashlight As menu


You can also use the create, configure, and run Android Applications from the Flashlight Launch Configuration view. See Section 2.5 for more details.

Figure 2.33. Create and manage a run configuration from the Flashlight Configuration View

Create and manage a run configuration from the Flashlight Configuration View


2.11.2. Stopping Flashlight

The simplest approach is to use the Flashlight Launched Run Control dialog. This will not stop the application on the Android device or emulator but will stop data collection and prepared the data for querying. Data collection is stopped for a particular instrumented Android run by pressing the to the far right of that run in the dialog.

Figure 2.34. Terminating data collection the Flashlight Launched Run Control dialog

Terminating data collection the Flashlight Launched Run Control dialog

Another approach is to stop the application on the Android device itself. Depending on your application, you may need to close the program yourself. How you do this depends on the and version of Android that you are using. Later versions of Android have a Application Monitor widget that is suitable for this purpose. Alternatively, you can leave the program running and manually terminate the instrumentation using the runtime console.

Figure 2.35. Terminating the application from the Application Monitor

Terminating the application from the Application Monitor

Figure 2.36. Terminating Flashlight Instrumentation from the Runtime Console

Terminating Flashlight Instrumentation from the Runtime Console

2.11.3. Launching Packaged Android Applications (APK)

Any Android APK may be launched from the Flashlight main menu as shown in Figure 2.37.

Figure 2.37. Launching a packaged Android application (binary APK) from the Flashlight main menu

Launching a packaged Android application (binary APK) from the Flashlight main menu

There are a number of approaches to get an APK file, these are discussed in the following paragraphs.

Using an Application.  There are a number of tools that allow you to get at the APK files sitting on your Android device. One such tool is Apk Extractor, which is available on Google Play here. Apk Extractor allows you to extract the APK file corresponding to any application installed on your Android device. The file can then be mailed to you or saved to the device's SD card for easy extraction later.

From an Android project. Any Eclipse Android project can produce a signed APK suitable for instrumentation by right-clicking on the project from the Project Explorer view and choosing Android ToolsExport Signed Application Package... as shown below

From a project website. Many open source applications have a project website that makes their APK file publicly available. For example, builds of connectbot—an ssh client—and tomdroid—a notekeeping application—can be found at google code and launchpad.net respectively.

2.12. Using Ant

The Flashlight Ant task can can instrument a JAR or WAR to produce Flashlight results when the JAR or WAR is run. After the program is run, the output is a directory thatt can be loaded into Eclipse to examine its results. You load the run data into Eclipse using the Import Ant/Maven Scan... on the Flashlight menu. Once loaded into Eclipse the Flashlight run can be prepared and queried just like like any other run launched within Eclise. Note the the Ant task only works with Java and cannot (yet) be used to instrument an Android APK outside of Eclipse.

The Ant tasks are not included within the Eclipse plugin (to save space) but can be downloaded here on the SureLogic website.

Note that you must run this task in a Java 7 VM (it can analyze any code).

2.12.1. flashlight-instrument-archive task

This task instruments a JAR or WAR and produces another JAR or WAR. The attributes are:

AttributeDescriptionRequired
srcfile This attribute sets the path to the JAR or WAR to instrument. This file is not changed by the task. srcfile="server.jar" Yes
destfile This attribute sets set the output JAR or WAR to create (or overwrite). destfile="flserver.jar" Yes
runtime This attribute sets location of the flashlight runtime. Normally this is set by a property in your script. runtime="${flashlight.runtime}" Yes

For a concrete example, please see the tutorial in Section 1.3.4.

2.13. Using Maven

A Maven task for Flashlight is still under development. A workaround is to use Ant within Maven as discussed here and here.

2.14. Bugs and tips

Flashlight allows any user to send problem reports and suggestions to SureLogic from the main menu. Selecting Send Tip for Improvement or Send Problem Report allows a tip or problem report to be send to SureLogic directly within Eclipse as shown in Figure 2.38. These menu choices bring up dialogs that allow the user to control exactly what information is sent to SureLogic. In addition, the user can preview the exact text that will be sent over the internet.

Figure 2.38. Menu items to send bugs and tips to SureLogic

Menu items to send bugs and tips to SureLogic

The Send Tip for Improvement command opens a dialog to allow entry of a suggestion by the user to improve the Flashlight tool as seen in Figure 2.39. The dialog allows the user to control exactly what information is sent to SureLogic. In addition, the user can preview and edit the exact text that will be sent. If you have no Internet connection you can print or save the text of your problem report (to fax or email).

Figure 2.39. Dialog allowing the user to enter a tip to improve Flashlight

Dialog allowing the user to enter a tip to improve Flashlight

The Send Problem Report command opens a dialog to allow entry of a problem report by the user about the Flashlight tool as seen in Figure 2.40. The dialog allows the user to control exactly what information is sent to SureLogic. In addition, the user can preview and edit the exact text that will be sent. If you have no Internet connection you can print or save the text of your problem report (to fax or email).

Figure 2.40. Dialog allowing the user to enter a problem report about Flashlight

Dialog allowing the user to enter a problem report about Flashlight

Messages sent from these dialogs go over HTTP to SureLogic. If a proxy is used on your network then it is critical to configure Eclipse to use it. To do this open the Eclipse Preferences and examine the Network Connections under the General preferences. This dialog allows you to configure Eclipse for your network as shown in Figure 2.41.

Figure 2.41. Eclipse preferences for network connections within the IDE

Eclipse preferences for network connections within the IDE

Chapter 3. Release notes

For each release of Flashlight there are new and noteworthy features to try out, and known limitations to avoid or workaround. These are presented in the sections below for each released version of Flashlight.

3.1. Flashlight version 5.6.0

This section describes the 5.6.0 version of Flashlight.

3.1.1. New and Noteworthy

This section describes new and noteworthy features in this version of Flashlight.

  1. Improved happens-before analysis — This release of Flashlight can now detect happens-before events for util.concurrent Executors as well as Android AsyncTasks and Handlers.

  2. Instrumented Android tests — This release of Flashlight allows you to launch tests on Android projects. This allows Flashlight to be used on automated device integration tests such as robotium.

  3. Flashlight Launched Control dialog updated — The Flashlight Launched Run Control dialog has been reconfigured to be easier to use. It now includes a Close button which, while generally useful to dismiss the dialog, was most needed on OS X.

3.2. Flashlight version 5.5.0

This section describes the 5.5.0 version of Flashlight.

3.2.1. New and Noteworthy

This section describes new and noteworthy features in this version of Flashlight.

  1. Java 8 language and virtual machine support — This release of Flashlight fully supports the Java 8 programming language and virtual machine. The tool also supports running older Java programs on a Java 8 virtual machine. To launch Java 8 programs a version of Eclipse that supports Java 8, e.g., Eclipse Luna (4.4) or above, is required.

  2. New query to detect multiple acquisitions and releases of the same lock within a method — This release of Flashlight has a new query What methods acquire locks in more than one place? which is useful for uncovering potential locking problems. In particular, if a lock is released and then reacquired during a method it could indicate that a class-level invariant is not established and some other code could see the object in an "in-between" state.

    Because Flashlight does not understand the invariants that must be maintained in your code, this query may not be precise for all systems. But it can be useful in uncovering subtle locking problems.

3.3. Flashlight version 5.4.0

This section describes the 5.4.0 version of Flashlight.

3.3.1. New and Noteworthy

This section describes new and noteworthy features in this version of Flashlight.

  1. Binary Android APK Launch Support — A new Flashlight menu item has been added to launch binary Android applications on an Android device. Binary Android applications are contained within an APK file.

    This release is the first that makes this capability accessible from the tool menu. Note that you must have the ADT loaded in your Eclipse and load the "Flashlight Client Android (Optional)" feature when you install the SureLogic tools.

    The only limitation we are aware of with this new feature is that you cannot use it to "overwrite" default-, root-, or vendor-installed applications on your phone. The apps included in this set vary from carrier to carrier — but typically includes GMail, Camera and some other applications. We are currently investigating approaches to avoid this limitation.

    For more information please see Section 2.11.3.

  2. Duration totals corrected — A bug that caused the total duration reported in several Flashlight queries to be incorrect has been fixed in this release. An example is highlighted in the image below.

3.4. Flashlight version 5.1.0

This section describes the 5.1.0 version of Flashlight.

3.4.1. New and Noteworthy

This section describes new and noteworthy features in this version of Flashlight.

  1. Dynamic analysis instrumentation made more concurrent to reduce overhead — This release contains several changes to the dynamic analysis data store used by Flashlight to collect data from both standard Java programs and Android applications. These changes reduce the overhead of the tool's instrumentation for most applications.

3.5. Flashlight version 5.0.0

This section describes the 5.0.0 version of Flashlight.

3.5.1. New and Noteworthy

This section describes new and noteworthy features in this version of Flashlight.

  1. Query Results shows good and bad news about the selected run — The Query Results view now shows either (a) an overview of the run currently selected in the Flashlight Runs view or (b) query results as a table, tree or tree-table. What is new is the lists of good and bad news items about the selected run. These news items are not definitive, because they represent information from a single run of the program—hence the name news instead of results. Some news items are underlined. These underlined news items may be selected with the mouse to invoke a query and show the news item's corresponding results. Some news items are not underlined because they indicate that no information was observed during the run—in these cases no results indicates something newsworthy. These items that are not underlined have no associated results.

    The screenshot below shows an example of good and bad news about a run of the FlashlightTutorial_CounterRace Android application.

  2. Major changes to tool queries — The set of queries and sub-queries available in Flashlight has been significantly changed. These changes make the tool easier to use and more actionable. In particular, these changes make it easier to get to stack traces and lock traces and, therefore, link an analysis result to your code.

  3. Stack and lock traces are now unique — Flashlight now identifies each stack and lock trace uniquely. This changes the way many queries are reported. The problem which could occur in past versions of Flashlight is that a query could result in hundreds of rows. Now queries can group by distinct stack trace or lock trace and dramatically reduce the on-screen clutter. The updated queries present more information to the user in a concise manner.

    As an example, the screenshot below shows the query results about where the field f_threadLocalCounts is accessed in the code.

    The result is grouped by unique path to the access—or unique stack trace. This result is three rows, in the previous release of Flashlight this result would have been 1,874 rows. In addition, this result conveys at a glance more about the use of the f_threadLocalCounts field by the program. In particular, the field is initialized in the main thread, passed to Thread-272 where it is thread confined for almost a second, then, finally, read again by the main thread. This insight would be hard to obtain from a list of 1,874 accesses.

Bibliography

[1] Chet Haase and Romain Guy. Filthy Rich Clients. Developing Animated and Graphical Effects for Desktop Java Applications. Prentice Hall PTR. 2007.