2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://floralicense.org/license/
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 #include <dali/internal/render/common/performance-monitor.h>
26 #include <dali/public-api/common/dali-common.h>
27 #include <dali/integration-api/debug.h>
28 #include <dali/integration-api/platform-abstraction.h>
31 #if defined(PRINT_TIMERS) || defined(PRINT_COUNTERS) || defined(PRINT_DRAW_CALLS) || defined(PRINT_MATH_COUNTERS)
41 PerformanceMonitor *mInstance = NULL;
42 const float epsilon = 0.9f; // smooth average = (average * epsilon) + (current * epsilon)
44 const unsigned int MICROSECONDS_PER_SECOND = 1000000;
45 const unsigned int NANOSECS_TO_MICROSECS = 1000; ///< 1000 nanoseconds = 1 microsecond
48 * Structure similar to timespec which holds the seconds and millisecond values.
53 unsigned int microSeconds;
57 * Returns the time difference in seconds (as a float)
59 float Diff(const TimeInfo& start, const TimeInfo& end)
61 int diff = end.microSeconds - start.microSeconds;
64 diff += MICROSECONDS_PER_SECOND;
66 return (float) diff / MICROSECONDS_PER_SECOND;
69 } // unnamed namespace
72 * Base performance metric class, needs overloading
74 class PerformanceMetric
82 FPS_TIMER, ///< timer that outputs in frames per second
83 COUNTER, ///< counter that is set once per frame using SET macro
84 INC_COUNTER, ///< incremental counter which is set multiple times per frame (e.g. to count number of draw calls).
85 DATA_COUNTER, ///< used to measure changes in data, e.g. amount of texture data uploaded
88 PerformanceMetric(MetricType type):mType(type) {}
90 virtual void SetFloat(float value) {}
91 virtual void SetInt(unsigned int value) {}
92 virtual void IncreaseBy(unsigned int value) {}
93 virtual void Tick() {}
94 virtual void Reset() {};
95 virtual void Log() = 0;
97 bool mEnabled; ///< whether the metric is enabled
98 MetricType mType; ///< type of metric
99 std::string mName; ///< name
100 unsigned int mMetricId; ///< unique id
104 * Timer metric, used to measure elapsed time each frame (e.g. for frame rate)
106 class TimerMetric : public PerformanceMetric
111 : PerformanceMetric( TIMER ),
121 mMin = 10.0; // default min to 10 seconds
127 LogMessage( Integration::Log::DebugInfo, "%s min: %.06f, max: %.06f, total %.06f, average: %.06f, count: %.0f, mean: %f\n", mName.c_str(), mMin, mMax, mTotal, mAvg, mCount, mTotal/mCount );
139 * Timer metric, used to measure elapsed time each frame (e.g. for frame rate)
141 class FPSTimerMetric : public TimerMetric
147 LogMessage( Integration::Log::DebugInfo, "%s average: %04f\n", mName.c_str(), 1.0f/mAvg );
153 * Counter class, used to measure things like the number of nodes drawn
155 class CounterMetric : public PerformanceMetric
159 CounterMetric():PerformanceMetric(COUNTER) { Reset();}
168 * Used for values set one per-frame, e.g. number of messages
170 void SetInt(unsigned int value)
189 mAvg = ((float)mAvg * epsilon) + ((float)value * (1.0f - epsilon));
194 LogMessage(Integration::Log::DebugInfo, "%s min: %04d, max: %04d, average: %04d\n",mName.c_str(),mMin,mMax,mAvg);
205 * Incremental Counter class, used to measure things like the number of nodes drawn
207 class IncCounterMetric : public PerformanceMetric
210 IncCounterMetric():PerformanceMetric(INC_COUNTER){ Reset();}
220 * Used for values that are set multiple times a frame, e.g. number of draw calls
222 void IncreaseBy(unsigned int value)
243 mAvg = ((float)mAvg * epsilon) + ((float)mCurrent * (1.0f - epsilon));
251 LogMessage(Integration::Log::DebugInfo, "%s min: %04d, max: %04d, average: %04d\n",mName.c_str(),mMin,mMax,mAvg);
257 unsigned int mCurrent;
263 * used to measure things like the number of texture bytes uploaded
265 class DataCountMetric : public IncCounterMetric
269 DataCountMetric():mTotal(0) {}
285 unsigned int shift = 0;
286 std::string label("bytes");
299 LogMessage(Integration::Log::DebugInfo, "%s max: %01d %s, total: %01d MegaBytes since start-up \n",
309 * small structure used in MetricTable
315 PerformanceMetric::MetricType type;
319 * table to map a metric id, to a string / metric type
321 const MetricInfo MetricTable[] = {
322 { "NODE_COUNT ", PerformanceMonitor::NODE_COUNT, PerformanceMetric::COUNTER },
323 { "NODES_DRAWN ", PerformanceMonitor::NODES_DRAWN, PerformanceMetric::COUNTER },
324 { "MESSAGE_COUNT ", PerformanceMonitor::MESSAGE_COUNT, PerformanceMetric::COUNTER },
325 { "NODES_ADDED ", PerformanceMonitor::NODES_ADDED, PerformanceMetric::INC_COUNTER },
326 { "NODES_REMOVED ", PerformanceMonitor::NODES_REMOVED, PerformanceMetric::INC_COUNTER },
327 { "ANIMATORS_APPLIED ", PerformanceMonitor::ANIMATORS_APPLIED, PerformanceMetric::INC_COUNTER },
328 { "CONSTRAINTS_APPLIED ", PerformanceMonitor::CONSTRAINTS_APPLIED, PerformanceMetric::INC_COUNTER },
329 { "CONSTRAINTS_SKIPPED ", PerformanceMonitor::CONSTRAINTS_SKIPPED, PerformanceMetric::INC_COUNTER },
330 { "TEXTURE_STATE_CHANGES ", PerformanceMonitor::TEXTURE_STATE_CHANGES, PerformanceMetric::INC_COUNTER },
331 { "SHADER_STATE_CHANGES ", PerformanceMonitor::SHADER_STATE_CHANGES, PerformanceMetric::INC_COUNTER },
332 { "BLEND_MODE_CHANGES ", PerformanceMonitor::BLEND_MODE_CHANGES, PerformanceMetric::INC_COUNTER },
333 { "INDICIES ", PerformanceMonitor::INDICIE_COUNT, PerformanceMetric::INC_COUNTER },
334 { "GL_DRAW_CALLS ", PerformanceMonitor::GL_DRAW_CALLS, PerformanceMetric::INC_COUNTER },
335 { "GL_DRAW_ELEMENTS ", PerformanceMonitor::GL_DRAW_ELEMENTS, PerformanceMetric::INC_COUNTER },
336 { "GL_DRAW_ARRAYS ", PerformanceMonitor::GL_DRAW_ARRAYS, PerformanceMetric::INC_COUNTER },
337 { "TEXTURE_LOADS ", PerformanceMonitor::TEXTURE_LOADS, PerformanceMetric::INC_COUNTER },
338 { "TEXTURE_DATA_UPLOADED ", PerformanceMonitor::TEXTURE_DATA_UPLOADED, PerformanceMetric::DATA_COUNTER },
339 { "VERTEX_BUFFERS_BUILT ", PerformanceMonitor::VERTEX_BUFFERS_BUILT, PerformanceMetric::INC_COUNTER },
340 { "QUATERNION_TO_MATRIX ", PerformanceMonitor::QUATERNION_TO_MATRIX, PerformanceMetric::INC_COUNTER },
341 { "MATRIX_MULTIPLYS ", PerformanceMonitor::MATRIX_MULTIPLYS, PerformanceMetric::INC_COUNTER },
342 { "FLOAT_POINT_MULTIPLY ", PerformanceMonitor::FLOAT_POINT_MULTIPLY, PerformanceMetric::INC_COUNTER },
343 { "UPDATE ", PerformanceMonitor::UPDATE, PerformanceMetric::TIMER },
344 { "RESET_PROPERTIES ", PerformanceMonitor::RESET_PROPERTIES, PerformanceMetric::TIMER },
345 { "PROCESS_MESSAGES ", PerformanceMonitor::PROCESS_MESSAGES, PerformanceMetric::TIMER },
346 { "ANIMATE_NODES ", PerformanceMonitor::ANIMATE_NODES, PerformanceMetric::TIMER },
347 { "APPLY_CONSTRAINTS ", PerformanceMonitor::APPLY_CONSTRAINTS, PerformanceMetric::TIMER },
348 { "UPDATE_AND_SORT_NODES ", PerformanceMonitor::UPDATE_NODES, PerformanceMetric::TIMER },
349 { "PREPARE_RENDERABLES ", PerformanceMonitor::PREPARE_RENDERABLES, PerformanceMetric::TIMER },
350 { "PROCESS_RENDER_TASKS ", PerformanceMonitor::PROCESS_RENDER_TASKS, PerformanceMetric::TIMER },
351 { "DRAW_NODES ", PerformanceMonitor::DRAW_NODES, PerformanceMetric::TIMER },
352 { "FRAME_RATE ", PerformanceMonitor::FRAME_RATE, PerformanceMetric::FPS_TIMER }
357 const unsigned int NUM_METRICS = sizeof(MetricTable)/sizeof(MetricInfo);
358 } // unnamed namespace
360 void PerformanceMonitor::Init( Integration::PlatformAbstraction& platform )
362 if( NULL == mInstance )
364 mInstance = new PerformanceMonitor( platform );
368 PerformanceMonitor::PerformanceMonitor( Integration::PlatformAbstraction& platform )
369 : mPlatform( platform ),
375 PerformanceMonitor* PerformanceMonitor::Get()
377 DALI_ASSERT_ALWAYS( NULL != mInstance );
381 PerformanceMetric *PerformanceMonitor::Add(Metric metricId)
383 PerformanceMetric *metric = NULL;
384 const MetricInfo &info = GetMetricInfo(metricId);
388 case PerformanceMetric::FPS_TIMER : metric = new FPSTimerMetric(); break;
389 case PerformanceMetric::TIMER : metric = new TimerMetric(); break;
390 case PerformanceMetric::COUNTER : metric = new CounterMetric(); break;
391 case PerformanceMetric::INC_COUNTER : metric = new IncCounterMetric(); break;
392 case PerformanceMetric::DATA_COUNTER: metric = new DataCountMetric(); break;
393 default : DALI_ASSERT_ALWAYS( 0 && "PerformanceMetric enumeration out of bounds");
396 metric->mMetricId = metricId;
397 metric->mType = info.type;
398 metric->mName = info.mName;
399 metric->mEnabled = true;
400 mMetrics[metricId] = metric;
405 PerformanceMetric *PerformanceMonitor::GetMetric(Metric metricId)
407 mLookupTypeType::const_iterator item=mMetrics.find(metricId);
408 if (item!=mMetrics.end())
410 return ((*item).second);
412 // metric not found, so add it
413 return Add(metricId);
416 void PerformanceMonitor::Set(Metric metricId, float value)
418 PerformanceMetric *metric = GetMetric(metricId);
420 metric->SetFloat(value);
423 void PerformanceMonitor::Set(Metric metricId, unsigned int value)
425 PerformanceMetric *metric = GetMetric(metricId);
427 metric->SetInt(value);
430 void PerformanceMonitor::Increase(Metric metricId,unsigned int value)
432 PerformanceMetric *metric = GetMetric(metricId);
434 metric->IncreaseBy(value);
437 void PerformanceMonitor::StartTimer(Metric metricId)
439 TimerMetric *timer = static_cast<TimerMetric *>(GetMetric(metricId));
441 TimeInfo& timeInfo = timer->mTime;
442 mPlatform.GetTimeMicroseconds(timeInfo.seconds, timeInfo.microSeconds);
445 void PerformanceMonitor::EndTimer(Metric metricId)
447 TimerMetric *timer = static_cast<TimerMetric *>(GetMetric(metricId));
450 mPlatform.GetTimeMicroseconds(endTime.seconds, endTime.microSeconds);
452 // frame time in seconds
453 float elapsedTime = Diff(timer->mTime, endTime);
455 if (elapsedTime < timer->mMin)
457 timer->mMin = elapsedTime;
459 if (elapsedTime > timer->mMax)
461 timer->mMax = elapsedTime;
464 timer->mTotal += elapsedTime;
466 timer->mCount += 1.0f;
468 timer->mAvg = (elapsedTime * (1.0f - epsilon)) + (timer->mAvg * epsilon);
471 const MetricInfo &PerformanceMonitor::GetMetricInfo(Metric metricId)
473 for (unsigned int i = 0; i < NUM_METRICS; i++)
475 if (MetricTable[i].mId == metricId)
477 return MetricTable[i];
480 DALI_ASSERT_ALWAYS(0 && "metricId not found");
481 return MetricTable[0];
484 void PerformanceMonitor::FrameTick()
486 unsigned int currentTimeSeconds;
487 unsigned int currentTimeMicroSeconds;
488 mLookupTypeType::const_iterator item;
490 mPlatform.GetTimeMicroseconds(currentTimeSeconds, currentTimeMicroSeconds);
492 // incremental counters need to know when a frame has been done
493 // to store min/max/average values
495 for (item = mMetrics.begin(); item!=mMetrics.end(); item++)
497 PerformanceMetric *metric=(*item).second;
501 // only display info every other second
504 // This is the first tick
505 mStartSeconds = currentTimeSeconds;
507 else if ( currentTimeSeconds < (mSeconds + DEBUG_FREQUENCY))
512 mSeconds = currentTimeSeconds;
514 LogMessage(Integration::Log::DebugInfo, "--------------------------- %d\n", mSeconds - mStartSeconds);
515 for (item = mMetrics.begin(); item!=mMetrics.end(); item++)
517 PerformanceMetric *metric=(*item).second;
518 if (metric->mEnabled)
526 } // namespace Internal