158 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
--- Channels ---
 | 
						|
 | 
						|
As the emulation progresses, information is written in the PRV trace to record
 | 
						|
the new states. The emulator has specific mechanism to handle the output of new
 | 
						|
states in the PRV trace via channels. A channel stores an integer that
 | 
						|
represents an state at a given point in time and corresponds to the value that
 | 
						|
will be observed in the Paraver timeline.
 | 
						|
 | 
						|
  NOTE: In general, the emulator receives events, then performs a state
 | 
						|
  transition and the new state (or states) are written into the PRV file.
 | 
						|
 | 
						|
There are two classes of channels: CPU and thread channels. Both CPU and threads
 | 
						|
have the same fixed number of channels, given by the enumeration `enum chan`.
 | 
						|
 | 
						|
For example the CHAN_OVNI_STATE of the thread stores the execution state of the
 | 
						|
thread (running, paused ...). Whereas, the CPU channel CHAN_OVNI_NRTHREADS
 | 
						|
records how many running threads a given CPU has.
 | 
						|
 | 
						|
The channels are used in the following way:
 | 
						|
 | 
						|
1) In the "pre" phase, the emulator modifies the state of the emulator based on
 | 
						|
the new event. The channels are then updated accordingly in this phase, for
 | 
						|
example when a thread goes from running to paused it must update the
 | 
						|
CHAN_OVNI_STATE channel of the thread by also the CHAN_OVNI_NRTHREADS channel of
 | 
						|
the CPU.
 | 
						|
 | 
						|
2) In the "emit" phase, the emulator calls the chan_emit() method on those channels
 | 
						|
that have been modified. Those have the dirty attribute set to 1.
 | 
						|
 | 
						|
3) The optional "post" phase is used to perform some operations before the next
 | 
						|
event is loaded, but is not commonly used.
 | 
						|
 | 
						|
Then the emulator then loads the next event and repeats the process again.
 | 
						|
 | 
						|
-- Disabling and enabling channels --------------------------------------------
 | 
						|
 | 
						|
Some channels provide information that only makes sense in some conditions. For
 | 
						|
example, the CPU channel CHAN_OVNI_TID tracks the TID of the thread currently
 | 
						|
running in the CPU. When there is no thread running or there are multiple
 | 
						|
threads running in the same CPU, this channel cannot output valid information.
 | 
						|
 | 
						|
For those cases, the channels can be enabled or disabled as to only provide
 | 
						|
information when it is necessary. When a channel is disabled, it will emit the
 | 
						|
value stored in `badst` which by default is set to 0.
 | 
						|
 | 
						|
Notice that if a channel was in a given state A, and was disabled, it must emit
 | 
						|
the new state is 0. When the channel is enabled again, it will emit again the
 | 
						|
state A.
 | 
						|
 | 
						|
-- Thread tracking channels ----------------------------------------------------------
 | 
						|
 | 
						|
Regarding thread channels, there are two common conditions that cause the
 | 
						|
channels to become disabled. When the thread is no longer running, and then the
 | 
						|
thread is not active.
 | 
						|
 | 
						|
For those cases, the thread channels can be configured to automatically be
 | 
						|
enabled or disabled, following the execution state of the thread. The tracking
 | 
						|
mode specifies how the tracking must be done:
 | 
						|
 | 
						|
- CHAN_TRACK_NONE: nothing to track
 | 
						|
- CHAN_TRACK_RUNNING_TH: enable the channel only if the thread is running
 | 
						|
- CHAN_TRACK_ACTIVE_TH: enable the channel only if the thread is running,
 | 
						|
  cooling or warming.
 | 
						|
 | 
						|
This mechanism removes the complexity of detecting when a thread stops running,
 | 
						|
to update a channel of a given module. As the thread state changes as handled by
 | 
						|
the emu_ovni.c module only.
 | 
						|
 | 
						|
-- CPU tracking channels ------------------------------------------------------
 | 
						|
 | 
						|
