Title: .NET 2006 Presentation
1Using the .NET Profiler API to Collect Object
Instances for Constraint Evaluation Presented
by Dave Arnold
2- Outline
- Introduction to OCL 2.0
- Relationship to UML and MDA
- Problem / Solution
- Compiling C with OCL
- OclAnyAllInstances()
- The .NET Profiler API
- Getting the information back to the application
- Putting it all together
- Issues / Conclusion
- References
3OCL 2.0
- OCL Object Constraint Language
- Standardized by the OMG in August 2003
- Main use is for adding constraints to UML models
- Pre-Conditions
- Post-Conditions
- Class Invariants
- Can also be used to define derived attributes and
methods (Queries)
4Relationship with UML
- UML diagrams alone do not contain enough
information - The OCL can be used to specify additional
information - context Customerage Integer
- init 18
- context Customer inv
- self.age gt 17
5Model Driven Architecture
- Importance of using models in the development
process - Consists of three main steps
- Construct a model at a high level of abstraction,
free of all implementation technologies (PIM) - Transform the PIM model into one or more models
that contain implementation details (PSM) - Transform the PSM to implementation code
6Model Driven Architecture
7The Problem
- When a UML model is transformed into code what do
we do with the OCL? - Ignore it?
- Then why use it?
- Translate it into source code?
- How do we later determine what code was OCL and
what was not?
8A Solution
- Integrate the OCL directly into a high level
language - The OCL will be expressed separately from the
language constructs - Allows for enabling/disabling of the OCL and for
extracting the OCL constraints from the code
level back to the model
9Code Example
- class Customer
-
- OCL
-
- "context Customerage Integer"
- "init 18"
-
- private int age
-
10Why use C?
- Multipurpose high level language
- Fully reflexive (round trip)
- Source code available for compilers
- SSCLI
- MONO
- .NET languages are compatible
11Compiling C without OCL
12Compiling C and OCL
- Steps to add the OCL to the compilation process
- Construct an OCL parser
- Implement the OCL class library in C
- Map each OCL construct to a corresponding C
construct (or code block) - Merge the OCL parse tree(s) with the C parse
tree and generate executable code
13Compiling C and OCL
- The OCL lexical analyzer was written by hand
14Compiling C and OCL
- The parser was constructed using a parser
generator (JAY) from the OCL grammar
15Compiling C and OCL
- During the C semantic pass a reference model is
created - This reference model is used to perform the
semantic pass on the OCL AST(s)
16Compiling C and OCL
- Once the OCL semantic pass is complete the result
is merged into the C augmented AST - The resultant AST is then sent to the code
generator to generate the executable code
17Compiling C and OCL
18OclAnyallInstances()
- One of the issues that was encountered during the
implementation of our specialized compiler was
OclAnyallInstances() - The evaluation of the allInstances operation
requires determining the set of all active object
instances for a given classifier - As our application is being executed via the .NET
CLR it is non-trivial to obtain such a set
19Why is it non-trivial?
- The .NET CLR provides automated memory management
for both allocation and garbage collection - As memory management is abstracted away from the
programmer, it is difficult to determine which
object instances are allocated and active - We have devised an approach for accessing memory
management information from the CLR via the use
of the .NET Profiler API
20The big picture
21Enter the .NET Profiler API
- To obtain the set of live object instances we
will need to get inside the CLR and look at the
managed heaps - The .NET Profiler API allows for an external COM
component to monitor the execution and memory
usage of an application running under the CLR - Normally the profiler monitors the running
application and does not interfere with it - In our approach we will monitor object instance
allocation and garbage collection and we will
return this information to the managed application
22Implementing the Profiler
- The .NET Profiler API supports approximately
sixty events - We only need to specify behaviour for five of
them - ICorProfilerCallbackInitialize()
- ICorProfilerCallbackObjectAllocated()
- ICorProfilerCallbackMovedReferences()
- ICorProfilerCallBackObjectReferences()
- ICorProfilerCallbackRuntimeSuspendFinished()
23Initialize(IUnknown pICorProfilerInfoUnk)
- // Initialize - Sets up the profiler and
registers for the CLR events that we want - HRESULT COCLProfilerCallbackInitialize(IUnknown
pICorProfilerInfoUnk) -
- // Get the ICorProfilerInfo interface we need,
and stuff it away in a member variable. - HRESULT hr pICorProfilerInfoUnk-gtQueryInter
face(IID_ICorProfilerInfo, - (LPVOID )m_pICorProfilerInfo)
- if(FAILED(hr)) return E_INVALIDARG
- // Indicate which events we're interested in.
- m_dwEventMask 0
- m_dwEventMask COR_PRF_MONITOR_SUSPENDS //
For GC notification - m_dwEventMask COR_PRF_MONITOR_GC
// For all GC calls except ObjectAllocated - m_dwEventMask COR_PRF_ENABLE_OBJECT_ALLOCATED
// For ObjectAllocated call - m_dwEventMask COR_PRF_MONITOR_OBJECT_ALLOCATED
// For ObjectAllocated call - // Set the event mask
- m_pICorProfilerInfo-gtSetEventMask(m_dwEventMask)
- return S_OK
24ObjectAllocated(UINT objectId, UINT classId)
- ObjectAllocated is invoked every time memory on
the managed heap is allocated for a new object - The first parameter is a pointer to the managed
heap location where the object instance is being
stored - The second parameter is a pointer to the class
descriptor - The method stores the first parameter in an
internal data structure so that the object
instance can be found later - In order to reduce overhead, only classifiers
which are required are stored
25MovedReferences()
- MovedReferences is invoked to notify the profiler
that the garbage collector has moved one or more
object instance locations - The parameters specify the new locations for the
object instances (pointers) - The method simply updates the internal data
structure to reflect the new locations
26ObjectReferences()
- ObjectReferences is invoked once for each object
instance that remains in the managed heap after a
garbage collection operation - When the method is called we will mark the
corresponding object instance as active in our
internal data structure
27RuntimeSuspendFinished()
- RuntimeSuspendFinished is called once all of the
execution threads have been suspended for a
garbage collection operation - HRESULT COCLProfilerCallbackRuntimeSuspendFinish
ed() -
- // Loop through each of the objects and mark
them as collected - ObjectInstance oi m_objects.GetFirstItem()
- while(oi ! NULL)
-
- oi-gtCollect()
- oi m_objects.GetNextItem()
-
- return S_OK
28Getting the Information to the Managed Application
- The preceding five methods define a profiler that
will keep track of which object instances are
active at a given point in time - The next step is getting this information to the
managed application that is running - This is accomplished by having the profiler
export five methods that can be called from
within the managed application
29Getting the Information to the Managed Application
- // Determines if the OCL Profiler is attached to
this instance of the CLR VM - DllImport("OCLProfiler.dll")
- private static extern bool IsOCLProfilerAttached()
- // Registers the given classifier type with the
OCL Profiler so that we keep information - // about the classifier
- DllImport("OCLProfiler.dll", CharSetCharSet.Unic
ode) - private static extern void RegisterObject(string
name) - // Gets the number of instances that have been
allocated of the given classifier type - DllImport("OCLProfiler.dll", CharSetCharSet.Unic
ode) - private static extern int GetInstanceCount(string
name) - // Starts the instance copy operation. The
instance copy operation is used to build the - // allInstances set
- DllImport("OCLProfiler.dll")
- private static extern void StartInstanceCopy()
- // Stops the instance copy operation.
30Getting the Information to the Managed Application
- public static ArrayList GetInstancesFor(string
value, Type t) -
- VerifyProfiler()
- int count GetInstanceCountFor(value)
- ArrayList result new ArrayList()
- StartInstanceCopy()
- for(int i 0iltcounti)
-
- // Use the type information to create a new
object - // The profiler will be informed of the new
allocation - // and will copy the memory used by the
existing object - // into our new object...thus creating an
allInstances set - // that is a complete copy of each object
instance - Object obj t.InvokeMember(null,
BindingFlags.DeclaredOnly BindingFlags.Public
- BindingFlags.NonPublic BindingFlags.Instance
- BindingFlags.CreateInstance, null, null,
null) - result.Add(obj)
-
- StopInstanceCopy()
31Putting it all together
- We have integrated the previous method into our
specialized C/OCL compiler - Customer.allInstances()-gtforAll(c Customer
c.age gt 18) - bool result true
- foreach(Customer c in
- (Set)OCLProfilerControl.GetInstancesFor(Custo
mer, - System.Type.GetType(Customer)))
-
- result result (c.age gt 18)
-
32Putting it all together
- OCL
-
- "context AllInstancesMain() OclVoid"
- "post Customer.allInstances()-gtforAll(
- c Customer c.age gt 18)"
-
- public static void Main()
-
- Customer cs new Customer()
- cs.name "Dave"
- cs.age 27
- Customer cs2 new Customer()
- cs2.name "Mary"
- cs2.age 16
33Putting it all together
34Issues
- Threading
- Works in a single threaded model and uses
critical sections to prevent new object instances
from being created during the copying process,
etc. - Speed
- The runtime profiler introduces significant
overhead, thus reducing performance - As the OCL constraints are designed to be used
during development only this may not be an issue
35Conclusion
- The method presented here has been used to
implement software based constraints via the
OclAnyAllInstances operation - It would be interesting to explore other uses for
the complete set of live object instances - We are currently exploring how our method can be
used in the verification and validation of
non-functional requirements
36Acknowledgements Additional Information
- Acknowledgements
- Funding for this work has been generously
provided by the Natural Sciences and Engineering
Research Council of Canada - Additional Information Source Code
- http//www.ewebsimplex.ca/csocl
- or email dave_at_scs.carleton.ca
- Questions or Comments?