1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "time_perf.h"
16 #include <climits>
17 #include "media_log.h"
18
19 namespace {
20 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MediaTimePerf"};
21 static constexpr int32_t MICRO_SEC_PER_SEC = 1000000;
22 static constexpr int64_t MAX_SEC = LLONG_MAX / MICRO_SEC_PER_SEC;
23 static constexpr int32_t INVALID_TIME = -1;
24 }
25
26 namespace OHOS {
27 namespace Media {
StartPerfRecord(uintptr_t obj,std::string_view tag)28 void TimePerf::StartPerfRecord(uintptr_t obj, std::string_view tag)
29 {
30 std::lock_guard<std::mutex> lock(mutex_);
31
32 auto objIter = objPerfRecords_.find(obj);
33 if (objIter == objPerfRecords_.end()) {
34 auto ret = objPerfRecords_.emplace(obj, TagRecords{});
35 objIter = ret.first;
36 }
37
38 auto &tagRecords = objIter->second;
39 auto tagIter = tagRecords.find(tag);
40 if (tagIter == tagRecords.end()) {
41 auto ret = tagRecords.emplace(tag, PerfRecord {INVALID_TIME});
42 tagIter = ret.first;
43 tagIter->second.currStart = INVALID_TIME;
44 tagIter->second.currStop = INVALID_TIME;
45 tagIter->second.firstTime = INVALID_TIME;
46 tagIter->second.peakTime = INVALID_TIME;
47 tagIter->second.avgTime = INVALID_TIME;
48 tagIter->second.count = 0;
49 }
50
51 auto &record = tagIter->second;
52 if (record.currStart != INVALID_TIME) {
53 MEDIA_LOGW("already start for obj: 0x%{public}06" PRIXPTR ", tag: %{public}s",
54 FAKE_POINTER(obj), tag.data());
55 return;
56 }
57
58 struct timeval start {};
59 int32_t ret = gettimeofday(&start, nullptr);
60 if (ret != 0) {
61 MEDIA_LOGW("get time of day failed");
62 return;
63 }
64 TimeVal2USec(start, record.currStart);
65 }
66
StopPerfRecord(uintptr_t obj,std::string_view tag)67 void TimePerf::StopPerfRecord(uintptr_t obj, std::string_view tag)
68 {
69 struct timeval stop {};
70 int32_t getTimeRet = gettimeofday(&stop, nullptr);
71 if (getTimeRet != 0) {
72 MEDIA_LOGW("get time of day failed");
73 }
74
75 std::lock_guard<std::mutex> lock(mutex_);
76
77 auto objIter = objPerfRecords_.find(obj);
78 if (objIter == objPerfRecords_.end()) {
79 MEDIA_LOGW("no record exits for obj: 0x%{public}06" PRIXPTR ", tag: %{public}s",
80 FAKE_POINTER(obj), tag.data());
81 return;
82 }
83
84 auto &tagRecords = objIter->second;
85 auto tagIter = tagRecords.find(tag);
86 if (tagIter == tagRecords.end()) {
87 MEDIA_LOGW("no record exits for obj: 0x%{public}06" PRIXPTR ", tag: %{public}s",
88 FAKE_POINTER(obj), tag.data());
89 return;
90 }
91
92 auto &record = tagIter->second;
93 if (record.currStart == INVALID_TIME) {
94 MEDIA_LOGW("not start record for obj: 0x%{public}06" PRIXPTR ", tag: %{public}s",
95 FAKE_POINTER(obj), tag.data());
96 return;
97 }
98
99 if (getTimeRet != 0) {
100 record.currStart = INVALID_TIME;
101 return;
102 }
103
104 TimeVal2USec(stop, record.currStop);
105 int64_t currTime = record.currStop - record.currStart;
106 if (currTime > record.peakTime || record.peakTime == INVALID_TIME) {
107 record.peakTime = currTime;
108 }
109 if (record.firstTime == INVALID_TIME) {
110 record.firstTime = currTime;
111 }
112
113 record.avgTime = (record.avgTime * record.count + currTime) / (record.count + 1);
114 record.count += 1;
115 record.currStart = INVALID_TIME;
116 record.currStop = INVALID_TIME;
117
118 MEDIA_LOGD("obj[0x%{public}06" PRIXPTR "] tag[%{public}s] "
119 "current take time: %{public}" PRIi64 "us, first time: %{public}" PRIi64 ", "
120 "peak time: %{public}" PRIi64 ", avg time: %{public}" PRIi64 ", "
121 "count: %{public}" PRIi64 "",
122 FAKE_POINTER(obj), tag.data(), currTime, record.firstTime,
123 record.peakTime, record.avgTime, record.count);
124 }
125
DumpObjectRecord(uintptr_t obj)126 void TimePerf::DumpObjectRecord(uintptr_t obj)
127 {
128 std::lock_guard<std::mutex> lock(mutex_);
129
130 auto objIter = objPerfRecords_.find(obj);
131 if (objIter == objPerfRecords_.end()) {
132 MEDIA_LOGW("no record exits for obj: 0x%{public}06" PRIXPTR, FAKE_POINTER(obj));
133 return;
134 }
135
136 for (auto &[tag, record] : objIter->second) {
137 if (record.count == 0) {
138 continue;
139 }
140 MEDIA_LOGD("obj[0x%{public}06" PRIXPTR "] tag[%{public}s] "
141 ", first time: %{public}" PRIi64 ", peak time: %{public}" PRIi64 ", "
142 "avg time: %{public}" PRIi64 ", count: %{public}" PRIi64 "",
143 FAKE_POINTER(obj), tag.data(), record.firstTime,
144 record.peakTime, record.avgTime, record.count);
145 }
146 }
147
CleanObjectRecord(uintptr_t obj)148 void TimePerf::CleanObjectRecord(uintptr_t obj)
149 {
150 std::lock_guard<std::mutex> lock(mutex_);
151
152 auto objIter = objPerfRecords_.find(obj);
153 if (objIter == objPerfRecords_.end()) {
154 return;
155 }
156 (void)objPerfRecords_.erase(objIter);
157 }
158
DumpAllRecord()159 void TimePerf::DumpAllRecord()
160 {
161 std::lock_guard<std::mutex> lock(mutex_);
162
163 for (auto &[obj, tagRecords] : objPerfRecords_) {
164 for (auto &[tag, record] : tagRecords) {
165 if (record.count == 0) {
166 continue;
167 }
168 MEDIA_LOGD("obj[0x%{public}06" PRIXPTR "] tag[%{public}s], first time: %{public}" PRIi64 ""
169 ", peak time: %{public}" PRIi64 ", avg time: %{public}" PRIi64 ", count: %{public}" PRIi64 "",
170 FAKE_POINTER(obj), tag.data(), record.firstTime,
171 record.peakTime, record.avgTime, record.count);
172 }
173 }
174 }
175
CleanAllRecord()176 void TimePerf::CleanAllRecord()
177 {
178 std::lock_guard<std::mutex> lock(mutex_);
179 objPerfRecords_.clear();
180 }
181
TimeVal2USec(const struct timeval & time,int64_t & usec)182 void TimePerf::TimeVal2USec(const struct timeval &time, int64_t &usec)
183 {
184 if ((static_cast<int64_t>(time.tv_sec) > MAX_SEC) ||
185 (static_cast<int64_t>(time.tv_sec) == MAX_SEC && time.tv_usec > 0) ||
186 (time.tv_usec > MICRO_SEC_PER_SEC)) {
187 MEDIA_LOGW("time overflow");
188 usec = 0;
189 return;
190 }
191
192 usec = static_cast<int64_t>(time.tv_sec) * MICRO_SEC_PER_SEC + time.tv_usec;
193 }
194 } // namespace Media
195 } // namespace OHOS
196