Section 28.1. ASPECTC


28.1. ASPECTC

The structured implementation of prefetching presented here uses AspectC [1]a simple AOP extension to C. Overall, only a small portion of the code relies on these linguistic extensions. These extensions modularize crosscutting concerns by allowing fragments of code that would otherwise be spread across several functions to be co-located and to share context.

AspectC is a subset of AspectJ [2] (see the article by Kiczales et al. in this issue), without any support for OOP or explicit modules. Instead, we use the C convention of using a file to conceptually delimit a module. Aspect code, known as advice, interacts with primary functionality at function call boundaries and can run before, after or around existing function calls. The central elements of the language are a means for designating particular function calls, for accessing parameters of those calls, and for attaching advice to those calls.

Key to structuring the crosscutting implementation of prefetching is the ability to capture dynamic execution context with the control flow, or cflow, mechanism. Cflow supports the coordination of high-level and low-level prefetching activity along an execution path by exposing specific high-level context, such as function calls and parameters, to lower-level advice.

Figure 28-1 shows three color-coded paths to disk, two of which have been previously introduced: normal and sequential page fault handling. The third is the file system read path. Functions in the (simplified) primary functionality call graph are represented by ellipses labeled with function names.

Figure 28-1. Execution paths to disk.


28.1.1. Normal Behavior Prefetching in AspectC

Listing 28-1 shows an AO implementation of prefetching along the normal behavior page fault path. To develop this implementation, we first stripped prefetching out of the primary page fault handling. We then made several minor refactorings of the primary code structure to expose principled points for the definition of prefetching advice. In this example, refactoring spawned two new functions, ffs_valid and ffs_calc_size, from ffs_getpages.

This small aspect, normal_prefetching, contains two pointcut declarations, which identify and expose important control flow information, and four advice declarations, structured according to these pointcuts.

28.1.2. Pointcut Declarations

A pointcut identifies a collection of function calls and specific arguments to those calls. The first declaration in the aspect is a pointcut named vm_fault_cflow, with one parameter, map. The details are in the second line of the declaration: this pointcut refers to all function calls within the control flow of calls to vm_fault, and exposes vm_fault's first argument, the page map. This pointcut is used by advice to access the page map for planning and allocating prefetched pages. The '. .' in this parameter list means that although vm_fault has more parameters, they are not exposed by this pointcut.

Listing 28-1. Aspect for normal behavior prefetching during page fault handling.
 aspect normal_prefetching {   pointcut vm_fault_cflow( vm_map_t map ):       cflow( calls( int vm_fault( map, .. )));   pointcut ffs_getpages_cflow( vm_object_t obj,                           vm_page_t* plist, int                           len, int fpage ):       cflow( calls( int ffs_getpages( obj, plist, len,                                            fpage )));   before( vm_map_t map, vm_object_t obj, vm_page_t*         plist, int len, int fpage ):              calls( int vnode_pager_getpages( obj, plist,                                          len, fpage ))       && vm_fault_cflow( map )   {     if ( obj->declared_behaviour == NORMAL ) {       vm_map_lock( map );       plan_and_alloc_normal( obj, plist, len, fpage );       vm_map_unlock( map );     }   }   after( vm_object_t obj, vm_page_t* plist, int        len, int fpage, int valid ):       calls( valid ffs_valid(..) )       && ffs_getpages_cflow( obj, plist, len, fpage )   {     if ( valid )       dealloc_all_prefetch_pages( obj, plist,                                   len, fpage );   }   after( vm_object_t obj, vm_page_t* plist, int len, int          fpage, int error, int reqblkno ):       calls( error ufs_bmap( struct vnode*, reqblkno, ..) )       && ffs_getpages_cflow( obj, plist, len, fpage )   {     if ( error || (reqblkno == -1) )        dealloc_all_prefetch_pages( obj, plist, len, fpage );   }   after( vm_object_t obj, vm_page_t* plist, int len, int          fpage, struct t_args* trans_args ):       calls( int ffs_calc_size( trans_args ))       && ffs_getpages_cflow( obj, plist, len, fpage )   {     dealloc_noncontig_prefetch_pages( obj, plist, len,                                       fpage, trans_args );   } } 

Similarly, the second declaration is another pointcut, named ffs_ getpages_cflow, which allows advice to access the entire parameter list of ffs_getpages. This pointcut is used by advice for de-allocating planned pages.

28.1.3. Advice Declarations

Advice in this aspect are shown as four color-coded ellipses associated with normal behavior page fault handling in Figure 28-1. Each is labeled as executing before or after the function directly below it in the call graph. Places where control flow information is exposed are indicated by small arrows adjacent to specific functions.

The first advice in the aspect is responsible for the high-level planning and allocating of prefetched pages according to the object's behavior. The header says to execute the body of this advice before calls to vnode_pager_getpages, and to give the body access to the map parameter of the surrounding call to vm_fault.

In more detail, the first line of the header says this advice will run before function calls designated following the ':', and lists five parameters available in the body of the advice. The second line specifies calls to the function vnode_ pager_getpages, and exposes the four arguments to that function. The third line uses the previously declared pointcut vm_fault_cflow, to provide the value for map associated with the particular fault currently being serviced (that is, from a few frames back on the stack). The body of the advice is ordinary C code.

The next three declarations implement the low-level details associated with retrieval. There are three conditions under which the FFS layer can choose not to prefetch. In each case, the implementation of the decision not to prefetch results in deallocation of pages previously allocated for prefetching. Each of these instances of after advice uses ffs_getpages_cflow to provide access to the necessary parameters and to ensure the advice runs only within the control flow of an execution path that includes ffs_getpages. This is important because ufs_bmap is part of many other execution paths in the system.

28.1.4. Implementation Comparison

The key difference between the original code and the AOP code is that when implemented using aspects, the coordination of VM and FFS prefetching activity becomes clear. We can see, in a single screenful, the interaction of planning and canceling prefetching, and allocating and deallocating pages along a given execution path. Structuring the code this wayas path-specific customizationshas helped us refactor several other prefetching aspects, including one for sequential behavior page fault handling and another for file system reads [3].



Aspect-Oriented Software Development
Aspect-Oriented Software Development with Use Cases
ISBN: 0321268881
EAN: 2147483647
Year: 2003
Pages: 307

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net