Convert documentation to Markdown and mkdocs
This commit is contained in:
parent
6141c2e303
commit
a1b668a872
157
doc/emu_chan.txt
157
doc/emu_chan.txt
@ -1,157 +0,0 @@
|
|||||||
--- 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.
|
|
@ -1,63 +0,0 @@
|
|||||||
--- Nanos6 Emulation ---
|
|
||||||
|
|
||||||
The Nanos6 emulator generates four different Paraver views, which are explained
|
|
||||||
in this document.
|
|
||||||
|
|
||||||
--- Task id ---
|
|
||||||
|
|
||||||
The task id view represents the id of the Nanos6 task instance that is currently
|
|
||||||
executing on each thread/cpu. This id is a monotonically increasing identifier
|
|
||||||
assigned on task creation. Lower ids correspond to tasks created at an earlier
|
|
||||||
point than higher ids.
|
|
||||||
|
|
||||||
--- Task type ---
|
|
||||||
|
|
||||||
Every task in Nanos6 contains a task type, which roughly corresponds to the
|
|
||||||
actual location in the code a task was declared. For example if a function fn()
|
|
||||||
is declared as a Nanos6 task, and it is called multiple times in a program,
|
|
||||||
every created task will have a different id, but the same type.
|
|
||||||
|
|
||||||
In the view, each type is shown with a label declared in the source with the
|
|
||||||
label() attribute of the task. If no label was specified, one is automatically
|
|
||||||
generated for each type.
|
|
||||||
|
|
||||||
Note that in this view, event value is a hash function of the type label, so two
|
|
||||||
distinct types (tasks declared in different parts of the code) with the same
|
|
||||||
label will share event value and will hence be indistinguishable.
|
|
||||||
|
|
||||||
--- MPI Rank ---
|
|
||||||
|
|
||||||
Represents the current MPI rank for the currently running task in a thread or cpu.
|
|
||||||
|
|
||||||
--- Subsystem ---
|
|
||||||
|
|
||||||
Represents the internal Nanos6 subsystem each thread or cpu is currently
|
|
||||||
running. Here is a summary of each possible value with its meaning:
|
|
||||||
|
|
||||||
- Null or black (value 0): Either the thread is idle (blocked because there is
|
|
||||||
no work) or the current subsystem is not instrumented
|
|
||||||
- "Scheduler: Waiting for tasks": Actively waiting for tasks inside the scheduler
|
|
||||||
subsystem, registered but not holding the scheduler lock
|
|
||||||
- "Scheduler: Serving tasks": Inside the scheduler lock, serving tasks to other
|
|
||||||
threads
|
|
||||||
- "Scheduler: Adding ready tasks": Adding tasks to the scheduler queues, but outside of
|
|
||||||
the scheduler lock
|
|
||||||
- "Task: Running": Executing user task code
|
|
||||||
- "Task: Spawning function": Registering a new spawn function (programmatically
|
|
||||||
created task)
|
|
||||||
- "Task: Creating": Creating a new task, through nanos6_create_task
|
|
||||||
- "Task: Submitting": Submitting a recently created task, through
|
|
||||||
nanos6_submit_task
|
|
||||||
- "Dependency: Registering": Registering a task's dependencies
|
|
||||||
- "Dependency: Unregistering": Releasing a task's dependencies because it has
|
|
||||||
ended
|
|
||||||
- "Blocking: Taskwait": Task is blocked while inside a taskwait
|
|
||||||
- "Blocking: Blocking current task": Task is blocked through the Nanos6
|
|
||||||
blocking API
|
|
||||||
- "Blocking: Unblocking remote task": Unblocking a different task using the
|
|
||||||
Nanos6 blocking API
|
|
||||||
- "Blocking: Wait For": Blocking a deadline task, which will be re-enqueued
|
|
||||||
when a certain amount of time has passed
|
|
||||||
- "Threading: Attached as external thread": External/Leader thread (which has
|
|
||||||
registered to Nanos6) is running
|
|
||||||
|
|
170
doc/emulation/channels.md
Normal file
170
doc/emulation/channels.md
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
# 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:
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
- 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.
|
@ -1,9 +1,12 @@
|
|||||||
|
# Emulator events
|
||||||
|
|
||||||
This file contains an exhaustive list of events supported by the emulator.
|
This file contains an exhaustive list of events supported by the emulator.
|
||||||
|
|
||||||
- Punctual events don't produce a state transition.
|
- Punctual events don't produce a state transition.
|
||||||
- All events refer to the current thread.
|
- All events refer to the current thread.
|
||||||
- Descriptions must be kept short.
|
- Descriptions must be kept short.
|
||||||
|
|
||||||
|
```
|
||||||
**********************************************************
|
**********************************************************
|
||||||
Please keep this list synchronized with the emulator code!
|
Please keep this list synchronized with the emulator code!
|
||||||
**********************************************************
|
**********************************************************
|
||||||
@ -168,3 +171,4 @@ KCI Is back in the CPU due to a context switch
|
|||||||
|
|
||||||
6Bu Begins to unblock the given task
|
6Bu Begins to unblock the given task
|
||||||
6BU Ends unblocking the given task
|
6BU Ends unblocking the given task
|
||||||
|
```
|
26
doc/emulation/index.md
Normal file
26
doc/emulation/index.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Emulation overview
|
||||||
|
|
||||||
|
The emulator reads the events stored during runtime and reconstructs the
|
||||||
|
execution, restoring the state of each thread and CPU as time evolves. During
|
||||||
|
the emulation process, a detailed trace is generated with the state of the
|
||||||
|
execution in the Paraver PRV format.
|
||||||
|
|
||||||
|
The emulator has an execution model to represent the real execution that
|
||||||
|
happened on the hardware. It consists of CPUs which can execute multiple threads
|
||||||
|
at the same time.
|
||||||
|
|
||||||
|
The emulator uses several models to identify how the resources are being
|
||||||
|
used. The following diagram despicts the resource, process and task
|
||||||
|
model.
|
||||||
|
|
||||||
|
![Model](model.png)
|
||||||
|
|
||||||
|
The resource model directly maps to the available hardware on the
|
||||||
|
machine. It consists of clusters which contains nodes, where each node
|
||||||
|
contains a set of CPUs that can execute instructions.
|
||||||
|
|
||||||
|
The process model tracks the state of processes and threads. Processes
|
||||||
|
that use the same CPUs in a single node are grouped into looms.
|
||||||
|
|
||||||
|
The task model includes the information of MPI and tasks of the
|
||||||
|
programming model (OmpSs-2).
|
BIN
doc/emulation/model.png
Normal file
BIN
doc/emulation/model.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 158 KiB |
@ -1,4 +1,4 @@
|
|||||||
# Nanos6 Emulation
|
# Nanos6 model
|
||||||
|
|
||||||
The Nanos6 emulator generates four different Paraver views, which are
|
The Nanos6 emulator generates four different Paraver views, which are
|
||||||
explained in this document.
|
explained in this document.
|
||||||
@ -50,68 +50,77 @@ exiting each section), and one common section of code which is shared
|
|||||||
across the subsystems, U, of no interest. We also assume any other code
|
across the subsystems, U, of no interest. We also assume any other code
|
||||||
not belonging to the runtime to be in the U section.
|
not belonging to the runtime to be in the U section.
|
||||||
|
|
||||||
Every instruction of the runtime belongs to *exactly one section*.
|
!!! remark
|
||||||
|
|
||||||
|
Every instruction of the runtime belongs to *exactly one section*.
|
||||||
|
|
||||||
To determine the state of a thread, we look into the stack to see what
|
To determine the state of a thread, we look into the stack to see what
|
||||||
is the top-most instrumented section.
|
is the top-most instrumented section.
|
||||||
|
|
||||||
At any given point in time, a thread may be executing code with a stack
|
At any given point in time, a thread may be executing code with a stack
|
||||||
that spawns multiple sections, for example \[ S1, U, S2, S3, U \] (the
|
that spawns multiple sections, for example *S1, U, S2, S3* and *U* (the
|
||||||
last is on top). The subsystem view selects the last subsystem section
|
last is on top). The subsystem view selects the last subsystem section
|
||||||
from the stack ignoring the common section U, and presents that section
|
from the stack ignoring the common section *U*, and presents that section
|
||||||
as the current state of the execution, in this case the S3.
|
as the current state of the execution, in this case the *S3*.
|
||||||
|
|
||||||
Additionally, the runtime sections are grouped together in systems,
|
Additionally, the runtime sections are grouped together in subsystems,
|
||||||
which form a group of closely related functions. A complete set of
|
which form a group of closely related functions. A complete set of
|
||||||
states for the subsystem view is listed below. The system is listed
|
states for each subsystem is listed below.
|
||||||
first and then the subsystem:
|
|
||||||
|
|
||||||
- **No subsystem**: There is no instrumented section in the stack of the
|
When there is no instrumented section in the thread stack, the state is
|
||||||
thread.
|
set to **No subsystem**.
|
||||||
|
|
||||||
The **Scheduler** system groups the actions that relate to the queueing
|
### Task subsystem
|
||||||
and dequeueing of ready tasks. The subsystems are:
|
|
||||||
|
|
||||||
- **Scheduler: Waiting for tasks**: Actively waiting for tasks inside the
|
The **Task** subsystem contains the code that controls the lifecycle of
|
||||||
scheduler subsystem, registered but not holding the scheduler lock
|
tasks. It contains the following sections:
|
||||||
|
|
||||||
- **Scheduler: Serving tasks**: Inside the scheduler lock, serving tasks
|
- **Running**: Executing the body of the task (user defined code).
|
||||||
to other threads
|
|
||||||
|
|
||||||
- **Scheduler: Adding ready tasks**: Adding tasks to the scheduler queues,
|
- **Spawning function**: Registering a new spawn function
|
||||||
but outside of the scheduler lock.
|
|
||||||
|
|
||||||
The **Task** system contains the code that controls the lifecycle of
|
|
||||||
tasks.
|
|
||||||
|
|
||||||
- **Task: Running**: Executing the body of the task (user defined code).
|
|
||||||
|
|
||||||
- **Task: Spawning function**: Registering a new spawn function
|
|
||||||
(programmatically created task)
|
(programmatically created task)
|
||||||
|
|
||||||
- **Task: Creating**: Creating a new task, through `nanos6_create_task`
|
- **Creating**: Creating a new task, through `nanos6_create_task`
|
||||||
|
|
||||||
- **Task: Submitting**: Submitting a recently created task, through
|
- **Submitting**: Submitting a recently created task, through
|
||||||
`nanos6_submit_task`
|
`nanos6_submit_task`
|
||||||
|
|
||||||
The **Dependency** group only contains the dependency code:
|
### Scheduler subsystem
|
||||||
|
|
||||||
- **Dependency: Registering**: Registering a task's dependencies
|
The **Scheduler** system groups the actions that relate to the queueing
|
||||||
|
and dequeueing of ready tasks. It contains the following sections:
|
||||||
|
|
||||||
- **Dependency: Unregistering**: Releasing a task's dependencies because
|
- **Waiting for tasks**: Actively waiting for tasks inside the
|
||||||
|
scheduler subsystem, registered but not holding the scheduler lock
|
||||||
|
|
||||||
|
- **Serving tasks**: Inside the scheduler lock, serving tasks
|
||||||
|
to other threads
|
||||||
|
|
||||||
|
- **Adding ready tasks**: Adding tasks to the scheduler queues,
|
||||||
|
but outside of the scheduler lock.
|
||||||
|
|
||||||
|
### Dependency subsystem
|
||||||
|
|
||||||
|
The **Dependency** system only contains the code that manages the
|
||||||
|
registration of task dependencies. It contains the following sections:
|
||||||
|
|
||||||
|
- **Registering**: Registering a task's dependencies
|
||||||
|
|
||||||
|
- **Unregistering**: Releasing a task's dependencies because
|
||||||
it has ended
|
it has ended
|
||||||
|
|
||||||
- **Blocking: Taskwait**: Task is blocked while inside a taskwait
|
### Blocking subsystem
|
||||||
|
|
||||||
- **Blocking: Blocking current task**: Task is blocked through the Nanos6
|
The **Blocking** subsystem deals with the code stops the thread
|
||||||
|
execution. It contains the following sections:
|
||||||
|
|
||||||
|
- **Taskwait**: Task is blocked while inside a taskwait
|
||||||
|
|
||||||
|
- **Blocking current task**: Task is blocked through the Nanos6
|
||||||
blocking API
|
blocking API
|
||||||
|
|
||||||
- **Blocking: Unblocking remote task**: Unblocking a different task using
|
- **Unblocking remote task**: Unblocking a different task using
|
||||||
the Nanos6 blocking API
|
the Nanos6 blocking API
|
||||||
|
|
||||||
- **Blocking: Wait For**: Blocking a deadline task, which will be
|
- **Wait For**: Blocking a deadline task, which will be
|
||||||
re-enqueued when a certain amount of time has passed
|
re-enqueued when a certain amount of time has passed
|
||||||
|
|
||||||
- **Threading: Attached as external thread**: External/Leader thread
|
|
||||||
(which has registered to Nanos6) is running
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
|||||||
# nOS-V task type colors
|
# nOS-V model
|
||||||
|
|
||||||
|
## nOS-V task type colors
|
||||||
|
|
||||||
The color assigned to each nOS-V task type is computed from the task
|
The color assigned to each nOS-V task type is computed from the task
|
||||||
type label using a hash function; the task type id doesn't affect in any
|
type label using a hash function; the task type id doesn't affect in any
|
BIN
doc/emulation/ovni-thread-model.png
Normal file
BIN
doc/emulation/ovni-thread-model.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
5
doc/emulation/ovni.md
Normal file
5
doc/emulation/ovni.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Ovni model
|
||||||
|
|
||||||
|
The ovni model tracks the state of threads and cpus.
|
||||||
|
|
||||||
|
![Thread states](ovni-thread-model.png)
|
29
doc/index.md
Normal file
29
doc/index.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
![Ovni logo](logo2.png)
|
||||||
|
|
||||||
|
This is the documentation of ovni, the Obtuse (but Versatile) Nanoscale
|
||||||
|
Instrumentation project.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
|
||||||
|
Preferably write the name of the project as lowercase *ovni*
|
||||||
|
unless the grammar rules suggest otherwise, such as starting a
|
||||||
|
new sentence.
|
||||||
|
|
||||||
|
The instrumentation process is split in two stages: [runtime](runtime)
|
||||||
|
tracing and [emulation](emulation/).
|
||||||
|
|
||||||
|
During runtime, very simple and short events are stored on disk which
|
||||||
|
describe what is happening. Once the execution finishes, the events are
|
||||||
|
read and processed to reproduce the execution during the emulation
|
||||||
|
process, and the final execution trace is generated.
|
||||||
|
|
||||||
|
By splitting the runtime and emulation processes we can perform
|
||||||
|
expensive computations during the trace generation without disturbing
|
||||||
|
the runtime process.
|
||||||
|
|
||||||
|
Each event belongs to a model, which has a direct mapping to a target
|
||||||
|
library or program. Each model is independent of other models, and they
|
||||||
|
can be instrumented concurrently.
|
||||||
|
|
||||||
|
The events are classified by using three identifiers known as *model*,
|
||||||
|
*category* and *value* (or MCV for short).
|
BIN
doc/logo.png
Normal file
BIN
doc/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 142 KiB |
BIN
doc/logo2.png
Normal file
BIN
doc/logo2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 113 KiB |
@ -1,4 +1,4 @@
|
|||||||
--- Kernel support ---
|
# Kernel support
|
||||||
|
|
||||||
Currently, only context switch events are supported. The kernel events are
|
Currently, only context switch events are supported. The kernel events are
|
||||||
usually written by the kernel into a buffer, without any action from user space.
|
usually written by the kernel into a buffer, without any action from user space.
|
||||||
@ -6,7 +6,7 @@ This behavior poses a problem, as the user space events and kernel events can
|
|||||||
leave a unsorted trace.
|
leave a unsorted trace.
|
||||||
|
|
||||||
The current workaround involves surounding the kernel events by two special ovni
|
The current workaround involves surounding the kernel events by two special ovni
|
||||||
event markers OU[ and OU] which determine the region of events which must be
|
event markers `OU[` and `OU]` which determine the region of events which must be
|
||||||
sorted first. Notice that the events inside the region must be sorted!
|
sorted first. Notice that the events inside the region must be sorted!
|
||||||
|
|
||||||
The `ovnisort` tool has been designed to sort the events enclosed by those
|
The `ovnisort` tool has been designed to sort the events enclosed by those
|
@ -1,36 +1,38 @@
|
|||||||
--- Using libovni ---
|
# Tracing a program with ovni
|
||||||
|
|
||||||
Read carefully this document before using libovni to generate a trace.
|
Read carefully this document before using libovni to generate a trace.
|
||||||
|
|
||||||
-- Mark the start and end of processes and threads ----------------------------
|
## Mark the start and end of processes and threads
|
||||||
|
|
||||||
Call ovni_proc_init() when a new program begins the execution.
|
Call `ovni_proc_init()` when a new program begins the execution.
|
||||||
|
|
||||||
Call ovni_thread_init() when a new thread begins the execution (including the
|
Call `ovni_thread_init()` when a new thread begins the execution
|
||||||
main process thread). Call ovni_flush() and ovni_thread_free() when it finishes.
|
(including the main process thread). Call `ovni_flush()` and
|
||||||
|
`ovni_thread_free()` when it finishes.
|
||||||
|
|
||||||
Call ovni_proc_fini() when the program ends, after all threads have finished.
|
Call `ovni_proc_fini()` when the program ends, after all threads have
|
||||||
|
finished.
|
||||||
|
|
||||||
You can use ovni_ev_emit() to record a new event. If you need more than 16 bytes
|
You can use `ovni_ev_emit()` to record a new event. If you need more
|
||||||
of payload, use ovni_ev_jumbo_emit().
|
than 16 bytes of payload, use `ovni_ev_jumbo_emit()`.
|
||||||
|
|
||||||
Compile and link with libovni. When you run your program, a new directory ovni
|
Compile and link with libovni. When you run your program, a new
|
||||||
will be created in the current directory ($PWD/ovni) which contains the
|
directory ovni will be created in the current directory ($PWD/ovni)
|
||||||
execution trace.
|
which contains the execution trace.
|
||||||
|
|
||||||
-- Rules ----------------------------------------------------------------------
|
## Rules
|
||||||
|
|
||||||
Follow these rules to avoid losing events:
|
Follow these rules to avoid losing events:
|
||||||
|
|
||||||
1. No event may be emitted until the process is initialized with
|
1. No event may be emitted until the process is initialized with
|
||||||
ovni_proc_init() and the thread with ovni_thread_init().
|
`ovni_proc_init()` and the thread with `ovni_thread_init()`.
|
||||||
|
|
||||||
2. When a thread ends the execution, it must call ovni_flush() to write the
|
2. When a thread ends the execution, it must call `ovni_flush()` to write the
|
||||||
events in the buffer to disk.
|
events in the buffer to disk.
|
||||||
|
|
||||||
3. All threads must have flushed its buffers before calling ovni_proc_fini().
|
3. All threads must have flushed its buffers before calling `ovni_proc_fini()`.
|
||||||
|
|
||||||
-- Select a fast directory ----------------------------------------------------
|
## Select a fast directory
|
||||||
|
|
||||||
During the execution of your program, a per-thread buffer is kept where the new
|
During the execution of your program, a per-thread buffer is kept where the new
|
||||||
events are being recorded. When this buffer is full, it is written to disk and
|
events are being recorded. When this buffer is full, it is written to disk and
|
||||||
@ -43,16 +45,17 @@ time. It is advisable to use the fastest filesystem available (see the tmpfs(5)
|
|||||||
and df(1) manual pages).
|
and df(1) manual pages).
|
||||||
|
|
||||||
You can select the trace directory where the buffers will be flushed during the
|
You can select the trace directory where the buffers will be flushed during the
|
||||||
execution by setting the environment variable OVNI_TMPDIR. The last directory
|
execution by setting the environment variable `OVNI_TMPDIR`. The last directory
|
||||||
will be created if doesn't exist. In that case, as soon as a process calls
|
will be created if doesn't exist. In that case, as soon as a process calls
|
||||||
ovni_proc_fini(), the traces of all its threads will be moved to the final
|
`ovni_proc_fini()`, the traces of all its threads will be moved to the final
|
||||||
directory at $PWD/ovni. Example:
|
directory at `$PWD/ovni`. Example:
|
||||||
|
|
||||||
OVNI_TMPDIR=$(mktemp -u /dev/shm/ovni.XXXXXX) srun ./your-app
|
OVNI_TMPDIR=$(mktemp -u /dev/shm/ovni.XXXXXX) srun ./your-app
|
||||||
|
|
||||||
To test the different filesystem speeds, you can use hyperfine and dd. Take a
|
To test the different filesystem speeds, you can use hyperfine and dd. Take a
|
||||||
closer look at the max time:
|
closer look at the max time:
|
||||||
|
|
||||||
|
```
|
||||||
$ hyperfine 'dd if=/dev/zero of=/gpfs/projects/bsc15/bsc15557/kk bs=2M count=10'
|
$ hyperfine 'dd if=/dev/zero of=/gpfs/projects/bsc15/bsc15557/kk bs=2M count=10'
|
||||||
Benchmark 1: dd if=/dev/zero of=/gpfs/projects/bsc15/bsc15557/kk bs=2M count=10
|
Benchmark 1: dd if=/dev/zero of=/gpfs/projects/bsc15/bsc15557/kk bs=2M count=10
|
||||||
Time (mean ± σ): 71.7 ms ± 130.4 ms [User: 0.8 ms, System: 10.2 ms]
|
Time (mean ± σ): 71.7 ms ± 130.4 ms [User: 0.8 ms, System: 10.2 ms]
|
||||||
@ -71,4 +74,5 @@ $ hyperfine 'dd if=/dev/zero of=/dev/shm/kk bs=2M count=10'
|
|||||||
Benchmark 1: dd if=/dev/zero of=/dev/shm/kk bs=2M count=10
|
Benchmark 1: dd if=/dev/zero of=/dev/shm/kk bs=2M count=10
|
||||||
Time (mean ± σ): 11.4 ms ± 0.4 ms [User: 0.5 ms, System: 11.1 ms]
|
Time (mean ± σ): 11.4 ms ± 0.4 ms [User: 0.5 ms, System: 11.1 ms]
|
||||||
Range (min … max): 9.7 ms … 12.5 ms 269 runs
|
Range (min … max): 9.7 ms … 12.5 ms 269 runs
|
||||||
|
```
|
||||||
|
|
20
mkdocs.yml
Normal file
20
mkdocs.yml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
site_name: ovni
|
||||||
|
theme: readthedocs
|
||||||
|
docs_dir: doc
|
||||||
|
markdown_extensions:
|
||||||
|
- admonition
|
||||||
|
- toc:
|
||||||
|
permalink: "#"
|
||||||
|
separator: "_"
|
||||||
|
nav:
|
||||||
|
- index.md
|
||||||
|
- 'Runtime':
|
||||||
|
- runtime/tracing.md
|
||||||
|
- runtime/kernel.md
|
||||||
|
- 'Emulation':
|
||||||
|
- emulation/index.md
|
||||||
|
- emulation/ovni.md
|
||||||
|
- emulation/nosv.md
|
||||||
|
- emulation/nanos6.md
|
||||||
|
- emulation/events.md
|
||||||
|
- emulation/channels.md
|
Loading…
Reference in New Issue
Block a user