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 //
43 //  By default the profiler is disabled.
44 //
45 // Usage:
46 //  1. To Create a profiler, please call Profiler::Create(...).
47 //  2. Use Start() and End() to profile the enclosed code snippet.
48 //  3. Use SetUseCase to specify the name of the profiling target (purpose).
49 //  4  If you want to dump the profiling data to the disk, call
50 //     SetDumpFilePrefix(), which is default to "/vendor/camera/profiler/".
51 //     The dumped file name is the prefix name + usecase name.
52 //
53 // Example Code:
54 //  In the following example, we use a for loop to profile two fucntions Foo()
55 //  and Bar; Foo() run once, and Bar() run twice.
56 //
57 //   std::unique_ptr<Profiler> profiler = Profiler::Create(Profiler::kPrintBit);
58 //   profiler->SetUseCase("Profiling Example");
59 //
60 //   for (int i = 0; i < 100; i++) {
61 //     profiler->Start("Foo function", i);
62 //     Foo()
63 //     profiler->End("Foo function", i);
64 //
65 //     profiler->Start("Bar function", i);
66 //     Bar()
67 //     profiler->End("Bar function", i);
68 //
69 //     profiler->Start("Bar function", i);
70 //     Bar()
71 //     profiler->End("Bar function", i);
72 //   }
73 //
74 // Example Print Out:
75 //
76 // UseCase: Profiling Example. Profiled Frames: 100.
77 //      Foo function           Max:  0.012 ms.   Avg:  0.020 ms x 1 =  0.040 ms
78 //      Bar function           Max:  0.008 ms.   Avg:  0.019 ms x 2 =  0.039 ms
79 //                      SUM OF MAX:  0.020 ms,           SUM OF AVG =  0.079 ms
80 //
81 class Profiler {
82  public:
83   // Invalid request id.
84   static constexpr int kInvalidRequestId = std::numeric_limits<int>::max();
85 
86   // Create profiler.
87   static std::shared_ptr<Profiler> Create(int option);
88 
~Profiler()89   virtual ~Profiler(){};
90 
91   // adb setprop options.
92   enum SetPropFlag {
93     kDisable = 0,
94     kPrintBit = 1 << 0,
95     kDumpBit = 1 << 1,
96     kStopWatch = 1 << 2
97   };
98 
99   // Setup the name of use case the profiler is running.
100   // Argument:
101   //  usecase: the name use case of the profiler is running.
102   virtual void SetUseCase(std::string usecase) = 0;
103 
104   // Set the file prefix name for dumpping the profiling file.
105   // Argument:
106   //  dump_file_prefix: file prefix name. In the current setting,
107   //    "/data/vendor/camera/" is a valid folder for camera to dump file.
108   //    A valid prefix can be "/data/vendor/camera/test_prefix_".
109   virtual void SetDumpFilePrefix(std::string dump_file_prefix) = 0;
110 
111   // Start to profile.
112   // We use start and end to choose which code snippet to be profile.
113   // The user specifies the name, and the profiler will print the name and its
114   // timing.
115   // Arguments:
116   //   name: the name of the node to be profiled.
117   //   request_id: frame requesd id.
118   virtual void Start(const std::string name, int request_id) = 0;
119 
120   // End the profileing.
121   // Arguments:
122   //   name: the name of the node to be profiled. Should be the same in Start().
123   //   request_id: frame requesd id.
124   virtual void End(const std::string name, int request_id) = 0;
125 
126   // Print out the profiling result in the standard output (ANDROID_LOG_ERROR).
127   virtual void PrintResult() = 0;
128 
129  protected:
Profiler()130   Profiler(){};
131 };
132 
133 // A scoped utility class to facilitate profiling.
134 class ScopedProfiler {
135  public:
136   // Constructor.
137   // Arguments:
138   //   profiler: profiler object.
139   //   target: the name of the target to be profiled.
140   //   request_id: frame requesd id.
ScopedProfiler(std::shared_ptr<Profiler> profiler,const std::string target,int request_id)141   ScopedProfiler(std::shared_ptr<Profiler> profiler, const std::string target,
142                  int request_id)
143       : profiler_(profiler),
144         target_(std::move(target)),
145         request_id_(request_id) {
146     profiler_->Start(target_, request_id_);
147   }
148 
ScopedProfiler(std::shared_ptr<Profiler> profiler,const std::string target)149   ScopedProfiler(std::shared_ptr<Profiler> profiler, const std::string target)
150       : profiler_(profiler), target_(std::move(target)) {
151     request_id_ = Profiler::kInvalidRequestId;
152     profiler_->Start(target_, request_id_);
153   }
154 
ScopedProfiler(const std::string target,int option)155   ScopedProfiler(const std::string target, int option)
156       : target_(std::move(target)) {
157     profiler_ = Profiler::Create(option);
158     request_id_ = Profiler::kInvalidRequestId;
159     profiler_->Start(target_, request_id_);
160   }
161 
~ScopedProfiler()162   ~ScopedProfiler() {
163     profiler_->End(target_, request_id_);
164   }
165 
166  private:
167   std::shared_ptr<Profiler> profiler_;
168   const std::string target_;
169   int request_id_;
170 };
171 
172 }  // namespace camera_common
173 }  // namespace google
174 
175 #endif  // HARDWARE_GOOGLE_CAMERA_COMMON_PROFILER_H
176