|
RavEngine
|
#include <PxProfileEventBuffer.h>
Public Types | |
| typedef DataBuffer< TMutex, TScopedLock > | TBaseType |
| typedef TContextProvider | TContextProviderType |
| typedef TEventFilter | TEventFilterType |
| typedef TBaseType::TMutexType | TMutexType |
| typedef TBaseType::TScopedLockType | TScopedLockType |
| typedef TBaseType::TU8AllocatorType | TU8AllocatorType |
| typedef TBaseType::TMemoryBufferType | TMemoryBufferType |
| typedef TBaseType::TBufferClientArray | TBufferClientArray |
Public Types inherited from physx::profile::DataBuffer< TMutex, TScopedLock > | |
| typedef TMutex | TMutexType |
| typedef TScopedLock | TScopedLockType |
| typedef PxProfileWrapperNamedAllocator | TU8AllocatorType |
| typedef MemoryBuffer< TU8AllocatorType > | TMemoryBufferType |
| typedef PxProfileArray< PxProfileEventBufferClient * > | TBufferClientArray |
Public Member Functions | |
| EventBuffer (PxAllocatorCallback *inFoundation, uint32_t inBufferFullAmount, const TContextProvider &inProvider, TMutexType *inBufferMutex, const TEventFilterType &inEventFilter) | |
| TContextProvider & | getContextProvider () |
| PX_FORCE_INLINE void | startEvent (uint16_t inId, uint32_t threadId, uint64_t contextId, uint8_t cpuId, uint8_t threadPriority, uint64_t inTimestamp) |
| PX_FORCE_INLINE void | startEvent (uint16_t inId, uint64_t contextId) |
| PX_FORCE_INLINE void | startEvent (uint16_t inId, uint64_t contextId, uint32_t threadId) |
| PX_FORCE_INLINE void | stopEvent (uint16_t inId, uint32_t threadId, uint64_t contextId, uint8_t cpuId, uint8_t threadPriority, uint64_t inTimestamp) |
| PX_FORCE_INLINE void | stopEvent (uint16_t inId, uint64_t contextId) |
| PX_FORCE_INLINE void | stopEvent (uint16_t inId, uint64_t contextId, uint32_t threadId) |
| void | eventValue (uint16_t inId, uint64_t contextId, int64_t inValue) |
| void | eventValue (uint16_t inId, uint32_t threadId, uint64_t contextId, int64_t inValue) |
| void | flushProfileEvents () |
| void | release () |
Public Member Functions inherited from physx::profile::DataBuffer< TMutex, TScopedLock > | |
| DataBuffer (PxAllocatorCallback *inFoundation, uint32_t inBufferFullAmount, TMutexType *inBufferMutex, const char *inAllocationName) | |
| PxProfileAllocatorWrapper & | getWrapper () |
| TMutexType * | getBufferMutex () |
| void | setBufferMutex (TMutexType *mutex) |
| void | addClient (PxProfileEventBufferClient &inClient) |
| void | removeClient (PxProfileEventBufferClient &inClient) |
| bool | hasClients () const |
| virtual void | flushEvents () |
| virtual void | handleBufferFlush (const uint8_t *inData, uint32_t inDataSize) |
Protected Member Functions | |
| void | clearCachedData () |
| template<typename TProfileEventType > | |
| PX_FORCE_INLINE void | doAddProfileEvent (uint16_t eventId, const TProfileEventType &inType) |
| template<typename TDataType > | |
| PX_FORCE_INLINE void | doAddEvent (uint8_t inEventType, uint16_t eventId, const TDataType &inType) |
| template<typename TDataType > | |
| PX_FORCE_INLINE void | sendEvent (EventHeader &inHeader, TDataType &inType) |
Additional Inherited Members | |
Protected Attributes inherited from physx::profile::DataBuffer< TMutex, TScopedLock > | |
| PxProfileAllocatorWrapper | mWrapper |
| TMemoryBufferType | mDataArray |
| TBufferClientArray | mBufferClients |
| uint32_t | mBufferFullAmount |
| EventContextInformation | mEventContextInformation |
| TMutexType * | mBufferMutex |
| volatile bool | mHasClients |
| EventSerializer< TMemoryBufferType > | mSerializer |
An event buffer maintains an in-memory buffer of events. When this buffer is full it sends to buffer to all handlers registered and resets the buffer.
It is parameterized in four ways. The first is a context provider that provides both thread id and context id.
The second is the mutex (which may be null) and a scoped locking mechanism. Thus the buffer may be used in a multithreaded context but clients of the buffer don't pay for this if they don't intend to use it this way.
Finally the buffer may use an event filtering mechanism. This mechanism needs one function, namely isEventEnabled( uint8_t subsystem, uint8_t eventId ).
All of these systems can be parameterized at compile time leading to an event buffer that should be as fast as possible given the constraints.
Buffers may be chained together as this buffer has a handleBufferFlush method that will grab the mutex and add the data to this event buffer.
Overall, lets look at the PhysX SDK an how all the pieces fit together. The SDK should have a mutex-protected event buffer where actual devs or users of PhysX can register handlers. This buffer has slow but correct implementations of the context provider interface.
The SDK object should also have a concrete event filter which was used in the construction of the event buffer and which it exposes through opaque interfaces.
The SDK should protect its event buffer and its event filter from multithreaded access and thus this provides the safest and slowest way to log events and to enable/disable events.
Each scene should also have a concrete event filter. This filter is updated from the SDK event filter (in a mutex protected way) every frame. Thus scenes can change their event filtering on a frame-by-frame basis. It means that tasks running under the scene don't need a mutex when accessing the filter.
Furthermore the scene should have an event buffer that always sets the context id on each event to the scene. This allows PVD and other systems to correlate events to scenes. Scenes should provide access only to a relative event sending system that looks up thread id upon each event but uses the scene id.
The SDK's event buffer should be setup as an EventBufferClient for each scene's event buffer. Thus the SDK should expose an EventBufferClient interface that any client can use.
For extremely extremely performance sensitive areas we should create a specialized per-scene, per-thread event buffer that is set on the task for these occasions. This buffer uses a trivial event context setup with the scene's context id and the thread id. It should share the scene's concrete event filter and it should have absolutely no locking. It should empty into the scene's event buffer which in some cases should empty into the SDK's event buffer which when full will push events all the way out of the system. The task should always flush the event buffer (if it has one) when it is finished; nothing else will work reliably.
If the per-scene,per-thread event buffer is correctly parameterized and fully defined adding a new event should be an inline operation requiring no mutex grabs in the common case. I don't believe you can get faster event production than this; the events are as small as possible (all relative events) and they are all produced inline resulting in one 4 byte header and one 8 byte timestamp per event. Reducing the memory pressure in this way reduces the communication overhead, the mutex grabs, basically everything that makes profiling expensive at the cost of a per-scene,per-thread event buffer (which could easily be reduced to a per-thread event buffer.
|
inlineprotectedvirtual |
Reimplemented from physx::profile::DataBuffer< TMutex, TScopedLock >.