// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2019 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #ifndef PXPVDSDK_PXPROFILEZONEIMPL_H #define PXPVDSDK_PXPROFILEZONEIMPL_H #include "PxPvdProfileZone.h" #include "PxProfileZoneManager.h" #include "PxProfileContextProviderImpl.h" #include "PxProfileScopedMutexLock.h" #include "PxProfileEventBufferAtomic.h" #include "PsMutex.h" namespace physx { namespace profile { /** \brief Simple event filter that enables all events. */ struct PxProfileNullEventFilter { void setEventEnabled( const PxProfileEventId&, bool) { PX_ASSERT(false); } bool isEventEnabled( const PxProfileEventId&) const { return true; } }; typedef shdfnd::MutexT > TZoneMutexType; typedef ScopedLockImpl TZoneLockType; typedef EventBuffer< PxDefaultContextProvider, TZoneMutexType, TZoneLockType, PxProfileNullEventFilter > TZoneEventBufferType; //typedef EventBufferAtomic< PxDefaultContextProvider, TZoneMutexType, TZoneLockType, PxProfileNullEventFilter > TZoneEventBufferType; template class ZoneImpl : TZoneEventBufferType //private inheritance intended , public PxProfileZone , public PxProfileEventBufferClient { typedef shdfnd::MutexT > TMutexType; typedef PxProfileHashMap TNameToEvtIndexMap; //ensure we don't reuse event ids. typedef PxProfileHashMap TEvtIdToNameMap; typedef TMutexType::ScopedLock TLockType; const char* mName; mutable TMutexType mMutex; PxProfileArray mEventNames; // to avoid locking, read-only and read-write map exist TNameToEvtIndexMap mNameToEvtIndexMapR; TNameToEvtIndexMap mNameToEvtIndexMapRW; //ensure we don't reuse event ids. TEvtIdToNameMap mEvtIdToNameMap; PxProfileZoneManager* mProfileZoneManager; PxProfileArray mZoneClients; volatile bool mEventsActive; PX_NOCOPY(ZoneImpl) public: ZoneImpl( PxAllocatorCallback* inAllocator, const char* inName, uint32_t bufferSize = 0x10000 /*64k*/, const TNameProvider& inProvider = TNameProvider() ) : TZoneEventBufferType( inAllocator, bufferSize, PxDefaultContextProvider(), NULL, PxProfileNullEventFilter() ) , mName( inName ) , mMutex( PxProfileWrapperReflectionAllocator( mWrapper ) ) , mEventNames( mWrapper ) , mNameToEvtIndexMapR( mWrapper ) , mNameToEvtIndexMapRW( mWrapper ) , mEvtIdToNameMap( mWrapper ) , mProfileZoneManager( NULL ) , mZoneClients( mWrapper ) , mEventsActive( false ) { TZoneEventBufferType::setBufferMutex( &mMutex ); //Initialize the event name structure with existing names from the name provider. PxProfileNames theNames( inProvider.getProfileNames() ); for ( uint32_t idx = 0; idx < theNames.eventCount; ++idx ) { const PxProfileEventName& theName (theNames.events[idx]); doAddName( theName.name, theName.eventId.eventId, theName.eventId.compileTimeEnabled ); } TZoneEventBufferType::addClient( *this ); } virtual ~ZoneImpl() { if ( mProfileZoneManager != NULL ) mProfileZoneManager->removeProfileZone( *this ); mProfileZoneManager = NULL; TZoneEventBufferType::removeClient( *this ); } void doAddName( const char* inName, uint16_t inEventId, bool inCompileTimeEnabled ) { TLockType theLocker( mMutex ); mEvtIdToNameMap.insert( inEventId, inName ); uint32_t idx = static_cast( mEventNames.size() ); mNameToEvtIndexMapRW.insert( inName, idx ); mEventNames.pushBack( PxProfileEventName( inName, PxProfileEventId( inEventId, inCompileTimeEnabled ) ) ); } virtual void flushEventIdNameMap() { // copy the RW map into R map if (mNameToEvtIndexMapRW.size()) { for (TNameToEvtIndexMap::Iterator iter = mNameToEvtIndexMapRW.getIterator(); !iter.done(); ++iter) { mNameToEvtIndexMapR.insert(iter->first, iter->second); } mNameToEvtIndexMapRW.clear(); } } virtual uint16_t getEventIdForName( const char* inName ) { return getEventIdsForNames( &inName, 1 ); } virtual uint16_t getEventIdsForNames( const char** inNames, uint32_t inLen ) { if ( inLen == 0 ) return 0; // search the read-only map first const TNameToEvtIndexMap::Entry* theEntry( mNameToEvtIndexMapR.find( inNames[0] ) ); if ( theEntry ) return mEventNames[theEntry->second].eventId; TLockType theLocker(mMutex); const TNameToEvtIndexMap::Entry* theReEntry(mNameToEvtIndexMapRW.find(inNames[0])); if (theReEntry) return mEventNames[theReEntry->second].eventId; //Else git R dun. uint16_t nameSize = static_cast( mEventNames.size() ); //We don't allow 0 as an event id. uint16_t eventId = nameSize; //Find a contiguous set of unique event ids bool foundAnEventId = false; do { foundAnEventId = false; ++eventId; for ( uint16_t idx = 0; idx < inLen && foundAnEventId == false; ++idx ) foundAnEventId = mEvtIdToNameMap.find( uint16_t(eventId + idx) ) != NULL; } while( foundAnEventId ); uint32_t clientCount = mZoneClients.size(); for ( uint16_t nameIdx = 0; nameIdx < inLen; ++nameIdx ) { uint16_t newId = uint16_t(eventId + nameIdx); doAddName( inNames[nameIdx], newId, true ); for( uint32_t clientIdx =0; clientIdx < clientCount; ++clientIdx ) mZoneClients[clientIdx]->handleEventAdded( PxProfileEventName( inNames[nameIdx], PxProfileEventId( newId ) ) ); } return eventId; } virtual void setProfileZoneManager(PxProfileZoneManager* inMgr) { mProfileZoneManager = inMgr; } virtual PxProfileZoneManager* getProfileZoneManager() { return mProfileZoneManager; } const char* getName() { return mName; } PxProfileEventBufferClient* getEventBufferClient() { return this; } //SDK implementation void addClient( PxProfileZoneClient& inClient ) { TLockType lock( mMutex ); mZoneClients.pushBack( &inClient ); mEventsActive = true; } void removeClient( PxProfileZoneClient& inClient ) { TLockType lock( mMutex ); for ( uint32_t idx =0; idx < mZoneClients.size(); ++idx ) { if (mZoneClients[idx] == &inClient ) { inClient.handleClientRemoved(); mZoneClients.replaceWithLast( idx ); break; } } mEventsActive = mZoneClients.size() != 0; } virtual bool hasClients() const { return mEventsActive; } virtual PxProfileNames getProfileNames() const { TLockType theLocker( mMutex ); const PxProfileEventName* theNames = mEventNames.begin(); uint32_t theEventCount = uint32_t(mEventNames.size()); return PxProfileNames( theEventCount, theNames ); } virtual void release() { PX_PROFILE_DELETE( mWrapper.getAllocator(), this ); } //Implementation chaining the buffer flush to our clients virtual void handleBufferFlush( const uint8_t* inData, uint32_t inLength ) { TLockType theLocker( mMutex ); uint32_t clientCount = mZoneClients.size(); for( uint32_t idx =0; idx < clientCount; ++idx ) mZoneClients[idx]->handleBufferFlush( inData, inLength ); } //Happens if something removes all the clients from the manager. virtual void handleClientRemoved() {} //Send a profile event, optionally with a context. Events are sorted by thread //and context in the client side. virtual void startEvent( uint16_t inId, uint64_t contextId) { if( mEventsActive ) { TZoneEventBufferType::startEvent( inId, contextId ); } } virtual void stopEvent( uint16_t inId, uint64_t contextId) { if( mEventsActive ) { TZoneEventBufferType::stopEvent( inId, contextId ); } } virtual void startEvent( uint16_t inId, uint64_t contextId, uint32_t threadId) { if( mEventsActive ) { TZoneEventBufferType::startEvent( inId, contextId, threadId ); } } virtual void stopEvent( uint16_t inId, uint64_t contextId, uint32_t threadId ) { if( mEventsActive ) { TZoneEventBufferType::stopEvent( inId, contextId, threadId ); } } virtual void atEvent(uint16_t inId, uint64_t contextId, uint32_t threadId, uint64_t start, uint64_t stop) { if (mEventsActive) { TZoneEventBufferType::startEvent(inId, threadId, contextId, 0, 0, start); TZoneEventBufferType::stopEvent(inId, threadId, contextId, 0, 0, stop); } } /** * Set an specific events value. This is different than the profiling value * for the event; it is a value recorded and kept around without a timestamp associated * with it. This value is displayed when the event itself is processed. */ virtual void eventValue( uint16_t inId, uint64_t contextId, int64_t inValue ) { if( mEventsActive ) { TZoneEventBufferType::eventValue( inId, contextId, inValue ); } } virtual void flushProfileEvents() { TZoneEventBufferType::flushProfileEvents(); } }; }} #endif // PXPVDSDK_PXPROFILEZONEIMPL_H