...
- one at the start of the method and (method start)
- one at the end of the method (method end)
This functionality can easily be integrated by means of instrumenting the methods with before and after hooks. Additional identification of the methods are not necessary as the invocations within the thread are always synchronous and thus the stack of the invocations will easily allow to reconstruct the invocation sequence.
...
M1 start | M2 start | M2 end | M3 start | M3 end | M1 end |
Inter-Thread
Problems that need to be solved:
- Correlation of the per se independent invocation sequences of two (or more threads)
- Identification which methods within the calling thread invoked a method within the called thread.
Basic: Inter-Thread invocation sequences should provide the location within the invocation that creates the asynchronous call.
Approach 1
Idea: Creation of a Runnable object identifies the location which initializes the asynchronous call to another thread
- The creation of a Runnable is an additional event that can be added to the
- We need to instrument the creation of a Runnable object and provide the following information
- the current thread identification of the current thread that created the Runnable
- the counter of how many asynchronous calls were already started within this thread
Scenario:
This scenario should help to describe this approach. Our calling thread has stack that is unique for this Runnable/Thread (see chapter about inner thread invocation sequences). Within this stack the creation of a Runnable is added.
M1 start | M2 start | Runnable (cur thread id, 1) | M2 end | Runnable (cur thread id, 2) | M1 end |
So our m1 method within the thread first invokes the method m2, then we encounter a Runnable object being instantiated, which we understand as the start of an asynchronous call. Then method M2 terminates. After that method m1 starts another asynchronous call and returns. Each creation of a Runnable adds the information about the current thread we are in and the order / number of this asynchronous invocation.
Lets have a look at the first Runnable. Here our first thread called the method M5
M5 start | M6 start | M6 end | M5 end |
Braindump
- Each thread has a unique number (per JVM) automatically assigned
- But threads can and - in fact are - reused. For example thread pools do not instantiate new threads, but instead pass different Runnable instances to the existing threads. Each different runnable is itself a different functionality. Thus the thread ID cannot be safely used for identification
- To build up an invocation sequence, each invoked method must know the method that was invoked before it
- Innerthread communication can simply make use of the ThreadLocal pattern and build a stack of the concrete methods being called
- Interthread and inter JVM communication has to connect the stacks of the involved threads. This can be done by an invocation identifier that is passed from the caller to the callee.
- Invocation identifier must also include the method identification that invoked this call
- Continuous sending of information
- Each method needs to have a thread-wide identification (stored within the stack)
- Each invocation of a method must refer to the parent invocation
- CMR server can match its current call tree with the information sent by the agent. Based on the invocation identification it will find the correct sequence. it will use the method identification to complete the tree
...