Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gpuperformance.cc
Go to the documentation of this file.
1 
19 
20 #if !ION_PRODUCTION
21 
22 #include <algorithm>
23 #include <iomanip>
24 #include <limits>
25 
26 #include "ion/gfx/attribute.h"
27 #include "ion/gfx/bufferobject.h"
28 #include "ion/gfx/indexbuffer.h"
29 #include "ion/gfx/shape.h"
30 #include "ion/gfx/statetable.h"
32 #include "ion/math/range.h"
33 #include "ion/math/vector.h"
34 #include "ion/port/timer.h"
35 
36 namespace ion {
37 using analytics::Benchmark;
38 using base::AllocatorPtr;
39 using gfx::Attribute;
40 using gfx::BufferObjectElement;
41 using gfx::ImagePtr;
43 using gfx::IndexBuffer;
44 using gfx::NodePtr;
45 using gfx::Node;
47 using gfx::Renderer;
48 using gfx::RendererPtr;
49 using gfx::ShapePtr;
50 using gfx::Shape;
51 using gfx::StateTablePtr;
52 using gfx::StateTable;
53 using math::Range1i;
54 using math::Range2i;
55 using math::Point2i;
56 using math::Vector4f;
57 
58 namespace analytics {
59 
60 namespace {
61 
62 static const int kDefaultTrialCount = 5;
63 
66 static const int kInnerTrialCount = 20;
67 
68 static const double kMinValue = 1e-20;
69 static const double kMaxValue = 1e20;
70 
71 static const double kToPercent = 1e2;
72 static const double kToKilo = 1e-3;
73 static const double kToMega = 1e-6;
74 static const double kToMilli = 1e3;
75 
76 static const char *kUseProgramString = "UseProgram";
77 static const char *kBindTextureString = "BindTexture";
78 static const char *kUniformString = "Uniform";
79 
81 typedef GpuPerformanceTester::Measurement Measurement;
82 
83 
84 static const char kSceneConstantsGroup[] = "Scene constants";
85 
86 static const Benchmark::Descriptor kNodeCountDescriptor(
87  "Node Count", kSceneConstantsGroup, "Nodes in Ion scene graph", "nodes");
88 
89 static const Benchmark::Descriptor kShapeCountDescriptor(
90  "Shape Count", kSceneConstantsGroup,
91  "Shapes in Ion scene graph", "shapes");
92 
93 static const Benchmark::Descriptor kDrawCountDescriptor(
94  "Draw Count", kSceneConstantsGroup,
95  "Draw calls in Ion scene graph", "draw calls");
96 
97 static const Benchmark::Descriptor kVertexCountDescriptor(
98  "Vertex Count", kSceneConstantsGroup,
99  "Vertices in scene", "vertices");
100 
101 static const Benchmark::Descriptor kPrimitiveCountDescriptor(
102  "Primitive Count", kSceneConstantsGroup,
103  "Renderable elements in scene: Triangles; points; etc.", "primitives");
104 
105 static const Benchmark::Descriptor kTriangleCountDescriptor(
106  "Triangle Count", kSceneConstantsGroup,
107  "Renderable triangles in scene", "triangles");
108 
109 static const Benchmark::Descriptor kLineCountDescriptor(
110  "Line Count", kSceneConstantsGroup,
111  "Renderable lines in scene", "lines");
112 
113 static const Benchmark::Descriptor kPointCountDescriptor(
114  "Point Count", kSceneConstantsGroup,
115  "Renderable points in scene", "points");
116 
117 static const Benchmark::Descriptor kTrianglePercentDescriptor(
118  "Triangle Percent", kSceneConstantsGroup,
119  "Percent of primitives that are triangles", "%");
120 
121 static const Benchmark::Descriptor kLinePercentDescriptor(
122  "Line Percent", kSceneConstantsGroup,
123  "Percent of primitives that are lines", "%");
124 
125 static const Benchmark::Descriptor kPointPercentDescriptor(
126  "Point Percent", kSceneConstantsGroup,
127  "Percent of primitives that are points", "%");
128 
129 static const Benchmark::Descriptor kVerticesPerShapeDescriptor(
130  "Vertices Per Shape", kSceneConstantsGroup,
131  "Average number of vertices per shape (draw call)", "vertices/shape");
132 
133 static const Benchmark::Descriptor kPrimitivesPerShapeDescriptor(
134  "Primitives Per Shape", kSceneConstantsGroup,
135  "Average number of primitives per shape (draw call)", "primitives/shape");
136 
137 static const Benchmark::Descriptor kTrialCountDescriptor(
138  "Trial Count", kSceneConstantsGroup,
139  "Number of trials used to compute averages.", "frames");
140 
141 static const Benchmark::Descriptor kBindShaderCountDescriptor(
142  "Bind Shader Count", kSceneConstantsGroup,
143  "Number of bind shader calls.", "binds");
144 
145 static const Benchmark::Descriptor kBindTextureCountDescriptor(
146  "Bind Texture Count", kSceneConstantsGroup,
147  "Number of bind shader calls.", "binds");
148 
149 static const Benchmark::Descriptor kSetUniformCountDescriptor(
150  "Set Uniform Count", kSceneConstantsGroup,
151  "Number of uniform value set calls.", "set uniforms");
152 
153 static const Benchmark::Descriptor kBufferMemoryDescriptor(
154  "Buffer Memory", kSceneConstantsGroup,
155  "GPU Buffer memory used during the frame", "MB");
156 
157 static const Benchmark::Descriptor kFboMemoryDescriptor(
158  "FBO Memory", kSceneConstantsGroup,
159  "GPU Framebuffer Object memory used during the frame", "MB");
160 
161 static const Benchmark::Descriptor kTextureMemoryDescriptor(
162  "Texture Memory", kSceneConstantsGroup,
163  "GPU texture memory used during the frame", "MB");
164 
165 static const Benchmark::Descriptor kFramebufferMemoryDescriptor(
166  "Framebuffer Memory", kSceneConstantsGroup, "GPU Framebuffer memory", "MB");
167 
168 static const Benchmark::Descriptor kTotalGpuMemoryDescriptor(
169  "Total GPU Memory", kSceneConstantsGroup,
170  "Total GPU memory used during the frame (excluding frame buffer)", "MB");
171 
172 static const char kSceneRatesGroup[] = "Scene Rates";
173 
174 static const Benchmark::Descriptor kFramesPerSecondDescriptor(
175  "Frames Per Second", kSceneRatesGroup, "Frames per second.",
176  "frames/s");
177 
178 static const Benchmark::Descriptor kNodesPerSecondDescriptor(
179  "Nodes Per Second", kSceneRatesGroup,
180  "Nodes per second.", "Knodes/s");
181 
182 static const Benchmark::Descriptor kShapesPerSecondDescriptor(
183  "Shapes Per Second", kSceneRatesGroup,
184  "Shapes per second.", "Kshapes/s");
185 
186 static const Benchmark::Descriptor kDrawCallsPerSecondDescriptor(
187  "Draw Calls Per Second", kSceneRatesGroup,
188  "Draw calls per second.", "Kdraws/s");
189 
190 static const Benchmark::Descriptor kVerticesPerSecondDescriptor(
191  "Vertices Per Second", kSceneRatesGroup,
192  "Millions of vertices per second.", "Mvertices/s");
193 
194 static const Benchmark::Descriptor kPrimitivesPerSecondDescriptor(
195  "Primitives Per Second", kSceneRatesGroup,
196  "Millions of primitives per second.", "Mprimitives/s");
197 
198 static const Benchmark::Descriptor kPixelsPerSecondDescriptor(
199  "Pixels Per Second", kSceneRatesGroup,
200  "Millions of pixels per second.", "Mpixels/s");
201 
202 static const char kTimingsGroup[] = "Timings";
203 
204 static const Benchmark::Descriptor kRenderTimeDescriptor(
205  "Render Time", kTimingsGroup,
206  "Time to render unmodified scene.", "ms/frame");
207 
208 static const Benchmark::Descriptor kResourceCreationDescriptor(
209  "Resource Creation", kTimingsGroup,
210  "Time creating GL resources; CPU-GPU Bandwidth.", "ms/frame");
211 
212 static const Benchmark::Descriptor kNoDrawCallsDescriptor(
213  "No Draw Calls", kTimingsGroup,
214  "Ion & OpenGL state change time; draw calls ignored.", "ms/frame");
215 
216 static const Benchmark::Descriptor kMinViewportDescriptor(
217  "Min Viewport", kTimingsGroup,
218  "Render time with no fill; vertex transform only.", "ms/frame");
219 
220 static const char kRatesBreakdownGroup[] = "Rates Breakdown";
221 
222 static const Benchmark::Descriptor kTransformRateDescriptor(
223  "Transform Rate", kRatesBreakdownGroup,
224  "Approximate Vertex Program performance.", "Mtriangles/s");
225 
226 static const Benchmark::Descriptor kFillRateDescriptor(
227  "Fill Rate", kRatesBreakdownGroup,
228  "Approximate Fragment Program performance.", "Mpixels/s");
229 
230 const char kPercentBreakdownGroup[] = "Percent Breakdown";
231 
232 static const Benchmark::Descriptor kTraversalPercentDescriptor(
233  "Traversal Percent", kPercentBreakdownGroup,
234  "Approximate Ion and OpenGL API overhead.", "%");
235 
236 static const Benchmark::Descriptor kTransformPercentDescriptor(
237  "Transform Percent", kPercentBreakdownGroup,
238  "Approximate Vertex Program utilization.", "%");
239 
240 static const Benchmark::Descriptor kFillPercentDescriptor(
241  "Fill Percent", kPercentBreakdownGroup,
242  "Approximate Fragment Program utilization.", "%");
243 
245 template <typename FUNCTOR>
246 void ApplyToTree(const NodePtr& node, FUNCTOR& f) { // NOLINT
247  if (node.Get()) {
248  f(node);
249  const size_t size = node->GetChildren().size();
250  for (size_t i = 0; i < size; ++i) {
251  ApplyToTree(node->GetChildren()[i], f);
252  }
253  }
254 }
255 
258 struct MinifyViewport {
259  void operator()(const NodePtr& node) {
260  DCHECK(node.Get());
261  if (StateTable* state_table = node->GetStateTable().Get()) {
262  static const Range2i kZeroRange(Point2i(0, 0), Point2i(0, 0));
263  static const Range2i kPixelRange(Point2i(0, 0), Point2i(1, 0));
264  if (!state_table->GetViewport().IsEmpty()) {
265  state_table->SetViewport(kPixelRange);
266  }
267  }
268  }
269 };
270 
272 struct DisableDepthTest {
273  void operator()(const NodePtr& node) {
274  DCHECK(node.Get());
275  if (StateTable* state_table = node->GetStateTable().Get()) {
276  state_table->ResetCapability(StateTable::kDepthTest);
277  }
278  }
279 };
280 
282 struct RemoveGeometry {
283  void operator()(const NodePtr& node) {
284  DCHECK(node.Get());
285  node->ClearShapes();
286  }
287 };
288 
290 struct CountPrimitives {
291  CountPrimitives() :
292  node_count(0),
293  shape_count(0),
294  draw_count(0),
295  triangle_count(0),
296  line_count(0),
297  point_count(0),
298  vertex_count(0) {}
299  void operator()(const NodePtr& node) {
300  DCHECK(node.Get());
301  ++node_count;
303  const size_t size = node->GetShapes().size();
304  shape_count += size;
305  for (size_t i = 0; i < size; ++i) {
306  const ShapePtr& shape = node->GetShapes()[i];
307  size_t count = 0;
309  if (const size_t range_count = shape->GetVertexRangeCount()) {
310  for (size_t r = 0; r < range_count; ++r) {
311  if (shape->IsVertexRangeEnabled(r)) {
312  count += shape->GetVertexRange(r).GetSize();
313  draw_count += 1;
314  }
315  }
316  } else {
318  if (IndexBuffer* index_buffer = shape->GetIndexBuffer().Get()) {
320  count += index_buffer->GetCount();
321  } else {
323  if (shape->GetAttributeArray().Get() &&
324  shape->GetAttributeArray()->GetBufferAttributeCount()) {
325  const Attribute& attrib =
326  shape->GetAttributeArray()->GetBufferAttribute(0);
327  const BufferObjectElement& buffer_element =
328  attrib.GetValue<BufferObjectElement>();
329  count = buffer_element.buffer_object->GetCount();
330  }
331  }
332  draw_count += 1;
333  }
334  vertex_count += count;
336  switch (shape->GetPrimitiveType()) {
337  case Shape::kLines:
338  count /= 2;
339  line_count += count;
340  break;
341  case Shape::kLineLoop:
342  line_count += count;
343  break;
344  case Shape::kLineStrip:
345  count -= 1;
346  line_count += count;
347  break;
348  case Shape::kPoints:
349  point_count += count;
350  break;
351  case Shape::kTriangles:
352  count /= 3;
353  triangle_count += count;
354  break;
355  case Shape::kTriangleFan:
356  case Shape::kTriangleStrip:
357  count -= 2;
358  triangle_count += count;
359  break;
360  }
361  } // for each shape
362  }
363  size_t node_count;
364  size_t shape_count;
365  size_t draw_count;
367  size_t line_count;
368  size_t point_count;
369  size_t vertex_count;
370 };
371 
372 static NodePtr GetClearNode(uint32 width, uint32 height,
373  const AllocatorPtr& allocator) {
374  NodePtr clear_node(new(allocator) Node);
375  StateTablePtr clear_state_table(new(allocator) StateTable(width, height));
376  clear_state_table->SetViewport(Range2i(Point2i(0, 0),
377  Point2i(width, height)));
378  clear_state_table->SetClearColor(Vector4f(1.f, 0.f, 0.f, 1.0f));
379  clear_state_table->SetClearDepthValue(1.f);
380  clear_node->SetStateTable(clear_state_table);
381  return clear_node;
382 }
383 
384 static void ResetVariable(Benchmark::AccumulatedVariable* variable) {
385  DCHECK(variable);
386  variable->samples = 0;
387  variable->minimum = kMaxValue;
388  variable->maximum = kMinValue;
389  variable->mean = 0;
390  variable->standard_deviation = 0;
391 }
392 
393 static void ClearVariable(Benchmark::AccumulatedVariable* variable) {
394  DCHECK(variable);
395  variable->samples = 0;
396  variable->minimum = 0;
397  variable->maximum = 0;
398  variable->mean = 0;
399  variable->standard_deviation = 0;
400 }
401 
402 static void AccumulateVariable(Benchmark::AccumulatedVariable* variable,
403  const GpuPerformanceTester::Measurement& m) {
404  DCHECK(variable);
408  variable->mean += m.mean;
410  variable->standard_deviation += m.deviation;
411  DCHECK_NE(m.maximum, kMinValue);
412  DCHECK_NE(m.minimum, kMaxValue);
413  if (variable->maximum != kMinValue) {
414  variable->maximum += m.maximum;
415  } else {
416  variable->maximum = m.maximum;
417  }
418  if (variable->minimum != kMaxValue) {
419  variable->minimum += m.minimum;
420  } else {
421  variable->minimum = m.minimum;
422  }
423 }
424 
425 static void AccumulateInverseVariable(
426  Benchmark::AccumulatedVariable* inverse_variable,
427  const GpuPerformanceTester::Measurement& m) {
428  DCHECK(inverse_variable);
429  if (inverse_variable->mean != 0.0) {
430  inverse_variable->mean = 1.0 / (1.0 / inverse_variable->mean +
431  1.0 / m.inverse_mean);
432  } else {
433  inverse_variable->mean = m.inverse_mean;
434  }
435  if (inverse_variable->standard_deviation != 0.0) {
436  inverse_variable->standard_deviation =
437  1.0 / (1.0 / inverse_variable->standard_deviation +
438  1.0 / m.inverse_deviation);
439  } else {
440  inverse_variable->standard_deviation = m.inverse_deviation;
441  }
442  DCHECK_NE(m.maximum, kMinValue);
443  DCHECK_NE(m.minimum, kMaxValue);
444  if (inverse_variable->maximum != kMinValue) {
445  inverse_variable->maximum = 1.0 / (1.0 / inverse_variable->maximum +
446  m.minimum);
447  } else {
448  inverse_variable->maximum = 1.0 / m.minimum;
449  }
450  if (inverse_variable->minimum != kMaxValue) {
451  inverse_variable->minimum = 1.0 / (1.0 / inverse_variable->minimum +
452  m.maximum);
453  } else {
454  inverse_variable->minimum = 1.0 / m.maximum;
455  }
456 }
457 
458 } // namespace
459 
463  DCHECK(scene.Get());
464  NodePtr instance(new(scene->GetAllocator()) Node);
466  if (StateTable* scene_state_table = scene->GetStateTable().Get()) {
467  StateTablePtr state_table(
468  new(scene_state_table->GetAllocator()) StateTable);
469  state_table->CopyFrom(*scene_state_table);
470  instance->SetStateTable(state_table);
471  }
473  instance->SetShaderProgram(scene->GetShaderProgram());
475  const size_t uniform_size = scene->GetUniforms().size();
476  for (size_t i = 0; i < uniform_size; ++i) {
477  instance->AddUniform(scene->GetUniforms()[i]);
478  }
480  const size_t uniform_blocks_size = scene->GetUniformBlocks().size();
481  for (size_t i = 0; i < uniform_blocks_size; ++i) {
482  instance->AddUniformBlock(scene->GetUniformBlocks()[i]);
483  }
485  const size_t shape_size = scene->GetShapes().size();
486  for (size_t i = 0; i < shape_size; ++i) {
487  instance->AddShape(scene->GetShapes()[i]);
488  }
490  const size_t children_size = scene->GetChildren().size();
491  for (size_t i = 0; i < children_size; ++i) {
492  instance->AddChild(InstanceCopy(scene->GetChildren()[i]));
493  }
495  instance->Enable(scene->IsEnabled());
496  return instance;
497 }
498 
500  : number_of_trials_(kDefaultTrialCount),
501  width_(width),
502  height_(height),
503  enables_(kConstants | kBaseline | kNoDraw |
504  kMinimumViewport | kGpuMemory | kGlTrace),
505  num_nodes_(0),
506  num_shapes_(0),
507  num_draws_(0),
508  num_vertices_(0),
509  num_triangles_(0),
510  num_lines_(0),
511  num_points_(0),
512  num_bind_shader_(0),
513  num_bind_texture_(0),
514  num_set_uniform_(0),
515  buffer_memory_(0),
516  fbo_memory_(0),
517  texture_memory_(0),
518  framebuffer_memory_(0),
519  baseline_(kRenderTimeDescriptor, 0, kMaxValue, kMinValue, 0.0, 0.0),
520  baseline_inverse_(kRenderTimeDescriptor, 0, kMaxValue, kMinValue,
521  0.0, 0.0),
522  resource_(kResourceCreationDescriptor, 0, kMaxValue, kMinValue, 0.0, 0.0),
523  no_draw_calls_(kNoDrawCallsDescriptor, 0, kMaxValue, kMinValue, 0.0, 0.0),
524  min_viewport_(kMinViewportDescriptor, 0, kMaxValue, kMinValue, 0.0, 0.0),
525  min_viewport_inverse_(kMinViewportDescriptor, 0, kMaxValue, kMinValue,
526  0.0, 0.0) {
527 }
528 
530 
532  const NodePtr& scene,
533  const GraphicsManagerPtr& graphics_manager,
534  const RendererPtr& renderer) {
535 
538  CountPrimitives primitive_count;
539  ApplyToTree(scene, primitive_count);
540  num_nodes_ += static_cast<int>(primitive_count.node_count);
541  num_shapes_ += static_cast<int>(primitive_count.shape_count);
542  num_draws_ += static_cast<int>(primitive_count.draw_count);
543  num_triangles_ += static_cast<int>(primitive_count.triangle_count);
544  num_lines_ += static_cast<int>(primitive_count.line_count);
545  num_points_ += static_cast<int>(primitive_count.point_count);
546  num_vertices_ += static_cast<int>(primitive_count.vertex_count);
547  }
548 
555  const size_t current_buffer_memory =
556  renderer->GetGpuMemoryUsage(Renderer::kBufferObject);
557  buffer_memory_ = std::max(buffer_memory_, current_buffer_memory);
558 
559  const size_t current_fbo_memory =
560  renderer->GetGpuMemoryUsage(Renderer::kFramebufferObject);
561  fbo_memory_ = std::max(fbo_memory_, current_fbo_memory);
562 
563  const size_t current_texture_memory =
564  renderer->GetGpuMemoryUsage(Renderer::kTexture);
565  texture_memory_ = std::max(texture_memory_, current_texture_memory);
566 
568  GLint red_bits, green_bits, blue_bits, alpha_bits, depth_bits, stencil_bits;
569  graphics_manager->GetIntegerv(GL_RED_BITS, &red_bits);
570  graphics_manager->GetIntegerv(GL_GREEN_BITS, &green_bits);
571  graphics_manager->GetIntegerv(GL_BLUE_BITS, &blue_bits);
572  graphics_manager->GetIntegerv(GL_ALPHA_BITS, &alpha_bits);
573  graphics_manager->GetIntegerv(GL_DEPTH_BITS, &depth_bits);
574  graphics_manager->GetIntegerv(GL_STENCIL_BITS, &stencil_bits);
576  static const int kBufferCount = 2;
577  const int bits = depth_bits + stencil_bits +
578  (red_bits + green_bits + blue_bits + alpha_bits) * kBufferCount;
579  const size_t current_framebuffer_memory = bits/8 * width_ * height_;
581  current_framebuffer_memory);
582  }
583 
585  if (AreModesEnabled(kGlTrace)) {
589 
591  std::ostream* prev_stream = graphics_manager->GetTracingStream();
592  std::ostringstream trace_stream;
593  graphics_manager->SetTracingStream(&trace_stream);
594  renderer->gfx::Renderer::DrawScene(scene);
595  graphics_manager->SetTracingStream(prev_stream);
596 
598  gfx::TraceCallExtractor extractor(trace_stream.str());
599  num_bind_shader_ += extractor.GetCountOf(kUseProgramString);
600  num_bind_texture_ += extractor.GetCountOf(kBindTextureString);
601  num_set_uniform_ += extractor.GetCountOf(kUniformString);
602  }
603 
608  if (AreModesEnabled(kBaseline)) {
609  MeasureBaseline(scene, graphics_manager, renderer);
610  } else {
611  ClearVariable(&baseline_);
612  ClearVariable(&baseline_inverse_);
613  }
615  if (AreModesEnabled(kNoDraw)) {
616  MeasureStateChanges(scene, graphics_manager, renderer);
617  } else {
618  ClearVariable(&no_draw_calls_);
619  }
622  MeasureMinViewportSpeed(scene, graphics_manager, renderer);
623  } else {
624  ClearVariable(&min_viewport_);
625  ClearVariable(&min_viewport_inverse_);
626  }
628  if (AreModesEnabled(kResource)) {
629  MeasureResourceCreation(scene, graphics_manager);
633  renderer->ClearCachedBindings();
634  } else {
635  ClearVariable(&resource_);
636  }
637 }
638 
640  Benchmark benchmark;
641 
642  int num_primitives = 0;
643  double percent_triangles = 0;
644  double percent_lines = 0;
645  double percent_points = 0;
646  double vertices_per_shape = 0;
647  double primitives_per_shape = 0;
648 
655 
659  num_primitives = num_triangles_ + num_lines_ + num_points_;
660  if (num_primitives > 0) {
661  percent_triangles =
662  static_cast<double>(num_triangles_) /
663  static_cast<double>(num_primitives) * kToPercent;
664  percent_lines =
665  static_cast<double>(num_lines_) /
666  static_cast<double>(num_primitives) * kToPercent;
667  percent_points =
668  static_cast<double>(num_points_) /
669  static_cast<double>(num_primitives) * kToPercent;
670  }
671  if (num_shapes_ > 0) {
672  vertices_per_shape = static_cast<double>(num_vertices_) /
673  static_cast<double>(num_shapes_);
674  primitives_per_shape = static_cast<double>(num_primitives) /
675  static_cast<double>(num_shapes_);
676  }
677  }
678 
679  benchmark.AddConstant(Benchmark::Constant(kNodeCountDescriptor,
680  num_nodes_));
681  benchmark.AddConstant(Benchmark::Constant(kShapeCountDescriptor,
682  num_shapes_));
683  benchmark.AddConstant(Benchmark::Constant(kDrawCountDescriptor,
684  num_draws_));
685  benchmark.AddConstant(Benchmark::Constant(kVertexCountDescriptor,
686  num_vertices_));
687  benchmark.AddConstant(Benchmark::Constant(kPrimitiveCountDescriptor,
688  num_primitives));
689  benchmark.AddConstant(Benchmark::Constant(kTriangleCountDescriptor,
690  num_triangles_));
691  benchmark.AddConstant(Benchmark::Constant(kLineCountDescriptor,
692  num_lines_));
693  benchmark.AddConstant(Benchmark::Constant(kPointCountDescriptor,
694  num_points_));
695  benchmark.AddConstant(Benchmark::Constant(kTrianglePercentDescriptor,
696  percent_triangles));
697  benchmark.AddConstant(Benchmark::Constant(kLinePercentDescriptor,
698  percent_lines));
699  benchmark.AddConstant(Benchmark::Constant(kPointPercentDescriptor,
700  percent_points));
701  benchmark.AddConstant(Benchmark::Constant(kVerticesPerShapeDescriptor,
702  vertices_per_shape));
703  benchmark.AddConstant(Benchmark::Constant(kPrimitivesPerShapeDescriptor,
704  primitives_per_shape));
705 
707  const int trial_count = GetTrialCount();
708  benchmark.AddConstant(Benchmark::Constant(kTrialCountDescriptor,
709  trial_count));
710 
713  kBindShaderCountDescriptor, static_cast<double>(num_bind_shader_)));
715  kBindTextureCountDescriptor, static_cast<double>(num_bind_texture_)));
717  kSetUniformCountDescriptor, static_cast<double>(num_set_uniform_)));
718 
720  const double kBytesToMegabytes = 1.0 / (1024 * 1024);
721  const size_t total_gpu_memory =
724  kBufferMemoryDescriptor,
725  static_cast<double>(buffer_memory_) * kBytesToMegabytes));
727  kFboMemoryDescriptor,
728  static_cast<double>(fbo_memory_) * kBytesToMegabytes));
730  kTextureMemoryDescriptor,
731  static_cast<double>(texture_memory_) * kBytesToMegabytes));
733  kFramebufferMemoryDescriptor,
734  static_cast<double>(framebuffer_memory_) * kBytesToMegabytes));
736  kTotalGpuMemoryDescriptor,
737  static_cast<double>(total_gpu_memory) * kBytesToMegabytes));
738 
740  const double fps_baseline = baseline_inverse_.mean;
741  const double fps_deviation = baseline_inverse_.standard_deviation;
742  const double fps_min = baseline_inverse_.minimum;
743  const double fps_max = baseline_inverse_.maximum;
744  benchmark.AddAccumulatedVariable(
745  Benchmark::AccumulatedVariable(kFramesPerSecondDescriptor,
746  trial_count,
747  fps_min,
748  fps_max,
749  fps_baseline,
750  fps_deviation));
751 
752  double baseline, deviation, min, max;
753 
755  baseline = fps_baseline * num_nodes_;
756  deviation = fps_deviation * num_nodes_;
757  min = fps_min * num_nodes_;
758  max = fps_max * num_nodes_;
759  benchmark.AddAccumulatedVariable(
760  Benchmark::AccumulatedVariable(kNodesPerSecondDescriptor,
761  trial_count,
762  min * kToKilo,
763  max * kToKilo,
764  baseline * kToKilo,
765  deviation * kToKilo));
766 
768  baseline = fps_baseline * num_shapes_;
769  deviation = fps_deviation * num_shapes_;
770  min = fps_min * num_shapes_;
771  max = fps_max * num_shapes_;
772  benchmark.AddAccumulatedVariable(
773  Benchmark::AccumulatedVariable(kShapesPerSecondDescriptor,
774  trial_count,
775  min * kToKilo,
776  max * kToKilo,
777  baseline * kToKilo,
778  deviation * kToKilo));
779 
781  baseline = fps_baseline * num_draws_;
782  deviation = fps_deviation * num_draws_;
783  min = fps_min * num_draws_;
784  max = fps_max * num_draws_;
785  benchmark.AddAccumulatedVariable(
786  Benchmark::AccumulatedVariable(kDrawCallsPerSecondDescriptor,
787  trial_count,
788  min * kToKilo,
789  max * kToKilo,
790  baseline * kToKilo,
791  deviation * kToKilo));
792 
794  baseline = fps_baseline * num_vertices_;
795  deviation = fps_deviation * num_vertices_;
796  min = fps_min * num_vertices_;
797  max = fps_max * num_vertices_;
798  benchmark.AddAccumulatedVariable(
799  Benchmark::AccumulatedVariable(kVerticesPerSecondDescriptor,
800  trial_count,
801  min * kToMega,
802  max * kToMega,
803  baseline * kToMega,
804  deviation * kToMega));
805 
807  baseline = fps_baseline * num_primitives;
808  deviation = fps_deviation * num_primitives;
809  min = fps_min * num_primitives;
810  max = fps_max * num_primitives;
811  benchmark.AddAccumulatedVariable(
812  Benchmark::AccumulatedVariable(kPrimitivesPerSecondDescriptor,
813  trial_count,
814  min * kToMega,
815  max * kToMega,
816  baseline * kToMega,
817  deviation * kToMega));
818 
820  const int num_pixels = width_ * height_;
821  baseline = fps_baseline * num_pixels;
822  deviation = fps_deviation * num_pixels;
823  min = fps_min * num_pixels;
824  max = fps_max * num_pixels;
825  benchmark.AddAccumulatedVariable(
826  Benchmark::AccumulatedVariable(kPixelsPerSecondDescriptor,
827  trial_count,
828  min * kToMega,
829  max * kToMega,
830  baseline * kToMega,
831  deviation * kToMega));
832 
834  benchmark.AddAccumulatedVariable(
835  Benchmark::AccumulatedVariable(kRenderTimeDescriptor,
836  trial_count,
837  baseline_.minimum * kToMilli,
838  baseline_.maximum * kToMilli,
839  baseline_.mean * kToMilli,
841  kToMilli));
842 
845  benchmark.AddAccumulatedVariable(
846  Benchmark::AccumulatedVariable(kResourceCreationDescriptor,
847  trial_count,
848  resource_.minimum * kToMilli,
849  resource_.maximum * kToMilli,
850  resource_.mean * kToMilli,
852  kToMilli));
853 
855  benchmark.AddAccumulatedVariable(
856  Benchmark::AccumulatedVariable(kNoDrawCallsDescriptor,
857  trial_count,
858  no_draw_calls_.minimum * kToMilli,
859  no_draw_calls_.maximum * kToMilli,
860  no_draw_calls_.mean * kToMilli,
862  kToMilli));
863 
865  benchmark.AddAccumulatedVariable(
866  Benchmark::AccumulatedVariable(kMinViewportDescriptor,
867  trial_count,
868  min_viewport_.minimum * kToMilli,
869  min_viewport_.maximum * kToMilli,
870  min_viewport_.mean * kToMilli,
872  kToMilli));
873 
877  const double transform_time = min_viewport_.mean;
878  const double transform_deviation = min_viewport_.standard_deviation;
879  const double transform_min = min_viewport_.minimum;
880  const double transform_max = min_viewport_.maximum;
881  const double inv_transform_time = min_viewport_inverse_.mean;
882  const double inv_transform_min = min_viewport_inverse_.minimum;
883  const double inv_transform_max = min_viewport_inverse_.maximum;
884  const double inv_transform_deviation =
886  const double num_mega_primitives = num_primitives * GetTrialCount() * kToMega;
887  const double transform_tps = num_mega_primitives * inv_transform_time;
888  const double transform_tps_deviation =
889  num_mega_primitives * inv_transform_deviation;
890  const double transform_tps_min = inv_transform_min * num_mega_primitives;
891  const double transform_tps_max = inv_transform_max * num_mega_primitives;
892  benchmark.AddAccumulatedVariable(
893  Benchmark::AccumulatedVariable(kTransformRateDescriptor,
894  trial_count,
895  transform_tps_min,
896  transform_tps_max,
897  transform_tps,
898  transform_tps_deviation));
899 
902  const double fill_time =
903  std::max(kMinValue, baseline_.mean - min_viewport_.mean);
904  const double fill_deviation =
906  const double fill_min =
907  std::max(kMinValue, baseline_.minimum - transform_max);
908  const double fill_max =
909  std::max(kMinValue, baseline_.maximum - transform_min);
910  const double inv_fill_time =
911  std::max(kMinValue, 1.0/ (baseline_.mean - min_viewport_.mean));
912  const double inv_fill_deviation = baseline_inverse_.standard_deviation +
914  const double pixel_count = GetTrialCount() * width_ * height_;
915  const double fill_pps = pixel_count * inv_fill_time;
916  const double fill_pps_deviation = pixel_count * inv_fill_deviation;
917  const double fill_pps_min =
918  fill_max == kMinValue ? kMaxValue : pixel_count / fill_max;
919  const double fill_pps_max =
920  fill_min == kMinValue ? kMaxValue : pixel_count / fill_min;
921  benchmark.AddAccumulatedVariable(
922  Benchmark::AccumulatedVariable(kFillRateDescriptor,
923  trial_count,
924  fill_pps_min * kToMega,
925  fill_pps_max * kToMega,
926  fill_pps * kToMega,
927  fill_pps_deviation * kToMega));
928 
930  const double inv_total_time =
931  1.0 / (no_draw_calls_.mean + transform_time + fill_time);
932  const double inv_time_min_traversal =
933  1.0 / (no_draw_calls_.minimum + transform_max + fill_max);
934  const double inv_time_max_traversal =
935  1.0 / (no_draw_calls_.maximum + transform_min + fill_min);
936  const double traversal_frac = no_draw_calls_.mean * inv_total_time;
937  const double traversal_min_frac =
938  no_draw_calls_.minimum * inv_time_min_traversal;
939  const double traversal_max_frac =
940  no_draw_calls_.maximum * inv_time_max_traversal;
941  const double traversal_frac_deviation =
942  no_draw_calls_.standard_deviation * inv_total_time;
943  benchmark.AddAccumulatedVariable(
944  Benchmark::AccumulatedVariable(kTraversalPercentDescriptor,
945  trial_count,
946  traversal_min_frac * kToPercent,
947  traversal_max_frac * kToPercent,
948  traversal_frac * kToPercent,
949  traversal_frac_deviation * kToPercent));
950 
951  const double transform_frac = transform_time * inv_total_time;
952  const double inv_time_min_transform =
953  1.0 / (no_draw_calls_.maximum + transform_min + fill_max);
954  const double inv_time_max_transform =
955  1.0 / (no_draw_calls_.minimum + transform_max + fill_min);
956  const double transform_min_frac = transform_min * inv_time_min_transform;
957  const double transform_max_frac = transform_max * inv_time_max_transform;
958  const double transform_frac_deviation =
959  transform_deviation * inv_total_time;
960  benchmark.AddAccumulatedVariable(
961  Benchmark::AccumulatedVariable(kTransformPercentDescriptor,
962  trial_count,
963  transform_min_frac * kToPercent,
964  transform_max_frac * kToPercent,
965  transform_frac * kToPercent,
966  transform_frac_deviation * kToPercent));
967 
968  const double fill_frac = fill_time * inv_total_time;
969  const double inv_time_min_fill =
970  1.0 / (no_draw_calls_.maximum + transform_max + fill_min);
971  const double inv_time_max_fill =
972  1.0 / (no_draw_calls_.minimum + transform_min + fill_max);
973  const double fill_frac_min = fill_min * inv_time_min_fill;
974  const double fill_frac_max = fill_max * inv_time_max_fill;
975  const double fill_frac_deviation = fill_deviation * inv_total_time;
976  benchmark.AddAccumulatedVariable(
977  Benchmark::AccumulatedVariable(kFillPercentDescriptor,
978  trial_count,
979  fill_frac_min * kToPercent,
980  fill_frac_max * kToPercent,
981  fill_frac * kToPercent,
982  fill_frac_deviation * kToPercent));
983 
985  ResetVariable(&baseline_);
986  ResetVariable(&baseline_inverse_);
987  ResetVariable(&resource_);
988  ResetVariable(&no_draw_calls_);
989  ResetVariable(&min_viewport_);
990  ResetVariable(&min_viewport_inverse_);
991  num_nodes_ = 0;
992  num_shapes_ = 0;
993  num_draws_ = 0;
994  num_vertices_ = 0;
995  num_triangles_ = 0;
996  num_lines_ = 0;
997  num_points_ = 0;
998  num_bind_shader_ = 0;
999  num_bind_texture_ = 0;
1000  num_set_uniform_ = 0;
1001  buffer_memory_ = 0;
1002  fbo_memory_ = 0;
1003  texture_memory_ = 0;
1004  framebuffer_memory_ = 0;
1005  return benchmark;
1006 }
1007 
1009  const NodePtr& scene,
1010  const GraphicsManagerPtr& graphics_manager,
1011  const RendererPtr& renderer) {
1012  AccumulateMeasurements(scene, graphics_manager, renderer);
1013  return GetResults();
1014 }
1015 
1017  const NodePtr& scene,
1018  const GraphicsManagerPtr& graphics_manager,
1019  const RendererPtr& renderer) {
1020  DCHECK(scene.Get());
1021  NodePtr clear_test_node(GetClearNode(width_, height_,
1022  scene->GetAllocator()));
1023  clear_test_node->AddChild(InstanceCopy(scene));
1024  Measurement m = MeasurePerformance(clear_test_node, graphics_manager,
1025  renderer);
1026  AccumulateVariable(&baseline_, m);
1027  AccumulateInverseVariable(&baseline_inverse_, m);
1028  return m;
1029 }
1030 
1032  const NodePtr& scene,
1033  const GraphicsManagerPtr& graphics_manager,
1034  const RendererPtr& renderer) {
1035  DCHECK(scene.Get());
1036  NodePtr test_scene(InstanceCopy(scene));
1037  MinifyViewport minviewport_functor;
1038  ApplyToTree(test_scene, minviewport_functor);
1039  static const Range2i kPixelRange(Point2i(0, 0), Point2i(1, 1));
1040  if (!test_scene->GetStateTable().Get()) {
1041  test_scene->SetStateTable(
1042  StateTablePtr(new(scene->GetAllocator()) StateTable));
1043  }
1044  test_scene->GetStateTable()->SetViewport(kPixelRange);
1045  Measurement m = MeasurePerformance(test_scene, graphics_manager, renderer);
1046  AccumulateVariable(&min_viewport_, m);
1047  AccumulateInverseVariable(&min_viewport_inverse_, m);
1048  return m;
1049 }
1050 
1052  const NodePtr& scene,
1053  const GraphicsManagerPtr& graphics_manager,
1054  const RendererPtr& renderer) {
1055  DCHECK(scene.Get());
1056  NodePtr test_scene(InstanceCopy(scene));
1057  RemoveGeometry remove_geometry_functor;
1058  ApplyToTree(test_scene, remove_geometry_functor);
1059  Measurement m = MeasurePerformance(test_scene, graphics_manager, renderer);
1060  AccumulateVariable(&no_draw_calls_, m);
1061  return m;
1062 }
1063 
1065  const NodePtr& scene,
1066  const GraphicsManagerPtr& graphics_manager,
1067  const RendererPtr& renderer) {
1068  DCHECK(scene.Get());
1069 
1071  DisableDepthTest disable_depth_test_functor;
1072  ApplyToTree(scene, disable_depth_test_functor);
1073 
1074  NodePtr clear_node(GetClearNode(width_, height_, scene->GetAllocator()));
1079  renderer->gfx::Renderer::DrawScene(clear_node);
1080 
1083  renderer->gfx::Renderer::DrawScene(scene);
1084  renderer->gfx::Renderer::DrawScene(clear_node);
1085  graphics_manager->Finish();
1086 
1087  double time_sum = 0.0;
1088  double inv_time_sum = 0.0;
1089  double time_squared = 0.0;
1090  double inv_time_squared = 0.0;
1091  double minimum = std::numeric_limits<double>::max();
1092  double maximum = std::numeric_limits<double>::min();
1093  for (uint32 frame = 0; frame < number_of_trials_; ++frame) {
1094  port::Timer timer;
1095  for (int i = 0; i < kInnerTrialCount; ++i)
1096  renderer->gfx::Renderer::DrawScene(scene);
1097  graphics_manager->Finish();
1098  double frame_time = timer.GetInS() / kInnerTrialCount;
1100  DCHECK_GE(frame_time, 0.0);
1101  frame_time = frame_time > 0.0 ? frame_time : 0.0;
1102  time_sum += frame_time;
1103  time_squared += frame_time * frame_time;
1104  inv_time_sum += 1.0 / frame_time;
1105  inv_time_squared += 1.0 / frame_time * 1.0 / frame_time;
1106  minimum = std::min(frame_time, minimum);
1107  maximum = std::max(frame_time, maximum);
1108  }
1109  const double inv_num_trials = 1.0 / number_of_trials_;
1110  const double ave_time = time_sum * inv_num_trials;
1111  const double ave_time_squared = time_squared * inv_num_trials;
1112  const double ave_inv_time = inv_time_sum * inv_num_trials;
1113  const double ave_inv_time_squared = inv_time_squared * inv_num_trials;
1114  const double stddev_time = kInnerTrialCount *
1115  sqrt(fabs(ave_time_squared - ave_time * ave_time));
1116  const double stddev_inv_time = kInnerTrialCount *
1117  sqrt(fabs(ave_inv_time_squared - ave_inv_time * ave_inv_time));
1118 
1119  return Measurement(
1120  ave_time, stddev_time, ave_inv_time, stddev_inv_time, minimum, maximum);
1121 }
1122 
1124  const gfx::NodePtr& scene,
1125  const GraphicsManagerPtr& graphics_manager) {
1130  NodePtr clear_node(GetClearNode(width_, height_, scene->GetAllocator()));
1131 
1132  RendererPtr resource_renderer_one(new Renderer(graphics_manager));
1133  resource_renderer_one->gfx::Renderer::DrawScene(clear_node);
1134  port::Timer timer;
1135  resource_renderer_one->gfx::Renderer::DrawScene(scene);
1136  graphics_manager->Finish();
1137  const double time_one = timer.GetInS();
1138 
1139  RendererPtr resource_renderer_two(new Renderer(graphics_manager));
1140  resource_renderer_two->gfx::Renderer::DrawScene(clear_node);
1141  timer.Reset();
1142  resource_renderer_two->gfx::Renderer::DrawScene(scene);
1143  graphics_manager->Finish();
1144  const double time_two = timer.GetInS();
1145 
1146  Measurement m((time_one + time_two) / 2.0,
1147  fabs(time_one - time_two) / 2.0,
1148  (1.0 / time_one + 1.0 / time_two) / 2.0,
1149  fabs(1.0 / time_one - 1.0 / time_two) / 2.0,
1150  time_one < time_two ? time_one : time_two,
1151  time_one > time_two ? time_one : time_two);
1152  AccumulateVariable(&resource_, m);
1153  return m;
1154 }
1155 
1156 } // namespace analytics
1157 } // namespace ion
1158 
1159 #endif // !ION_PRODUCTION
base::ReferentPtr< Node >::Type NodePtr
Definition: node.h:33
#define GL_BLUE_BITS
Definition: glheaders.h:159
Benchmark::AccumulatedVariable min_viewport_
Benchmark::AccumulatedVariable baseline_
double GetInS() const
Returns the elapsed time since construction or the last Reset() in seconds.
Definition: timer.cc:87
virtual void AccumulateMeasurements(const gfx::NodePtr &scene, const gfx::GraphicsManagerPtr &graphics_manager, const gfx::RendererPtr &renderer)
Keeps running totals for the full set of basic measurements for all scene nodes passed to it until Ge...
base::ReferentPtr< Image >::Type ImagePtr
Definition: image.h:29
Benchmark::AccumulatedVariable min_viewport_inverse_
#define GL_GREEN_BITS
Definition: glheaders.h:411
virtual Measurement MeasureResourceCreation(const gfx::NodePtr &scene, const gfx::GraphicsManagerPtr &graphics_manager)
Measures render performance WITH resource creation time by creating a new Renderer.
base::ReferentPtr< Shape >::Type ShapePtr
Convenience typedef for shared pointer to a Shape.
Definition: shape.h:167
bool AreModesEnabled(Enables enables) const
Returns true if all of the specified modes are currently enabled.
Range< 1, int32 > Range1i
Definition: range.h:363
#define GL_DEPTH_BITS
Definition: glheaders.h:321
#define DCHECK(expr)
Definition: logging.h:331
size_t triangle_count
static gfx::NodePtr InstanceCopy(const gfx::NodePtr &scene)
Copy scene in preparation for modifying the nodes for various measurements.
void AddAccumulatedVariable(const AccumulatedVariable &variable)
Definition: benchmark.h:143
#define GL_ALPHA_BITS
Definition: glheaders.h:141
size_t node_count
virtual Measurement MeasureMinViewportSpeed(const gfx::NodePtr &scene, const gfx::GraphicsManagerPtr &graphics_manager, const gfx::RendererPtr &renderer)
Returns the avg and stddev time to render scene with a minimal viewport, i.e.
size_t vertex_count
Range< 2, int32 > Range2i
Definition: range.h:371
#define GL_RED_BITS
Definition: glheaders.h:705
base::ReferentPtr< StateTable >::Type StateTablePtr
Convenience typedef for shared pointer to a StateTable.
Definition: statetable.h:705
SharedPtr< Allocator > AllocatorPtr
Definition: allocator.h:51
The TraceCallExtractor class parses an OpenGL trace output generated by a GraphicsManager, segmenting it into a vector of calls with arguments.
virtual const Benchmark GetResults()
Finalizes accumulated measurements, returns benchmark data, and resets accumulation totals...
base::ReferentPtr< IndexBuffer >::Type IndexBufferPtr
Definition: indexbuffer.h:38
#define DCHECK_NE(val1, val2)
Definition: logging.h:333
int num_nodes_
Benchmark data in progress.
void Reset()
Resets the timer.
Definition: timer.cc:83
size_t line_count
int GetTrialCount() const
Returns/sets the number of trials used to measure performance.
size_t point_count
virtual Measurement MeasureBaseline(const gfx::NodePtr &scene, const gfx::GraphicsManagerPtr &graphics_manager, const gfx::RendererPtr &renderer)
Returns the avg and stddev time to render unmodified scene.
#define DCHECK_GE(val1, val2)
Definition: logging.h:336
This struct represents a number that is constant over all samples.
Definition: benchmark.h:54
Benchmark::AccumulatedVariable baseline_inverse_
#define GL_STENCIL_BITS
Definition: glheaders.h:942
int width
void AddConstant(const Constant &constant)
Each of these adds a measurement of a specific type to the benchmark results.
Definition: benchmark.h:139
Benchmark::AccumulatedVariable no_draw_calls_
size_t shape_count
base::ReferentPtr< GraphicsManager >::Type GraphicsManagerPtr
Convenience typedef for shared pointer to a GraphicsManager.
virtual Measurement MeasurePerformance(const gfx::NodePtr &scene, const gfx::GraphicsManagerPtr &graphics_manager, const gfx::RendererPtr &renderer)
Returns the average (avg) time and standard deviation (stddev) for rendering a scene some number of t...
virtual Measurement MeasureStateChanges(const gfx::NodePtr &scene, const gfx::GraphicsManagerPtr &graphics_manager, const gfx::RendererPtr &renderer)
Measures performance of state changes, i.e.
The Benchmark class provides types and utilities to make it easier to create performance benchmarks...
Definition: benchmark.h:34
virtual const Benchmark RunAllMeasurements(const gfx::NodePtr &scene, const gfx::GraphicsManagerPtr &graphics_manager, const gfx::RendererPtr &renderer)
Runs full set of basic measurements, returns Benchmark immediately.
Benchmark::AccumulatedVariable resource_
base::ReferentPtr< Renderer >::Type RendererPtr
Convenience typedef for shared pointer to a Renderer.
Definition: renderer.h:428
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
Definition: sharedptr.h:60
GpuPerformanceTester(uint32 width, uint32 height)
Width and height should be the OpenGL render window dimensions.
size_t draw_count
This struct represents accumulated values for a variable.
Definition: benchmark.h:84