1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 #ifndef HARDWARE_GOOGLE_CAMERA_COMMON_PROFILER_H
18 #define HARDWARE_GOOGLE_CAMERA_COMMON_PROFILER_H
19 
20 #include <cutils/properties.h>
21 
22 #include <limits>
23 #include <memory>
24 #include <string>
25 
26 namespace google {
27 namespace camera_common {
28 
29 // The goal of the Profiler is to profile the performance of camemra pipeline.
30 // However you can use it profile any procedure.
31 // The profiler prints out the result when the Profiler obejct is deconstructed.
32 //
33 // Setprops:
34 //  - To disable the profiler:
35 //    $ adb shell setprop persist.vendor.camera.profiler 0
36 //  - To print the profiling result in standard output:
37 //    $ adb shell setprop persist.vendor.camera.profiler 1
38 //  - To dump the profiling result to "/data/vendor/camera/profiler":
39 //    $ adb shell setprop persist.vendor.camera.profiler 2
40 //  - To print and dump the profiling result to "/data/vendor/camera/profiler":
41 //    $ adb shell setprop persist.vendor.camera.profiler 3
42 //  After add FPS option, here are the combination results.
43 //  Option 0 (kDisable): Disable Profiler
44 //  Option 1 (kPrintBit):
45 //    When close, Print the result
46 //    - Processing time
47 //    - FPS with total frames on process start function
48 //  Option 2 (kDumpBit):
49 //    When close, dump the result to file(dump_file_prefix)
50 //    - Processing time
51 //    - FPS with total frames on process start function
52 //  Option 3 (kPrintBit|kDumpBit):
53 //    When close, print and dump the result
54 //    - Processing time
55 //    - FPS with total frames on process start function
56 //  Option 8 (kPrintFpsPerIntervalBit):
57 //    Print FPS per interval on ProfileFrameRate function
58 //    The frequency is based on the value of SetFpsPrintInterval()
59 //  Option 9 (kPrintFpsPerIntervalBit|kPrintBit):
60 //    Print FPS per interval on process start and ProfileFrameRate function
61 //    When close, print the result
62 //    - Processing time
63 //    - FPS with total frames on process start function
64 //  Option 10 (kPrintFpsPerIntervalBit|kDumpBit):
65 //    Print FPS per interval on process start and ProfileFrameRate function
66 //    When close, dump the result
67 //    - Processing time
68 //    - FPS with total frames on process start function
69 //  Option 11 (kPrintFpsPerIntervalBit|kPrintBit|kDumpBit):
70 //    Print FPS per interval on process start and ProfileFrameRate function
71 //    When close, print and dump the result
72 //    - Processing time
73 //    - FPS with total frames on process start function
74 //  Option 16 (kCalculateFpsOnEndBit):
75 //    Calculate FPS on process end function instead of process start function
76 //  Option 17 (kCalculateFpsOnEndBit|kPrintBit):
77 //    When close, print the result
78 //    - Processing time
79 //    - FPS with total frames on process "end" function
80 //  Option 18 (kCalculateFpsOnEndBit|kDumpBit):
81 //    When close, dump the result
82 //    - Processing time
83 //    - FPS with total frames on process "end" function
84 //  Option 19 (kCalculateFpsOnEndBit|kPrintBitk|DumpBit):
85 //    When close, print and dump the result
86 //    - Processing time
87 //    - FPS with total frames on process "end" function
88 //  Option 25 (kCalculateFpsOnEndBit|kPrintFpsPerIntervalBit|kPrintBit):
89 //    Print FPS per interval on process start and ProfileFrameRate function
90 //    When close, print the result
91 //    - Processing time
92 //    - FPS with total frames on process "end" function
93 //  Option 26 (kCalculateFpsOnEndBit|kPrintFpsPerIntervalBit|DumpBit):
94 //    Print FPS per interval on process start and ProfileFrameRate function
95 //    When close, dump the result
96 //    - Processing time
97 //    - FPS with total frames on process "end" function
98 //  Option 27 (kCalculateFpsOnEndBit|kPrintFpsPerIntervalBit|kPrintBitk|DumpBit):
99 //    Print FPS per interval on process start and ProfileFrameRate function
100 //    When close, print and dump the result
101 //    - Processing time
102 //    - FPS with total frames on process "end" function
103 //
104 //  By default the profiler is disabled.
105 //
106 // Usage:
107 //  1. To Create a profiler, please call Profiler::Create(...).
108 //  2. Use Start() and End() to profile the enclosed code snippet.
109 //  3. Use SetUseCase to specify the name of the profiling target (purpose).
110 //  4  If you want to dump the profiling data to the disk, call
111 //     SetDumpFilePrefix(), which is default to "/vendor/camera/profiler/".
112 //     The dumped file name is the prefix name + usecase name.
113 //
114 // Example Code:
115 //  In the following example, we use a for loop to profile two fucntions Foo()
116 //  and Bar; Foo() run once, and Bar() run twice.
117 //
118 //   std::unique_ptr<Profiler> profiler = Profiler::Create(Profiler::kPrintBit);
119 //   profiler->SetUseCase("Profiling Example");
120 //
121 //   for (int i = 0; i < 100; i++) {
122 //     profiler->Start("Foo function", i);
123 //     Foo()
124 //     profiler->End("Foo function", i);
125 //
126 //     profiler->Start("Bar function", i);
127 //     Bar()
128 //     profiler->End("Bar function", i);
129 //
130 //     profiler->Start("Bar function", i);
131 //     Bar()
132 //     profiler->End("Bar function", i);
133 //   }
134 //
135 // Example Print Out:
136 //
137 // UseCase: Profiling Example. Profiled Frames: 100.
138 //      Foo function           Max:  0.012 ms.   Avg:  0.020 ms x 1 =  0.040 ms
139 //      Bar function           Max:  0.008 ms.   Avg:  0.019 ms x 2 =  0.039 ms
140 //                      SUM OF MAX:  0.020 ms,           SUM OF AVG =  0.079 ms
141 //
142 class Profiler {
143  public:
144   // Invalid request id.
145   static constexpr int kInvalidRequestId = std::numeric_limits<int>::max();
146 
147   // Create profiler.
148   static std::shared_ptr<Profiler> Create(int option);
149 
150   virtual ~Profiler() = default;
151 
152   // adb setprop options.
153   enum SetPropFlag {
154     kDisable = 0,
155     kPrintBit = 1 << 0,
156     kDumpBit = 1 << 1,
157     kStopWatch = 1 << 2,
158     // Print FPS per interval time based on the value of SetFpsPrintInterval()
159     kPrintFpsPerIntervalBit = 1 << 3,
160     // Calculate FPS on process end function instead of process start function
161     kCalculateFpsOnEndBit = 1 << 4,
162     // Dynamic start profiling.
163     kDynamicStartBit = 1 << 5,
164     // Dumps result using proto format.
165     kProto = 1 << 6,
166     // Customized profiler derived from Profiler
167     kCustomProfiler = 1 << 7,
168   };
169 
170   // Setup the name of use case the profiler is running.
171   // Argument:
172   //  usecase: the name use case of the profiler is running.
173   virtual void SetUseCase(std::string usecase) = 0;
174 
175   // Set the file prefix name for dumpping the profiling file.
176   // Argument:
177   //  dump_file_prefix: file prefix name. In the current setting,
178   //    "/data/vendor/camera/" is a valid folder for camera to dump file.
179   //    A valid prefix can be "/data/vendor/camera/test_prefix_".
180   virtual void SetDumpFilePrefix(const std::string& dump_file_prefix) = 0;
181 
182   // Start to profile.
183   // We use start and end to choose which code snippet to be profile.
184   // The user specifies the name, and the profiler will print the name and its
185   // timing.
186   // Arguments:
187   //   name: the name of the node to be profiled.
188   //   request_id: frame requesd id.
189   virtual void Start(const std::string& name, int request_id) = 0;
190 
191   // End the profileing.
192   // Arguments:
193   //   name: the name of the node to be profiled. Should be the same in Start().
194   //   request_id: frame requesd id.
195   virtual void End(const std::string& name, int request_id) = 0;
196 
197   // Print out the profiling result in the standard output (ANDROID_LOG_ERROR).
198   virtual void PrintResult() = 0;
199 
200   // Profile the frame rate
201   // If only call this function without start() and End(),
202   // creating profiler needs to set option with kPrintFpsPerIntervalBit bit.
203   // It can print FPS every second.
204   virtual void ProfileFrameRate(const std::string& name) = 0;
205 
206   // Set the interval of FPS print
207   // The interval unit is second and interval_seconds must >= 1
208   virtual void SetFpsPrintInterval(int32_t interval_seconds) = 0;
209 
210   virtual int64_t GetLatencyInNanoseconds(const std::string& name,
211                                           int request_id) = 0;
212 
213  protected:
214   Profiler() = default;
215 };
216 
217 // A scoped utility class to facilitate profiling.
218 class ScopedProfiler {
219  public:
220   // Constructor.
221   // Arguments:
222   //   profiler: profiler object.
223   //   target: the name of the target to be profiled.
224   //   request_id: frame requesd id.
ScopedProfiler(std::shared_ptr<Profiler> profiler,const std::string target,int request_id)225   ScopedProfiler(std::shared_ptr<Profiler> profiler, const std::string target,
226                  int request_id)
227       : profiler_(profiler),
228         target_(std::move(target)),
229         request_id_(request_id) {
230     profiler_->Start(target_, request_id_);
231   }
232 
ScopedProfiler(std::shared_ptr<Profiler> profiler,const std::string target)233   ScopedProfiler(std::shared_ptr<Profiler> profiler, const std::string target)
234       : profiler_(profiler), target_(std::move(target)) {
235     request_id_ = Profiler::kInvalidRequestId;
236     profiler_->Start(target_, request_id_);
237   }
238 
ScopedProfiler(const std::string target,int option)239   ScopedProfiler(const std::string target, int option)
240       : target_(std::move(target)) {
241     profiler_ = Profiler::Create(option);
242     request_id_ = Profiler::kInvalidRequestId;
243     profiler_->Start(target_, request_id_);
244   }
245 
~ScopedProfiler()246   ~ScopedProfiler() {
247     profiler_->End(target_, request_id_);
248   }
249 
250  private:
251   std::shared_ptr<Profiler> profiler_;
252   const std::string target_;
253   int request_id_;
254 };
255 
256 }  // namespace camera_common
257 }  // namespace google
258 
259 #endif  // HARDWARE_GOOGLE_CAMERA_COMMON_PROFILER_H
260