This section discusses what happens during the precompilation process of Breezy. This process is important in that it describes how the data access is designed and how user functions are made available. As mentioned above, these two important functions of Breezy are implemented at the language level; the program analysis and instrumentation is where that implementation takes place. Program analysis is accomplished using a utility called Sage++, a compiler toolkit that provides an API for browsing the syntax tree of the program and modifying that tree as desired. Once modified, the new syntax tree can be unparsed to C++ source code, which can subsequently be compiled. To take advantage of Breezy, other languages would have to provide similar information about the program either from a compiler toolkit, or from the compiler itself.
The user program is first analyzed to generate type information. This type information is passed on to the instrumentor as well as saved to a separate type description file. This file contains ``interesting'' types (e.g., types involved in parallel data structures), and will be read by Breezy during the initialization phase of the execution to make the type information available at runtime. The second step in the process is instrumentation of the user program.
The instrumentor also makes use of the type information. It must add code to the user program that will allow access to the parallel data objects at runtime. The first step in this process is creating functions that extract the data from the parallel structures. If the distributed elements of the parallel object are instances of a class, then we must add methods to that class to get to that data. In generating these new functions and methods, the instrumentor uses the type information. It then must make a table that correlates the string type name of each interesting data type with the function that accesses (extracts data from) that data type. This table, and others that are created during the instrumentation process, are accessible by Breezy at runtime. Note that the access functions and methods have fixed argument types so that the access function table entries need not include the parameter types.
The next operation that the instrumentor must perform is detecting all lines in the code where parallel data objects are created. At each of these points, the instrumentor inserts code which will add the new variable's name, the pointer to that variable, and the type of that variable to a table. At each new allocation of a parallel structure, a new table entry is created, making the new variable available to Breezy. Note that at all points where parallel structures are deallocated, there must also be code added which deletes the table entry for the object being deallocated.
The last step the instrumentor takes is to detect user-defined
access functions. This consists of searching
all function names in the user program for a certain prefix,
UserDefined. As in the previous step, the
instrumentor again must construct a table relating the
name of the function with a pointer to the function for
Thus, by accomplishing these steps, Breezy has runtime access to tables from which it can do the following.
Given access to this information at runtime, Breezy can forward variable, type and functions names from these tables to the client. In return, the client can specify what it is interested in by using these names as arguments to basic calls in the Breezy API. The result is a high-level interface based on the language and the program itself.