I haven’t written in my blog for a while, but again, that doesn’t mean I didn’t do anything. I did a lot, actually.
Corky — my advisor — and I decided we’re going to change the course slightly. Instead of using Lamport clocks for replay, we’ll try to record just raw synchronization points. That means I don’t have to introduce a unique ID into each object (something with which I had major problems), only a unique thread ID into the Thread
class (something I already knew how to do).
This allowed me to write an instrumentation strategy that uses a compact buffer of long
s. Right now, I use pairs of long
s comprised of the event code (1 = monitorenter
, 2 = monitorexit
) and the thread ID. Later I can either merge the two into a single long
, or ideally dispose of the code entirely. In the interest of safety, right now I keep track of what code it is, just as a sanity check. And that was a good thing, as I’ll explain in a second.
I then started to write the replay strategy. There’s a GUI launcher now that runs the program in the client VM and loads the synchronization points into the buffer whenever the client VM runs out. The log of synchronization points right now simply is a text file with the number pairs and some slash-slash comments. The synchronization points that were recorded before the main method was entered are included but commented out:
// -- VM Started -- // Note: getting updated thread list from VM // 3: put // 4: put // 1: put // Note: Attempting to process sync points - VM start // Total number of compact sync points so far: 5 // 2 0 // 1 3 // 2 3 // 1 3 // 2 3 // Note: Finished processing sync points - VM start // Note: Updating sync points. edu.rice.cs.cunit.SyncPointBuffer.transfer or compactTransfer entered by thread id 1 // Note: Attempting to process sync points - push // Total number of compact sync points so far: 261 ... // Note: Finished processing sync points - main entered // Note: Attempting to process sync points - main exited // Total number of compact sync points so far: 2363 2 0 1 0 2 0 1 0 ... 2 0 2 0 2 0 // Note: Finished processing sync points - main exited // -- The application exited -- // Total number of compact sync points: 2363
Before I began to implement the actual replay algorithm, which I’ll describe in another post in more detail, I wanted to write a sanity check, so I compared the synchronization points in the buffer to the ones the program actually executed, expecting them to be the same.
For some strange reason, the synchronization points that were recorded begin with 231 synchronization points that are not found in the synchronization points that are found during replay. After those 231 synchronization points, the two lists match up. Then, at the end, there are 8 synchronization points (all by thread ID 9 — don’t yet know which thread that is) that are only found during replay. Just as a visualization, a diff
of the two lists looks like this:
231 sync points (thread ID 0) only found during record ... matching sync points ... 8 sync points (thread ID 9) only found during replay
For a while I thought that because I used the String
class to send the error messages to the master VM during replay, the String
class had to be initialized and that changed the order of synchronization points. Unfortunately, this just turned out to be false.
I have to admit right now I’m clueless why this is happening. On the other hand, it’s encouraging that the two lists match up except for those two blocks at the beginning and the end.