Add decoder component timing functionality

Change-Id: I3cf714eb68e4d500c7fde069228dc356cd1a9053
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index ca9f0a4..a4b786e 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -5276,6 +5276,9 @@
                                     const uint8_t *data_end,
                                     const uint8_t **p_data_end, int start_tile,
                                     int end_tile, int initialize_flag) {
+#if CONFIG_COLLECT_COMPONENT_TIMING
+  start_timing(pbi, av1_decode_tg_tiles_and_wrapup_time);
+#endif
   AV1_COMMON *const cm = &pbi->common;
   CommonTileParams *const tiles = &cm->tiles;
   MACROBLOCKD *const xd = &pbi->dcb.xd;
@@ -5404,4 +5407,8 @@
   if (cm->show_frame && !cm->seq_params->order_hint_info.enable_order_hint) {
     ++cm->current_frame.frame_number;
   }
+
+#if CONFIG_COLLECT_COMPONENT_TIMING
+  end_timing(pbi, av1_decode_tg_tiles_and_wrapup_time);
+#endif
 }
diff --git a/av1/decoder/decoder.h b/av1/decoder/decoder.h
index d6610cd..b95d00e 100644
--- a/av1/decoder/decoder.h
+++ b/av1/decoder/decoder.h
@@ -229,6 +229,28 @@
   int alloc_tile_cols;
 } AV1DecTileMT;
 
+#if CONFIG_COLLECT_COMPONENT_TIMING
+#include "aom_ports/aom_timer.h"
+// Adjust the following to add new components.
+enum {
+  av1_decode_tg_tiles_and_wrapup_time,
+  aom_decode_frame_from_obus_time,
+  kTimingComponents,
+} UENUM1BYTE(TIMING_COMPONENT);
+
+static inline char const *get_component_name(int index) {
+  switch (index) {
+    case av1_decode_tg_tiles_and_wrapup_time:
+      return "av1_decode_tg_tiles_and_wrapup_time";
+    case aom_decode_frame_from_obus_time:
+      return "aom_decode_frame_from_obus_time";
+
+    default: assert(0);
+  }
+  return "error";
+}
+#endif
+
 typedef struct AV1Decoder {
   DecoderCodingBlock dcb;
 
@@ -369,6 +391,18 @@
    * Number of spatial layers: may be > 1 for SVC (scalable vector coding).
    */
   unsigned int number_spatial_layers;
+
+#if CONFIG_COLLECT_COMPONENT_TIMING
+  /*!
+   * component_time[] are initialized to zero while decoder starts.
+   */
+  uint64_t component_time[kTimingComponents];
+  struct aom_usec_timer component_timer[kTimingComponents];
+  /*!
+   * frame_component_time[] are initialized to zero at beginning of each frame.
+   */
+  uint64_t frame_component_time[kTimingComponents];
+#endif
 } AV1Decoder;
 
 // Returns 0 on success. Sets pbi->common.error.error_code to a nonzero error
@@ -445,6 +479,28 @@
 
 /*!\endcond */
 
+#if CONFIG_COLLECT_COMPONENT_TIMING
+static inline void start_timing(AV1Decoder *pbi, int component) {
+  aom_usec_timer_start(&pbi->component_timer[component]);
+}
+static inline void end_timing(AV1Decoder *pbi, int component) {
+  aom_usec_timer_mark(&pbi->component_timer[component]);
+  pbi->frame_component_time[component] +=
+      aom_usec_timer_elapsed(&pbi->component_timer[component]);
+}
+
+static inline char const *get_frame_type_enum(int type) {
+  switch (type) {
+    case 0: return "KEY_FRAME";
+    case 1: return "INTER_FRAME";
+    case 2: return "INTRA_ONLY_FRAME";
+    case 3: return "S_FRAME";
+    default: assert(0);
+  }
+  return "error";
+}
+#endif
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/av1/decoder/obu.c b/av1/decoder/obu.c
index 7e89332..c58f6b2 100644
--- a/av1/decoder/obu.c
+++ b/av1/decoder/obu.c
@@ -869,6 +869,9 @@
 int aom_decode_frame_from_obus(struct AV1Decoder *pbi, const uint8_t *data,
                                const uint8_t *data_end,
                                const uint8_t **p_data_end) {
+#if CONFIG_COLLECT_COMPONENT_TIMING
+  start_timing(pbi, aom_decode_frame_from_obus_time);
+#endif
   AV1_COMMON *const cm = &pbi->common;
   int frame_decoding_finished = 0;
   int is_first_tg_obu_received = 1;
@@ -1121,5 +1124,29 @@
   }
 
   if (pbi->error.error_code != AOM_CODEC_OK) return -1;
+
+#if CONFIG_COLLECT_COMPONENT_TIMING
+  end_timing(pbi, aom_decode_frame_from_obus_time);
+
+  // Print out timing information.
+  int i;
+  fprintf(stderr,
+          "\n Frame number: %d, Frame type: %s, Show Frame: %d, Show existing "
+          "frame: %d\n",
+          cm->current_frame.frame_number,
+          get_frame_type_enum(cm->current_frame.frame_type), cm->show_frame,
+          cm->show_existing_frame);
+  // Exclude show_existing_frame since it doesn't take much time.
+  if (!cm->show_existing_frame) {
+    for (i = 0; i < kTimingComponents; i++) {
+      pbi->component_time[i] += pbi->frame_component_time[i];
+      fprintf(stderr, " %s:  %" PRId64 " us (total: %" PRId64 " us)\n",
+              get_component_name(i), pbi->frame_component_time[i],
+              pbi->component_time[i]);
+      pbi->frame_component_time[i] = 0;
+    }
+  }
+#endif
+
   return frame_decoding_finished;
 }