Similarly, CPU channels can also be configured to track the execution state of
 | 
						|
the threads. They become disabled when the tracking condition is not met, but
 | 
						|
also copy the state of the tracking thread channel.
 | 
						|
 | 
						|
They share the same tracking modes, but their behavior is slightly different:
 | 
						|
 | 
						|
In the case of tracking the running thread, if the CPU has more than one thread
 | 
						|
running, the channel will always output the error state ST_TOO_MANY_TH.
 | 
						|
 | 
						|
If is has no threads running, will be disabled and emit a 0 state by default.
 | 
						|
 | 
						|
Otherwise, it will emit the same value as the running thread. If the thread
 | 
						|
channel is disabled, it will emit a ST_BAD error state.
 | 
						|
 | 
						|
Regarding the active thread tracking mode, the CPU channels behave similarly,
 | 
						|
but with the active threads instead of running ones.
 | 
						|
 | 
						|
The CPU tracking mechanism simplify the process of updating CPU channels, as
 | 
						|
the modules don't need to worry about the execution model. Only the channels
 | 
						|
need to be configured to follow the proper execution state.
 | 
						|
 | 
						|
-- Channel state modes --------------------------------------------------------
 | 
						|
 | 
						|
The channels can be updated in three ways:
 | 
						|
 | 
						|
1) A fixed state can be set to the channel using chan_set(), which overrides the
 | 
						|
previous state.
 | 
						|
 | 
						|
2) The new state can be stored in a stack with chan_push() and chan_pop(), to
 | 
						|
remember the history of the previous states. The emitted event will be the one
 | 
						|
on the top.
 | 
						|
 | 
						|
3) Using a punctual event.
 | 
						|
 | 
						|
Setting the channel state is commonly used to track quantities such as the
 | 
						|
number of threads running per CPU. While the stack mode is commonly used to
 | 
						|
track functions or sections of code delimited with enter and exit events, which
 | 
						|
can call an return to the previous state.
 | 
						|
 | 
						|
An example program may be instrumented like this:
 | 
						|
 | 
						|
	int bar() {
 | 
						|
		instr("Xb[");
 | 
						|
		...
 | 
						|
		instr("Xb]");
 | 
						|
	}
 | 
						|
 | 
						|
	int foo() {
 | 
						|
		instr("Xf[");
 | 
						|
		bar();
 | 
						|
		instr("Xf]");
 | 
						|
	}
 | 
						|
 | 
						|
Then, in the emulator, when processing the events "Xf[" and "Xf]", we could track
 | 
						|
of the state as follows:
 | 
						|
 | 
						|
	int hook_pre_foo(struct ovni_chan *chan, int value) {
 | 
						|
		switch(value) {
 | 
						|
			case '[': chan_push(chan, 2); break;
 | 
						|
			case ']': chan_pop(chan, 2); break;
 | 
						|
			default: break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	int hook_pre_bar(struct ovni_chan *chan, int value) {
 | 
						|
		switch(value) {
 | 
						|
			case '[': chan_push(chan, 1); break;
 | 
						|
			case ']': chan_pop(chan, 1); break;
 | 
						|
			default: break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
The channel will emit the following sequence of states: 0, 1, 2, 1, 0.
 | 
						|
 | 
						|
Notice that the chan_pop() function uses the same state being pop()'ed as
 | 
						|
argument. The function checks that the stack contains the expected state,
 | 
						|
forcing the emulator to always receive a matching pair of enter and exit events.
 | 
						|
 | 
						|
-- Punctual events ------------------------------------------------------------
 | 
						|
 | 
						|
There are some conditions that are better mapped to events rather than to state
 | 
						|
transitions. For those cases, the channels provide punctual events which are
 | 
						|
emitted as a state than only has 1 ns of duration.
 | 
						|
 | 
						|
When a channel is configured to emit a punctual event with chan_ev(), it will
 | 
						|
first output the new state at the current time minus 1 ns, then restore the
 | 
						|
previous channel state and emit it at the current time.
 |