MPI is a declarative, event-based interface, offering a variety of well-defined events and data request operations. Some of the events may be optionally restricted to specific selective criteria, such as specific classes rather than all, reducing the overhead and the amount of data generated.
An MPI client registers to relevant events and event-specific data by implementing Event Observer objects. Once the event occurs, the Observer's HandleEvent
callback function is called, with event-specific data passed as an argument. Additional data can be retrieved by calling one of the data request functions.
More that one profiler can use MPI at the same time. Each profiler registers to its own events and receives notification only for the events to which it registered.
IMpi::RegisterEvent
function. The client can optionally override the observer's EventDataTypes
method and specify the data items to be supplied with the event. After registration, when the requested event occurs, the Event Observer's HandleEvent
function is called with the requested data as an argument.The following example shows how to define and register an event observer for the Method Enter MPI event:
using namespace Martini::MPI; // Define an event observer for the Method Enter event class MethodEnterObserver : public IMethodEnterEventObserver { public: // Specify the data items to be supplied with the event virtual BitSet EventDataTypes() { return DR_METHOD_ID | DR_THREAD_ID; } // Event handler virtual void HandleEvent(SMethodEnterEventData &data) { cout << "Method Enter event received. Method id = " << data.methodId << " Thread id = " << data.threadId << endl; } } // Event Observer instance MethodEnterObserver g_methodEnterObserver; // MPI Client entry point extern "C" API_EXPORT TResult MPICL_Instantiate(IMpi *pMpiApi, TId clientId, const char *szOptions) { TResult res = pMpiApi->RegisterEvent(clientId, g_methodEnterObserver); return MRTE_RESULT_OK; }
Since applying filters usually make sense for a group of events rather than for an individual event, MPI Event Filters are applied to Event Groups and not to specific events.
MPI defines the following event groups:
To apply a filter to an MPI event group, the MPI client must define an Event Filter class for the specific event group it wants to restrict, and then register an instance of this class with Martini using the IMpi::SetEventGroupFilter
function.
After registration, The Event Filter's ShouldNotify
function will be called by Martini to determine the set of elements for which to generate the events belonging to the restricted group.
The following example shows how to instruct Martini to generate Method Enter and Method Leave events only for public methods of the public class Foo:
using namespace Martini::MPI; // Define a call-graph event filter class CallGraphFilter : public ICallGraphFilter { bool ShouldNotify(SCallGraphFilterData &methodInfo) { if (strcmp("Foo", data.szClassName) == 0 && data.methodAccessType == MAT_PACKAGE_API) { return true; } return false; } }; // Event Observer instance MethodEnterObserver g_methodEnterObserver; // Event Filter instance CallGraphFilter g_callGraphFilter; // MPI Client entry point extern "C" API_EXPORT TResult MPICL_Instantiate(IMpi *pMpiApi, TId clientId, const char *szOptions) { // Register for the Method Enter event pMpiApi->RegisterEvent(clientId, g_methodEnterObserver); // Set the call-graph filter pMpiApi->SetEventGroupFilter(clientId, EG_CALL_GRAPH, g_callGraphFilter); return MRTE_RESULT_OK; }
All data request functions has the following definition
virtual TResult GetElementInfo(TId clientId, TId ElementId, BitSet requestedDataTypes, SElementInfo *pData);
Where Element represents the type of element for which to retrieve information.
The data request functions are all used in the following way:
clientId
parameterElementId
parameter (moduleId
, classId
, objectId
, etc...).requestedDataTypes
parameter. Data items are specified as a combination of TDataRequestType consts OR'ed together (see Data Request Types).pData
parameter. Upon return, MPI will write the requested data to this structure and will set the pData->validData
field to indicate which data items were successfully retrieved.All data request return one of the following values:
MRTE_RESULT_OK | If data successfully retrieved | |
MRTE_ERROR_PARTIAL_INFO | If not all data items could be retrieved. The client should examine the 'pData->validData' field to check which data items were returned. | |
MRTE_ERROR_BUFFER_TOO_SHORT | For requests that return arrays, indicates that not enough space was allocated to return all the available information. For more information, refer to the Working with MPI Arrays section. | |
MRTE_ERROR_NULL_PTR | If pData is NULL, or one of its requested pointer fields is NULL | |
MRTE_ERROR_ILLEGAL_ID | If clientId is not a valid MPI client id | |
MRTE_ERROR_NOT_SUPPORTED | If one of the specified data items is not supported by the data request. | |
MRTE_ERROR_PHASE_FAILURE | If the requested information cannot be retrieved before the VM has initialized. The client should request the information only after the VM Init event has been sent. | |
MRTE_ERROR_FAIL | If failed to retrieve data |
pData
argument must be allocated by the client before calling the data request function. Memory must be allocated for pointer fields that correspond to requested data items as well.IMpi *g_pMpiApi; void CNewMethodObserver::HandleEvent(SNewMethodEventData &data) { char szName[1000]; char szSig[1000]; SMethodInfo methodInfo; methodInfo.szMethodName = szName; methodInfo.szMethodSig = szSig; TResult res = g_pMpiApi->GetMethodInfo(m_clientId, data.methodId, DR_METHOD_NAME | DR_METHOD_SIGNATURE, &methodInfo); }
All MPI arrays are defined as structs similar to the following
struct SArray { TArrayElement *entries; unsigned int uiSize; unsigned int uiActualSize; };
entries
member is a pointer to the array elementsuiSize
member indicates the size of the entries
array.uiSize
member. When the data request returns, the uiActualSize
member will indicate the number of entries that were populated. If not enough entries were allocated, the first uiSize
entries will be populated, the uiActualSize
member will indicate the actual number of available entries and the Data Request operation will return the MRTE_ERROR_BUFFER_TOO_SHORT error. (C) Copyright Intel Corporation 2007-2008. All Rights Reserved.
Generated on Thu Mar 6 15:07:55 2008 for Martini by