Continuing with the series of Nanos++ articles we wanted to shortly describe the instrumentation mechanism. In this post we give an overview of the Instrumentation main components and concepts. In a future post will show how to use them to instrument the runtime.
The main goal of instrumentation is to get some information about the program execution. In other words, we want to know “What happens in this WorkDescriptor running on this Thread ?”. There are the three main components involved in the instrumentation process: What (we also call it Event, WorkDescriptor and Thread.
- Events are something that happen at a given time or at a given interval of time.
- WorkDescriptors are the runtime basic unit of work. They offer a context to execute a piece of code.
- Threads are logical (or virtual) processors that execute WorkDescriptors.
Instrumentation is driven through Key/Value pairs in which the item Key identifies the semantic of the associated Value (e.g., WorkDescriptor ID as a Key and a numerical identifier as the associated Value). Keys and Values can be registered in a global dictionary (InstrumentationDictionary) which can be used as a repository.
Nanos++ defines four different type of events:
- Point: Punctual events. They have a list of KV pairs.
- Bursts: Interval events. They have a single KV pair which identify the type of burst that we are creating. The runtime automatically manages a stack of burst of with the same key.
- State: Thread state events. They have no KV pair, they have just a numerical code which identifies a runtime state.
- Point-to-Point (PtP): Two connected punctual events. They have a domain and identifier in order to match origin and destination and also, they have a list of KV pairs.
The core of the instrumentation behavior is specified through the Instrumentation class. This class implements several type of methods: methods to create events, methods to raise event, WorkDescriptor context swhich methods and finally, specific Instrumentation methods which are actually defined into each derived class (plugins). Specific Instrumentation methods are (ideally) the ones that have to be implemented in each derived Instrumentation class. They are:
- initialize(): this method is executed at runtime startup and can be used to create buffers, auxiliary structures, initialize values (e.g. time stamp), etc.
- finalize(): this method is executed at runtime shutdown and can be used to dump remaining data into a file or standard output, post-process trace information, delete buffers and auxiliary structures, etc.
- addEventList(): this method is executed each time the runtime raises an event. It receives a list of events (EventList) and the specific instrumentation class has to deal with each event in this list in order to generate (or not) a valid output.
But specific Instrumentation programmers can also overload other base methods in order to get an specific behavior when the plugin is invoked.