• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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