General Information
Tutorials
Reference Manuals
Libraries
Translation Tasks
Tools
Administration
|
Execution Monitoring ReferenceImplementationThis chapter describes some of the implementation of Noosa in detail. Eli users who just want to perform monitoring with existing monitors do not need to read this chapter. It is intended for Eli developers or advanced users who want to extend the capabilities of Noosa. Monitoring InterfacesNoosa needs to obtain information from the running program. It uses the program's monitoring interface to do it. A program's monitoring interface is the union of all of the monitoring interfaces of the components making up that program. The contents of the monitoring interface for a component depend on the nature of the component and the information that it wants to make available to the monitoring system. Monitoring interfaces are described by type-`dapto' files. (See Dapto Grammar, for the syntax of the Dapto language.) Dapto files contain the information described in the following. Examples are taken from the monitoring interface for the string table module in Eli (see the file `pkg/Adt/csm.dapto' in the Eli distribution).
In the following discussion, two pre-defined data types:
AspectsAll elements of a monitoring interface are grouped together into aspects (similar to a module). The names of aspects are used to enable the monitoring system to decide what components are present in the program. Some monitoring commands are only applicable to programs which provide the aspects on which the monitor depends. For example, the Phrase command can only be used on programs that contain parsers. See Monitoring Database, for more details on this mechanism. An aspect syntactically encloses the interface elements which it contains.
aspect string; Interface elements of the string aspect end; Event TypesEvent types are described in a monitoring interface by giving their names plus the names and types of their parameters. We also enforce the inclusion of documentation strings for each of these entities to enable the user interface to provide readable descriptions of events where necessary.
The string table monitoring interface contains one event,
event string_stored* "Storage of a new string in the string table" (int index "Index of new string", str string "New string");
Normally event types are assumed to be hidden from the user. If you
want the events of a particular type to be visible to the user through
the Handlers window, it is necessary to append a Operations
Operation signatures are described in the monitoring interface by giving
the name of the operation, its parameters (if any), its return type (if
any), along with documentation strings. Currently the return type of
an operation must be
Here is the signature for the string table
operation get_string "Look up a string given its index" (int index "Index of the string to be looked up") : str operation set_string "Change the value of a stored string" (int index "Index of string to be changed", str value "New value for string")
Operation implementations are given in C following the operation
signature. Any legal C code can be used in an operation definition,
except that C
DAPTO_RESULT macros sets up a value that is returned when
the end of the operation is reached. To return from the middle of an
operation use the DAPTO_RETURN macro with no arguments.
For example, the following is the full definition of the
operation get_string "Look up a string given its index" (int index "Index of the string to be looked up") : str { if ((index < 0) || (index >= numstr)) { DAPTO_RESULT_STR ("*** Illegal string table index ***"); } else { char *s = string[index]; if (s == (char *) 0) { DAPTO_RESULT_STR ("*** No string at this index ***"); } else { DAPTO_RESULT_STR (s); } } }
The
DAPTO_RESULT_INT (i + 1); DAPTO_RESULT_INTVAL (i + 1);
The Header FilesWhen writing the operation and translation parts of a monitoring interface it is often necessary to refer to C entities exported by other modules. To enable the implementation of the monitoring interface to access these other interfaces it is necessary to include them in the monitoring interface description. Interfaces are included by simply naming the header files which contain them. The string table monitoring interface uses some standard C library functions, C string functions and entities made available by the string table module. Consequently the interface also includes the following lines:
<stdlib.h> <string.h> "csm.h" Non-standard types
By default, Dapto can handle the built-in types Even if you do not add new operations or events involving non-standard types you probably want to provide proper monitoring support for them anyway. The reason is that other parts of the system may need to report values of these types to Noosa. Most notably, the attribute evaluator generates events whenever attributes are evaluated. If you want to be able to monitor attributes of non-standard types then you must add proper monitoring support for these types or the attribute values will be reported as "unknown". The rest of this section explains what you need to do to monitor values of a non-standard type. It talks about the monitoring interface and associated support. The next section describes how you might go about displaying values in the Noosa transcript window for user browsing. The following information is based on the monitoring support for environment values in the current Eli system. The environment module has the following monitoring interface containing a couple of events and an operation (see the file `pkg/Name/envmod.dapto' in the Eli distribution).
aspect envmod; "envmod.h" event env_created* "An environment value has been created" (Environment env "The environment that was created", Environment parent "The parent environment (if any)"); event binding_made* "A binding has been made in an environment" (Environment env "The environment in which the binding was made", int idn "The identifier that was bound", DefTableKey key "The key to which the identifier was bound"); operation get_scope_info "Return the parent environment of an environment and its idn-key bindings" (Environment env "The environment to be searched") : str { Scope s; DAPTO_RESULT_PTR (env->parent); for (s = env->relate; s != NoScope; s = s->nxt) { DAPTO_RESULT_INT (s->idn); DAPTO_RESULT_PTR (s->key); } } end; As is conventional in a monitoring interface, the events are used to notify Noosa of important changes to the environment values as they occur. The operation is used to allow Noosa to get the complete contents of an environment. Providing both events and operations in this style is a good idea because the events allow fine-grained control via breakpoints and handlers while the operation can be used to implement value browsing. Note that the operation implementation can use any C code it likes to determine the appropriate information and return it to Noosa. In this case we use the fields provided by the environment module to return the parent environment and all of the integer-key pairs.
Since
When Dapto generates the event generation code for an event parameter
of unknown type it attempts to use a macro of the form
#define DAPTO_RESULTEnvironment(e) DAPTO_RESULT_PTR (e)which says that an environment value should be sent from the running program to Noosa as a pointer (since it is a pointer).
Similarly, to permit values of this type to be sent from Noosa to the
running program (as operation parameters) you need to define a macro
whose name is
#define DAPTO_ARGEnvironment(e) DAPTO_ARG_PTR (e, Environment)which says that it should be received as a pointer. In the definition of the macro, the second parameter is the type of the value. It is used to cast the received value to the appropriate type. Browsing non-standard typesOnce you have Noosa and the running program correctly passing values of a non-standard type back and forth, you usually want to see those values in the Noosa transcript. If the values are structured, you will also want to add browsing support for them.
Adding browsing support for a non-standard type involves writing Tcl
code that will be invoked whenever a value of this type is browsed. The
procedure can be automatically loaded into Noosa by placing its
definition in a startup file (see User Initialisation).
Alternatively, it can be placed in a file of type
The Noosa transcript is a general text display area, so you can use
Here is a slightly simplified version of the Tcl support used by Eli to support browsing of environment values.
set n(Environment,desc) "Identifier scoping environment" proc n_Environment_say {env} { n_say "Environment:0x[n_dectohex $env]" } proc n_Environment_open {text env} { n_say "$text" if {$env == 0} { n_say "\n NoEnv\n" } else { set env [n_hextodec $env] set r [n_send get_scope_info $env] if {[lindex $r 0] != 0} { n_say " (parent: " n_Environment_say [lindex $r 0] n_say ")" } set r [lreplace $r 0 0] n_say "\n" set c 0 foreach {i j} $r { n_say " " n_say_val DefTableKey $j set s [n_send get_string $i] n_say " $s\n" incr c } if {$c == 0} { n_say " No bindings\n" } } }
The first
The procedure
The procedure The implementation of this procedure first displays the clicked-on text to identify the subsequent output because the browsable value may be a long distance from the bottom of the transcript where the output will be displayed. A null environment is displayed in a standard way to match the user's view of the module.
Non-null environments are converted by
When the
All of the integer-key pairs in the environment are displayed. The
routine
Note that we don't display the integers as-is, we use the
Implementing Monitoring Interfaces
A type-`dapto' file defines the monitoring interface of a
component. (See Dapto Grammar, for the syntax of the Dapto
language.) The
The names of the generated files depend on the name of the input file; `csm.dapto' will produce `csm_dapto.c', `csm_dapto.h' and `csm_dapto.db'. Monitoring DatabaseA monitoring database is generated by Dapto from a monitoring interface description (see Implementing Monitoring Interfaces). The concatenation of the monitoring databases for all of the components present in a program comprises the monitoring database for the program. The monitoring database is simply a TCL file which, when loaded by Noosa, provides information about the aspects and events of the monitoring interface. For example, the monitoring database for the string table monitoring interface (see Monitoring Interfaces) yields the following database (reformatted slightly):
lappend n(aspects) string lappend n(events) \ [list string_stored "Storage of a new string in the string table" \ { index "Index of new string" string "New string" } 1]The global TCL lists n(aspects) and
n(events) are used to store the database information.
n(aspects) contains a list of the all of the aspect names
contained in the program. n(events) is a list of lists; each
sub-list contains the name and documentation strings for a single event
type and its parameters, plus a flag which is 1 if the event is visible
to the user and 0 otherwise.
Adding Monitoring Support To A ComponentOnce you have a monitoring interface implementation for a component you must add monitoring support to the component itself. This support consists entirely of calls to the event generation routines for any events you have in your interface (see Monitoring Interfaces and see Implementing Monitoring Interfaces). If you have no events in your interface, the code of the component does not need to be changed. Adding event generation to a component is a matter of adding calls to event generation routines at the appropriate places. The details of this will depend on the component, but the idea is to insert the calls at places where the action which the event represents can be said to have taken place. Any necessary event parameters should be passed to the event generation routine. To enable a monitoring-free version of the component to be easily produced, the convention is that all additions purely for the purpose of monitoring be conditionalised by
#ifdef MONITOR ... #endif The following examples are based on monitoring support for the Eli string table component. The component must be modified to include the C interface to the monitoring interface:
#ifdef MONITOR #include "csm_dapto.h" #endif
Then we must identify places in the code where
#ifdef MONITOR _dapto_string_stored (numstr, string[numstr]); #endif
When the component is compiled by Eli with the
Supporting Profiling
Noosa contains support for two kinds of profiles (see Frequency Profiles and see Time Profiles). To support profiling of a
component it is necessary to add extra event generation to a component.
It is necessary to generate an event enter "Enter a program component" (str name "Name of component"); event leave "Leave a program component" (str name "Name of component"); For the string table component we would add the following code to the beginning of each string table routine:
#ifdef MONITOR _dapto_enter ("string"); #endifand the following code at each exit point of each string table routine: #ifdef MONITOR _dapto_leave ("string"); #endifThe event parameter ("string" in this case) is used by the profile monitoring code to identify the component. Dapto GrammarThe following context-free grammar defines the syntax of the Dapto language. ident is an identifier in the C style. Identifier definitions are required to be unique within a specification and within event and operation blocks. str and bstr are strings delimited by double quotes and angled brackets, respectively. text is arbitrary text delimited by braces.
spec: aspects. aspects: aspect_stmt / aspects aspect_stmt. aspect_stmt: `aspect' iddef `;' sigs `end' `;'. sigs: sig / sigs sig. sig: event_sig / operation_sig / str / bstr. event_sig: `event' iddef export str event_block `;'. event_block: `(' optattrs `)'. export: `*' / /* empty */. optattrs: /* empty */ / attrs. attrs: attr / attrs `,' attr. attr: typeid iddef str. operation_sig: `operation' iddef str operation_block text / `operation' iddef str operation_block `:' typeid text. operation_block: `(' optparams `)'. optparams: /* empty */ / params. params: param / params `,' param. param: typeid iddef str. iddef: ident. iduse: ident. typeid: ident.
|