-//
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Flora License, Version 1.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://floralicense.org/license/
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an AS IS BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
// CLASS HEADER
#include "performance-server.h"
+// EXTERNAL INCLUDES
+#include <dali/integration-api/platform-abstraction.h>
+
// INTERNAL INCLUDES
#include <base/environment-options.h>
+#include <base/time-service.h>
namespace Dali
{
namespace Adaptor
{
-#define TIME_FMT "%0.2f ms" // 2 decimal places, e.g. 5.34 ms
-#define TOTAL_TIME_FMT "%0.1f secs" // 1 decimal place, e.g. 4.5 seconds
-
-
namespace
{
-const unsigned int DEFAULT_LOG_FREQUENCEY = 2; ///< default log frequency = 2
-const unsigned int MILLISECONDS_PER_SECOND = 1000; ///< 1000 milliseconds per second
-const unsigned int MICROSECONDS_PER_SECOND = 1000000; ///< 1000000 microseconds per second
-}
-
+const unsigned int NANOSECONDS_PER_MICROSECOND = 1000u;
+const float MICROSECONDS_TO_SECOND = 1e-6;
+} // unnamed namespace
PerformanceServer::PerformanceServer( AdaptorInternalServices& adaptorServices,
const EnvironmentOptions& environmentOptions)
-:mLoggingEnabled( false),
- mLogFunctionInstalled( false ),
- mLogFrequencyMicroseconds( 0),
- mPlatformAbstraction( adaptorServices.GetPlatformAbstractionInterface() ),
- mEnvironmentOptions(environmentOptions),
- mKernelTrace( adaptorServices.GetKernelTraceInterface() )
+: mEnvironmentOptions( environmentOptions ),
+ mKernelTrace( adaptorServices.GetKernelTraceInterface() ),
+ mSystemTrace( adaptorServices.GetSystemTraceInterface() ),
+ mLogMutex(),
+#if defined(NETWORK_LOGGING_ENABLED)
+ mNetworkServer( adaptorServices, environmentOptions ),
+ mNetworkControlEnabled( mEnvironmentOptions.GetNetworkControlMode()),
+#endif
+ mStatContextManager( *this ),
+ mStatisticsLogBitmask( 0 ),
+ mPerformanceOutputBitmask( 0 ),
+ mLoggingEnabled( false ),
+ mLogFunctionInstalled( false )
{
- SetLogging( mEnvironmentOptions.GetPerformanceLoggingLevel(), mEnvironmentOptions.GetFrameRateLoggingFrequency());
+ SetLogging( mEnvironmentOptions.GetPerformanceStatsLoggingOptions(),
+ mEnvironmentOptions.GetPerformanceTimeStampOutput(),
+ mEnvironmentOptions.GetPerformanceStatsLoggingFrequency());
+
+#if defined(NETWORK_LOGGING_ENABLED)
+ if( mNetworkControlEnabled )
+ {
+ mLoggingEnabled = true;
+ mNetworkServer.Start();
+ }
+#endif
}
PerformanceServer::~PerformanceServer()
{
+#if defined(NETWORK_LOGGING_ENABLED)
+ if( mNetworkControlEnabled )
+ {
+ mNetworkServer.Stop();
+ }
+#endif
+
if( mLogFunctionInstalled )
{
mEnvironmentOptions.UnInstallLogFunction();
}
}
-void PerformanceServer::SetLogging( unsigned int level, unsigned int interval)
+
+void PerformanceServer::SetLogging( unsigned int statisticsLogOptions,
+ unsigned int timeStampOutput,
+ unsigned int logFrequency )
{
- if( level == 0)
+ mStatisticsLogBitmask = statisticsLogOptions;
+ mPerformanceOutputBitmask = timeStampOutput;
+
+ mStatContextManager.SetLoggingLevel( mStatisticsLogBitmask, logFrequency);
+
+ if( ( mStatisticsLogBitmask == 0) && ( mPerformanceOutputBitmask == 0 ))
{
mLoggingEnabled = false;
- return;
}
- mLogLevel = level;
-
- mLogFrequencyMicroseconds = interval * MICROSECONDS_PER_SECOND;
-
- if( mLogFrequencyMicroseconds == 0 )
+ else
{
- mLogFrequencyMicroseconds = DEFAULT_LOG_FREQUENCEY * MICROSECONDS_PER_SECOND;
+ mLoggingEnabled = true;
}
- mLoggingEnabled = true;
+}
+
+void PerformanceServer::SetLoggingFrequency( unsigned int logFrequency, ContextId contextId )
+{
+ mStatContextManager.SetLoggingFrequency( logFrequency, contextId );
+}
+
+void PerformanceServer::EnableLogging( bool enable, ContextId contextId )
+{
+ mStatContextManager.EnableLogging( enable, contextId );
+}
+
+PerformanceInterface::ContextId PerformanceServer::AddContext( const char* name )
+{
+ // for adding custom contexts
+ return mStatContextManager.AddContext( name, PerformanceMarker::CUSTOM_EVENTS );
+}
+void PerformanceServer::RemoveContext( ContextId contextId )
+{
+ mStatContextManager.RemoveContext( contextId );
}
-void PerformanceServer::AddMarker( PerformanceMarker::MarkerType markerType )
+void PerformanceServer::AddMarker( MarkerType markerType, ContextId contextId )
{
+ // called only for custom markers
+
if( !mLoggingEnabled )
{
return;
}
- unsigned int seconds(0);
- unsigned int microseconds(0);
+ // Get the time stamp
+ uint64_t timeStamp = 0;
+ TimeService::GetNanoseconds( timeStamp );
+ timeStamp /= NANOSECONDS_PER_MICROSECOND; // Convert to microseconds
+
+ // Create a marker
+ PerformanceMarker marker( markerType, FrameTimeStamp( 0, timeStamp ) );
- // get the time
- mPlatformAbstraction.GetTimeMicroseconds( seconds, microseconds );
+ // get the marker description for this context, e.g SIZE_NEGOTIATION_START
+ const char* const description = mStatContextManager.GetMarkerDescription( markerType, contextId );
- // create a marker
- PerformanceMarker marker( markerType, FrameTimeStamp( 0, seconds, microseconds ));
+ // log it
+ LogMarker( marker, description );
- AddMarkerToLog( marker );
+ // Add custom marker to statistics context manager
+ mStatContextManager.AddCustomMarker( marker, contextId );
}
-void PerformanceServer::AddMarkerToLog( PerformanceMarker marker )
+void PerformanceServer::AddMarker( MarkerType markerType )
{
- // Add Marker can be called from any thread
- boost::mutex::scoped_lock sharedDatalock( mDataMutex );
+ // called only for internal markers
- // store the marker
- mMarkers.PushBack( marker );
-
- if( mLogLevel & LOG_EVENTS_TO_KERNEL )
+ if( !mLoggingEnabled )
{
- mKernelTrace.Trace(marker.GetName());
+ return;
}
- // only log on the v-sync thread, so we have less impact on update/render
- if( marker.GetType() != PerformanceMarker::V_SYNC )
+ if( markerType == VSYNC )
{
- return;
+ // make sure log function is installed, note this will be called only from v-sync thread
+ // if the v-sync thread has already installed one, it won't make any difference.
+ if( ! mLogFunctionInstalled )
+ {
+ mEnvironmentOptions.InstallLogFunction();
+ mLogFunctionInstalled = true;
+ }
}
- // log out every mLogFrequency.
- // check difference between first and last frame
- unsigned int microseconds = PerformanceMarker::MicrosecondDiff( mMarkers[0], marker );
+ // Get the time
+ uint64_t timeStamp = 0;
+ TimeService::GetNanoseconds( timeStamp );
+ timeStamp /= NANOSECONDS_PER_MICROSECOND; // Convert to microseconds
- if( microseconds >= mLogFrequencyMicroseconds )
- {
- LogMarkers( );
- mMarkers.Clear();
+ // Create a marker
+ PerformanceMarker marker( markerType, FrameTimeStamp( 0, timeStamp ) );
+
+ // log it
+ LogMarker(marker, marker.GetName() );
+
+ // Add internal marker to statistics context manager
+ mStatContextManager.AddInternalMarker( marker );
- // reset data for update / render statistics
- mUpdateStats.Reset();
- mRenderStats.Reset();
- mEventStats.Reset();
- }
}
-void PerformanceServer::LogMarker(const char* name, const FrameTimeStats& frameStats)
+void PerformanceServer::LogContextStatistics( const char* const text )
{
- // make sure log function is installed, note this will be called only from v-sync thread
- // if the v-sync thread has already installed one, it won't make any difference.
- if(! mLogFunctionInstalled )
- {
- mEnvironmentOptions.InstallLogFunction();
- mLogFunctionInstalled = true;
- }
-
- // this will always log regardless of debug / release mode
- Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo,
- "%s , min " TIME_FMT ", max " TIME_FMT ", total (" TOTAL_TIME_FMT "), avg " TIME_FMT "\n",
- name,
- frameStats.GetMinTime() * MILLISECONDS_PER_SECOND,
- frameStats.GetMaxTime() * MILLISECONDS_PER_SECOND,
- frameStats.GetTotalTime(),
- frameStats.GetRollingAverageTime() * MILLISECONDS_PER_SECOND);
+ Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, text );
}
-void PerformanceServer::LogMarkers()
+void PerformanceServer::LogMarker( const PerformanceMarker& marker, const char* const description )
{
- // insert time stamps into a frame-time-stats object, based on type
- for( MarkerVector::SizeType i = 0; i < mMarkers.Size(); ++i)
+#if defined(NETWORK_LOGGING_ENABLED)
+ // log to the network ( this is thread safe )
+ if( mNetworkControlEnabled )
{
- const PerformanceMarker& marker = mMarkers[i];
- switch( marker.GetType() )
- {
- case PerformanceMarker::UPDATE_START:
- {
- mUpdateStats.StartTime( marker.GetTimeStamp() );
- break;
- }
- case PerformanceMarker::UPDATE_END:
- {
- mUpdateStats.EndTime( marker.GetTimeStamp() );
- break;
- }
- case PerformanceMarker::RENDER_START:
- {
- mRenderStats.StartTime( marker.GetTimeStamp() );
- break;
- }
- case PerformanceMarker::RENDER_END:
- {
- mRenderStats.EndTime( marker.GetTimeStamp() );
- break;
- }
- case PerformanceMarker::PROCESS_EVENTS_START:
- {
- mEventStats.StartTime( marker.GetTimeStamp() );
- break;
- }
- case PerformanceMarker::PROCESS_EVENTS_END:
- {
- mEventStats.EndTime( marker.GetTimeStamp() );
- break;
- }
- default:
- {
- break;
- }
- }
+ mNetworkServer.TransmitMarker( marker, description );
}
- if( mLogLevel & LOG_UPDATE_RENDER )
+#endif
+
+ // log to kernel trace
+ if( mPerformanceOutputBitmask & OUTPUT_KERNEL_TRACE )
{
- LogMarker("Update",mUpdateStats);
- LogMarker("Render",mRenderStats);
+ // Kernel tracing implementation may not be thread safe
+ Mutex::ScopedLock lock( mLogMutex );
+ // description will be something like UPDATE_START or UPDATE_END
+ mKernelTrace.Trace( marker, description );
}
- if( mLogLevel & LOG_EVENT_PROCESS )
+
+ // log to system trace
+ if( mPerformanceOutputBitmask & OUTPUT_SYSTEM_TRACE )
{
- LogMarker("Event",mEventStats);
+ // System tracing implementation may not be thread safe
+ Mutex::ScopedLock lock( mLogMutex );
+
+ mSystemTrace.Trace( marker, description );
}
+ // log to Dali log ( this is thread safe )
+ if ( mPerformanceOutputBitmask & OUTPUT_DALI_LOG )
+ {
+ Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo,
+ "%.6f (seconds), %s\n",
+ (float)( marker.GetTimeStamp().microseconds * MICROSECONDS_TO_SECOND ),
+ description);
+
+ }
}
+
} // namespace Internal
} // namespace Adaptor