1/* 2 * Copyright (c) 2022 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 <thread> 16#include <algorithm> 17 18#include <log_utils.h> 19#include <properties.h> 20 21#include "log_stats.h" 22 23namespace OHOS { 24namespace HiviewDFX { 25using namespace std; 26 27LogStats::LogStats() 28{ 29 Reset(); 30 enable = IsStatsEnable(); 31 tagEnable = IsTagStatsEnable(); 32} 33LogStats::~LogStats() {} 34 35static inline int idxLvl(uint16_t lvl) 36{ 37 return static_cast<int>(lvl) - LevelBase; 38} 39 40static void UpdateStats(StatsEntry &entry, const StatsInfo &info) 41{ 42 LogTimeStamp ts_mono(info.mono_sec, info.tv_nsec); 43 static LogTimeStamp ts_audit_period(1, 0); // Audit period : one second 44 ts_mono -= entry.monoTimeLast; 45 if (ts_mono > ts_audit_period) { 46 entry.monoTimeLast -= entry.monoTimeAuditStart; 47 float secs = entry.monoTimeLast.FloatSecs(); 48 if (secs < 1.0f) { 49 secs = 1.0f; 50 } 51 float freq = entry.tmpLines / secs; 52 if (freq > entry.freqMax) { 53 entry.freqMax = freq; 54 entry.realTimeFreqMax = entry.realTimeLast; 55 } 56 entry.tmpLines = 0; 57 float throughput = entry.tmpLen / secs; 58 if (throughput > entry.throughputMax) { 59 entry.throughputMax = throughput; 60 entry.realTimeThroughputMax = entry.realTimeLast; 61 } 62 entry.tmpLen = 0; 63 entry.monoTimeAuditStart.SetTimeStamp(info.mono_sec, info.tv_nsec); 64 } 65 66 int lvl = idxLvl(info.level); 67 entry.lines[lvl]++; 68 entry.len[lvl] += info.len; 69 entry.dropped += info.dropped; 70 entry.tmpLines++; 71 entry.tmpLen += info.len; 72 entry.monoTimeLast.SetTimeStamp(info.mono_sec, info.tv_nsec); 73 entry.realTimeLast.SetTimeStamp(info.tv_sec, info.tv_nsec); 74} 75 76static void ResetStatsEntry(StatsEntry &entry) 77{ 78 entry.dropped = 0; 79 entry.tmpLines = 0; 80 entry.freqMax = 0; 81 entry.realTimeFreqMax.SetTimeStamp(0, 0); 82 entry.tmpLen = 0; 83 entry.throughputMax = 0; 84 entry.realTimeThroughputMax.SetTimeStamp(0, 0); 85 entry.monoTimeLast.SetTimeStamp(0, 0); 86 entry.monoTimeAuditStart.SetTimeStamp(0, 0); 87 for (uint32_t &i : entry.lines) { 88 i = 0; 89 } 90 for (uint64_t &i : entry.len) { 91 i = 0; 92 } 93} 94 95static void StatsInfo2NewStatsEntry(const StatsInfo &info, StatsEntry &entry) 96{ 97 entry.dropped = info.dropped; 98 entry.tmpLines = 1; 99 entry.freqMax = 0; 100 entry.realTimeFreqMax.SetTimeStamp(info.tv_sec, info.tv_nsec); 101 entry.tmpLen = info.len; 102 entry.throughputMax = 0; 103 entry.realTimeThroughputMax.SetTimeStamp(info.tv_sec, info.tv_nsec); 104 entry.realTimeLast.SetTimeStamp(info.tv_sec, info.tv_nsec); 105 entry.monoTimeLast.SetTimeStamp(info.mono_sec, info.tv_nsec); 106 entry.monoTimeAuditStart.SetTimeStamp(info.mono_sec, info.tv_nsec); 107 for (uint32_t &i : entry.lines) { 108 i = 0; 109 } 110 for (uint64_t &i : entry.len) { 111 i = 0; 112 } 113 int lvl = idxLvl(info.level); 114 entry.lines[lvl] = 1; 115 entry.len[lvl] = info.len; 116} 117 118void LogStats::UpdateTagTable(TagTable& tt, const StatsInfo &info) 119{ 120 if (!tagEnable) { 121 return; 122 } 123 auto itt = tt.find(info.tag); 124 if (itt != tt.end()) { 125 UpdateStats(itt->second, info); 126 } else { 127 TagStatsEntry entry; 128 StatsInfo2NewStatsEntry(info, entry); 129 (void)tt.emplace(info.tag, entry); 130 } 131} 132 133void LogStats::UpdateDomainTable(const StatsInfo &info) 134{ 135 DomainTable& t = domainStats[info.type]; 136 auto it = t.find(info.domain); 137 if (it != t.end()) { 138 UpdateStats(it->second.stats, info); 139 } else { 140 DomainStatsEntry entry; 141 StatsInfo2NewStatsEntry(info, entry.stats); 142 auto result = t.emplace(info.domain, entry); 143 if (!result.second) { 144 cerr << "Add entry to DomainTable error" << endl; 145 return; 146 } 147 it = result.first; 148 } 149 UpdateTagTable(it->second.tagStats, info); 150} 151 152void LogStats::UpdatePidTable(const StatsInfo &info) 153{ 154 PidTable& t = pidStats; 155 auto it = t.find(info.pid); 156 if (it != t.end()) { 157 UpdateStats(it->second.statsAll, info); 158 UpdateStats(it->second.stats[info.type], info); 159 } else { 160 PidStatsEntry entry; 161 StatsInfo2NewStatsEntry(info, entry.statsAll); 162 for (StatsEntry &e : entry.stats) { 163 ResetStatsEntry(e); 164 } 165 entry.stats[info.type] = entry.statsAll; 166 entry.name = GetNameByPid(info.pid); 167 auto result = t.emplace(info.pid, entry); 168 if (!result.second) { 169 cerr << "Add entry to PidTable error" << endl; 170 return; 171 } 172 it = result.first; 173 } 174 UpdateTagTable(it->second.tagStats, info); 175} 176 177void LogStats::Count(const StatsInfo &info) 178{ 179 if (enable) { 180 std::scoped_lock lk(lock); 181 int index = idxLvl(info.level); 182 totalLines[index]++; 183 totalLens[index] += info.len; 184 UpdateDomainTable(info); 185 UpdatePidTable(info); 186 } 187} 188 189void LogStats::Reset() 190{ 191 std::scoped_lock lk(lock); 192 for (auto &t : domainStats) { 193 t.clear(); 194 } 195 pidStats.clear(); 196 tsBegin = LogTimeStamp(CLOCK_REALTIME); 197 monoBegin = LogTimeStamp(CLOCK_MONOTONIC); 198 for (int i = 0; i < LevelNum; i++) { 199 totalLines[i] = 0; 200 totalLens[i] = 0; 201 } 202} 203 204const LogTypeDomainTable& LogStats::GetDomainTable() const 205{ 206 return domainStats; 207} 208 209const PidTable& LogStats::GetPidTable() const 210{ 211 return pidStats; 212} 213 214const LogTimeStamp& LogStats::GetBeginTs() const 215{ 216 return tsBegin; 217} 218 219const LogTimeStamp& LogStats::GetBeginMono() const 220{ 221 return monoBegin; 222} 223 224void LogStats::GetTotalLines(uint32_t (&in_lines)[LevelNum]) const 225{ 226 std::copy(totalLines, totalLines + LevelNum, in_lines); 227} 228 229void LogStats::GetTotalLens(uint64_t (&in_lens)[LevelNum]) const 230{ 231 std::copy(totalLens, totalLens + LevelNum, in_lens); 232} 233 234bool LogStats::IsEnable() const 235{ 236 return enable; 237} 238 239bool LogStats::IsTagEnable() const 240{ 241 return tagEnable; 242} 243 244std::unique_lock<std::mutex> LogStats::GetLock() 245{ 246 std::unique_lock<std::mutex> lk(lock); 247 return lk; 248} 249 250void LogStats::Print() 251{ 252 cout << "Domain Table:" << endl; 253 int i = 0; 254 for (auto &t : domainStats) { 255 i++; 256 if (t.size() == 0) { 257 continue; 258 } 259 cout << " Log type:" << (i - 1) << endl; 260 for (auto &it : t) { 261 cout << " Domain: 0x" << std::hex << it.first << std::dec << endl; 262 cout << " "; 263 it.second.stats.Print(); 264 for (auto &itt : it.second.tagStats) { 265 cout << " Tag: " << itt.first << endl; 266 cout << " "; 267 itt.second.Print(); 268 } 269 } 270 } 271 cout << "Pid Table:" << endl; 272 for (auto &t : pidStats) { 273 cout << " Proc: " << t.second.name << "(" << t.first << ")" << endl; 274 cout << " "; 275 t.second.statsAll.Print(); 276 int i = 0; 277 for (auto &s : t.second.stats) { 278 i++; 279 if (s.GetTotalLines() == 0) { 280 continue; 281 } 282 cout << " Log Type: " << (i - 1) << endl; 283 cout << " "; 284 s.Print(); 285 } 286 for (auto &itt : t.second.tagStats) { 287 cout << " Tag: " << itt.first << endl; 288 cout << " "; 289 itt.second.Print(); 290 } 291 } 292} 293} // namespace HiviewDFX 294} // namespace OHOS