<
aspect xmlns:src="
http://www.sdml.info/srcML/src"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform"
xmlns:cpp="
http://www.sdml.info/srcML/cpp"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xmlns="
http://control.ee.ethz.ch/XWeaver/AspectX"
xsi:schemaLocation="
http://control.ee.ethz.ch/XWeaver/AspectX ../../../../src/xsd/aspectX.xsd"
name="
Profiling">
<
description>
Sample aspect program to insert <
i>
profiling</
i>
instructions to the base code.
<
i>
Profiling</
i>
a system means collecting the information about the time spent by each operation in the system.
This sample aspect demonstrates how profiling instructions can be added to the base code.
For each method, the time that the program spend executing the method body is computed
and reported to the user at the end of the program execution.
<
author>
A. Pasetti, O. Rohlik</
author>
</
description>
<
pointcut name="
targetConstructor"
type="
src:constructor">
<
description>
Points to all constructors in the base code.</
description>
</
pointcut>
<
pointcut name="
targetClass"
type="
src:class">
<
description>
Points to all classes.</
description>
</
pointcut>
<
pointcut name="
targetClassImplementationUnit"
type="
src:unit">
<
description>
Points to all the units (source files) that contain implementations of the methods
defined in the classes specified by the <
code>
targetClass</
code>
pointcut.
</
description>
<
restriction type="
isDefinitionOf">
<
pointcutRef ref="
targetClass"
type="
src:class" />
</
restriction>
</
pointcut>
<
pointcut name="
targetMethod"
type="
src:function">
<
description>
Points to all method definitions that are
in the units (source files) specified by the pointcut
<
code>
targetClassImplementationUnit</
code>
.
Thus, it points to all <
i>
method</
i>
definitions (but not to
definitions of constructors, destructors and C functions).
</
description>
<
restriction type="
within">
<
pointcutRef ref="
targetClassImplementationUnit"
type="
src:unit" />
</
restriction>
</
pointcut>
<
pointcut name="
targetMethodReturn"
type="
src:return">
<
description>
Points to the return statements that must be modified. It only target the return
statements of <
i>
methods</
i>
.
</
description>
<
restriction type="
within">
<
pointcutRef ref="
targetMethod"
type="
src:function" />
</
restriction>
</
pointcut>
<
pointcut name="
targetMainFunction"
type="
src:function"
constraint="
src:name='main'">
<
description>
Points to the <
code>
main()</
code>
function.</
description>
</
pointcut>
<
pointcut name="
targetMainReturn"
type="
src:return">
<
description>
Points to return statements in the <
code>
main()</
code>
function.
</
description>
<
restriction type="
within">
<
pointcutRef ref="
targetMainFunction"
type="
src:function" />
</
restriction>
</
pointcut>
<
advice name="
addProfilingVariables"
type="
add">
<
description>
Insert declarations to each class.
<
p />
Set of new private member variables is added to the declaration of every class.
For each method one member variable is defined. Its name is derived from the name of the method.
Member variables have form <
code>
_profiling_XXX</
code>
where <
code>
XXX</
code>
stands for the method name. For example, the name of <
code>
_profiling_test</
code>
member variable
is derived from the name of the <
code>
test()</
code>
method.
<
p />
Two constructs of the XSL language are used to insert the variables: <
code>
xsl:for-each</
code>
and <
code>
xsl:value-of</
code>
. The <
code>
xsl:for-each</
code>
instruction locates all method
declarations. Then the <
code>
xsl:value-of</
code>
instruction is used to
extract the names of the methods and to write them to the base code.
<
p />
The advice also inserts the declaration of the public method <
code>
_profilingReport()</
code>
.
</
description>
<
pointcutRef ref="
targetClass"
type="
src:class" />
<
codeModifier type="
declaration">
<
accessModifier type="
public" />
<
text>
void _profilingReport();</
text>
</
codeModifier>
<
codeModifier type="
declaration">
<
accessModifier type="
private" />
<
text>
<
xsl:
for-each select="
/src:unit/src:class//src:function_decl">
long _profiling_<
xsl:
value-of select="
src:name" />
;
</
xsl:
for-each></
text>
</
codeModifier>
</
advice>
<
advice type="
before"
name="
insertReporterCall">
<
description>
Insert call of method <
code>
_profilingReport()</
code>
at the end of execution of the
<
code>
main()</
code>
function. More precisely, it inserts the function call before
every <
code>
return</
code>
statement of the <
code>
main()</
code>
function.
</
description>
<
pointcutRef ref="
targetMainReturn"
type="
src:return" />
<
codeModifier type="
codeFragment">
<
text>
sc._profilingReport();</
text>
</
codeModifier>
</
advice>
<
advice type="
begin"
name="
insertVariableDeclaration">
<
description>
Insert the code that reads the current time and saves it
to the local variable <
code>
_profilingMethodStart</
code>
.
</
description>
<
pointcutRef ref="
targetMethod"
type="
src:function" />
<
codeModifier type="
codeFragment">
<
text>
long _profilingMethodStart = MicroTime::getMicroTime(); // added by aspect</
text>
</
codeModifier>
</
advice>
<
advice type="
before"
name="
insertBeforeReturn">
<
description>
Insert code that computes the time the program spent executing the current method. It uses the current time and
the value of the local variable <
code>
_profilingMethodStart</
code>
. The computed amount of time is added to
the respective member variable <
code>
_profiling_XXX</
code>
where XXX stands for the name of the current method.
This code is inserted before every return statement.
</
description>
<
pointcutRef ref="
targetMethodReturn"
type="
src:return" />
<
codeModifier type="
codeFragment">
<
text>
_profiling_${functionName} += MicroTime::getMicroTime() - _profilingMethodStart; // added by aspect</
text>
</
codeModifier>
</
advice>
<
advice type="
end"
name="
insertTraceAtEnd">
<
description>
Insert code that computes the time the program spent executing the current method. It uses the current time and
the value of the local variable <
code>
_profilingMethodStart</
code>
. The computed amount of time is added to
the respective member variable <
code>
_profiling_XXX</
code>
where XXX stands for the name of the current method.
This code is inserted at the very end of every class method.
</
description>
<
pointcutRef ref="
targetMethod"
type="
src:function" />
<
codeModifier type="
codeFragment">
<
text>
_profiling_${functionName} += MicroTime::getMicroTime() - _profilingMethodStart; // added by aspect (and may be not accessible)</
text>
<
text />
</
codeModifier>
</
advice>
<
advice type="
add"
name="
addInclude">
<
description>
Add the necessary <
code>
#include</
code>
statements.
It adds the header file of <
code>
MicroTime</
code>
class that is used to measure time with accuracy of
one microsecond. It also includes the <
code>
iostream</
code>
library and declares
the <
code>
std</
code>
namespace needed for I/O operations.
</
description>
<
pointcutRef ref="
targetClassImplementationUnit"
type="
src:unit" />
<
codeModifier type="
include">
<
text>
#include "MicroTime.h"
#include <iostream>
using namespace std; // code WOVEN by ASPECT</
text>
</
codeModifier>
</
advice>
<
advice name="
addProfilingReportMethod"
type="
add">
<
description>
Insert the definition of <
code>
_profilingReport()</
code>
method. The method lists all
methods defined in the class. For every method it outputs the total execution time in microseconds.
<
p />
Two constructs of the XSL language are used to access the
member variables that stores the execution time for each method: <
code>
xsl:for-each</
code>
and <
code>
xsl:value-of</
code>
. The <
code>
xsl:for-each</
code>
instruction locates all method
definitions. Then the <
code>
xsl:value-of</
code>
instruction is used to
extract the local names of the methods and to write them to the base code.
</
description>
<
pointcutRef ref="
targetClassImplementationUnit"
type="
src:unit" />
<
codeModifier type="
definition">
<
text>
void SampleClass::_profilingReport() {
cout << "Profiling report" << endl;
cout << "================" << endl;</
text>
<
text>
<
xsl:
for-each select="
/src:unit/src:function">
cout << "Time spent in method '<
xsl:
value-of select="
src:name/src:name[2]" />
': " << _profiling_<
xsl:
value-of select="
src:name/src:name[2]" />
<< endl;
</
xsl:
for-each>
} </
text></
codeModifier>
</
advice>
<
advice type="
begin"
name="
addProfilingVariableInitialization">
<
description>
Insert the initialization code of all profiling member variables
to the class constructor. The two XSL constructs (<
code>
xsl:for-each</
code>
and <
code>
xsl:value-of</
code>
) are used to set all profiling member variables to zero.
</
description>
<
pointcutRef ref="
targetConstructor"
type="
src:constructor" />
<
codeModifier type="
codeFragment">
<
text>
<
xsl:
for-each select="
parent::src:unit/src:function">
_profiling_<
xsl:
value-of select="
src:name/src:name[2]" />
= 0;
</
xsl:
for-each></
text>
</
codeModifier>
</
advice>
</
aspect>
v