1/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7    http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations under the License.
14==============================================================================*/
15
16// Utility functions for performance profiling.
17
18#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TIME_LOG_H_
19#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TIME_LOG_H_
20
21#include <stdint.h>
22
23#include "tensorflow/examples/android/jni/object_tracking/logging.h"
24#include "tensorflow/examples/android/jni/object_tracking/utils.h"
25
26#ifdef LOG_TIME
27
28// Blend constant for running average.
29#define ALPHA 0.98f
30#define NUM_LOGS 100
31
32struct LogEntry {
33  const char* id;
34  int64_t time_stamp;
35};
36
37struct AverageEntry {
38  const char* id;
39  float average_duration;
40};
41
42// Storage for keeping track of this frame's values.
43extern int num_time_logs;
44extern LogEntry time_logs[NUM_LOGS];
45
46// Storage for keeping track of average values (each entry may not be printed
47// out each frame).
48extern AverageEntry avg_entries[NUM_LOGS];
49extern int num_avg_entries;
50
51// Call this at the start of a logging phase.
52inline static void ResetTimeLog() {
53  num_time_logs = 0;
54}
55
56
57// Log a message to be printed out when printTimeLog is called, along with the
58// amount of time in ms that has passed since the last call to this function.
59inline static void TimeLog(const char* const str) {
60  LOGV("%s", str);
61  if (num_time_logs >= NUM_LOGS) {
62    LOGE("Out of log entries!");
63    return;
64  }
65
66  time_logs[num_time_logs].id = str;
67  time_logs[num_time_logs].time_stamp = CurrentThreadTimeNanos();
68  ++num_time_logs;
69}
70
71
72inline static float Blend(float old_val, float new_val) {
73  return ALPHA * old_val + (1.0f - ALPHA) * new_val;
74}
75
76
77inline static float UpdateAverage(const char* str, const float new_val) {
78  for (int entry_num = 0; entry_num < num_avg_entries; ++entry_num) {
79    AverageEntry* const entry = avg_entries + entry_num;
80    if (str == entry->id) {
81      entry->average_duration = Blend(entry->average_duration, new_val);
82      return entry->average_duration;
83    }
84  }
85
86  if (num_avg_entries >= NUM_LOGS) {
87    LOGE("Too many log entries!");
88  }
89
90  // If it wasn't there already, add it.
91  avg_entries[num_avg_entries].id = str;
92  avg_entries[num_avg_entries].average_duration = new_val;
93  ++num_avg_entries;
94
95  return new_val;
96}
97
98
99// Prints out all the timeLog statements in chronological order with the
100// interval that passed between subsequent statements.  The total time between
101// the first and last statements is printed last.
102inline static void PrintTimeLog() {
103  LogEntry* last_time = time_logs;
104
105  float average_running_total = 0.0f;
106
107  for (int i = 0; i < num_time_logs; ++i) {
108    LogEntry* const this_time = time_logs + i;
109
110    const float curr_time =
111        (this_time->time_stamp - last_time->time_stamp) / 1000000.0f;
112
113    const float avg_time = UpdateAverage(this_time->id, curr_time);
114    average_running_total += avg_time;
115
116    LOGD("%32s:    %6.3fms    %6.4fms", this_time->id, curr_time, avg_time);
117    last_time = this_time;
118  }
119
120  const float total_time =
121      (last_time->time_stamp - time_logs->time_stamp) / 1000000.0f;
122
123  LOGD("TOTAL TIME:                          %6.3fms    %6.4fms\n",
124       total_time, average_running_total);
125  LOGD(" ");
126}
127#else
128inline static void ResetTimeLog() {}
129
130inline static void TimeLog(const char* const str) {
131  LOGV("%s", str);
132}
133
134inline static void PrintTimeLog() {}
135#endif
136
137#endif  // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TIME_LOG_H_
138