1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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
16#include "metrics.h"
17#include <regex>
18#include "string_help.h"
19
20namespace SysTuning {
21namespace TraceStreamer {
22constexpr uint32_t EXTRA_CHAR = 4;
23constexpr uint32_t SEND_FINISH = 1;
24constexpr uint32_t FUNCTION_ITEM_DUR_MIN = 1;
25constexpr uint32_t FUNCTION_ITEM_DUR_MAX = 2;
26constexpr uint32_t FUNCTION_ITEM_DUR_AVG = 3;
27constexpr uint32_t FUNCTION_ITEM_FUNCTION_NAME = 4;
28Metrics ::Metrics()
29{
30    metricsFunction_ = {
31        {TRACE_MEM, std::bind(&Metrics::InitMemoryStrategy, this, std::placeholders::_1)},
32        {TRACE_MEM_TOP_TEN, std::bind(&Metrics::InitMemoryStrategy, this, std::placeholders::_1)},
33        {TRACE_MEM_UNAGG, std::bind(&Metrics::InitMemoryUnAggStrategy, this, std::placeholders::_1)},
34        {TRACE_TASK_NAMES, std::bind(&Metrics::InitMemoryTaskNameStrategy, this, std::placeholders::_1)},
35        {TRACE_STATS, std::bind(&Metrics::InitTraceStatsStrategy, this, std::placeholders::_1)},
36        {TRACE_METADATA, std::bind(&Metrics::InitTraceMetaDataStrategy, this, std::placeholders::_1)},
37        {SYS_CALLS, std::bind(&Metrics::InitSysCallStrategy, this, std::placeholders::_1)}};
38    initMetricsMap_ = {
39        {METRICS_TRACE_MEM, TRACE_MEM},
40        {METRICS_TRACE_MEM_TOP_TEN, TRACE_MEM_TOP_TEN},
41        {METRICS_TRACE_MEM_UNAGG, TRACE_MEM_UNAGG},
42        {METRICS_TRACE_TASK_NAMES, TRACE_TASK_NAMES},
43        {METRICS_TRACE_STATS, TRACE_STATS},
44        {METRICS_TRACE_METADATA, TRACE_METADATA},
45        {METRICS_SYS_CALLS, SYS_CALLS},
46    };
47}
48
49void Metrics::ParserJson(const std::string &metrics, std::string &result)
50{
51    result = result.substr(EXTRA_CHAR, result.size());
52    auto it = metricsFunction_.find(metrics);
53    if (it == metricsFunction_.end()) {
54        TS_LOGE("Not support metrics!");
55        return;
56    }
57    it->second(result);
58}
59
60void Metrics::InitMemoryStrategy(const std::string &result)
61{
62    json jMessage = json::parse(result);
63    const uint32_t typeInfoItemMax = 0;
64    const uint32_t typeInfoItemMin = 1;
65    const uint32_t typeInfoItemAvg = 2;
66    const uint32_t processMetricesItemsName = 4;
67    for (int i = 0; i < jMessage.at("values").size(); i++) {
68        TypeInfoItem typeInfoItem;
69        typeInfoItem.max = jMessage.at("values")[i].at(typeInfoItemMax);
70        typeInfoItem.min = jMessage.at("values")[i].at(typeInfoItemMin);
71        typeInfoItem.avg = jMessage.at("values")[i].at(typeInfoItemAvg);
72        ProcessMetricsItems processMetricsItems;
73        processMetricsItems.overallCounters = typeInfoItem;
74        processMetricsItems.processName = jMessage.at("values")[i].at(processMetricesItemsName);
75        memStrategy_.emplace_back(std::move(processMetricsItems));
76    }
77    return;
78}
79void Metrics::InitMemoryUnAggStrategy(const std::string &result)
80{
81    json jMessage = json::parse(result);
82    const uint32_t processValuesItemName = 0;
83    const uint32_t namesIndex = 1;
84    const uint32_t valuesIndex = 2;
85    const uint32_t timesIndex = 3;
86    for (int i = 0; i < jMessage.at("values").size(); i++) {
87        ProcessValuesItem processValuesItem;
88        if (jMessage.at("values")[i].at(0).is_null()) {
89            processValuesItem.processName = "";
90        } else {
91            processValuesItem.processName = jMessage.at("values")[i].at(processValuesItemName);
92        }
93        auto names = base::SplitStringToVec(jMessage.at("values")[i].at(namesIndex), ",");
94        auto values = base::SplitStringToVec(jMessage.at("values")[i].at(valuesIndex), ",");
95        auto times = base::SplitStringToVec(jMessage.at("values")[i].at(timesIndex), ",");
96        auto oomScoreValue = 0;
97        for (auto index = 0; index < names.size(); index++) {
98            if (names[index] == "oom_score_adj") {
99                oomScoreValue = atoi(values.at(index).c_str());
100            }
101            TypeItem typeItem;
102            typeItem.ts = atoll(times.at(index).c_str());
103            typeItem.oomScore = oomScoreValue;
104            typeItem.value = atoi(values.at(index).c_str());
105            if (names.at(index) == "mem.rss.anon") {
106                processValuesItem.anonRss = typeItem;
107            } else if (names.at(index) == "mem.swap") {
108                processValuesItem.swap = typeItem;
109            } else if (names.at(index) == "mem.rss.file") {
110                processValuesItem.fileRss = typeItem;
111            } else if (names.at(index) == "oom_score_adj") {
112                processValuesItem.anonAndSwap = typeItem;
113            }
114        }
115        memAggStrategy_.emplace_back(processValuesItem);
116    }
117    return;
118}
119void Metrics::InitMemoryTaskNameStrategy(const std::string &result)
120{
121    json jMessage = json::parse(result);
122    const uint32_t jmessageValueSizeOne = 1;
123    const uint32_t jmessageValueSizeTwo = 2;
124    const uint32_t jmessageValueSizeThree = 3;
125    for (int i = 0; i < jMessage.at("values").size(); i++) {
126        TaskProcessItem taskProcessItem;
127        taskProcessItem.pid = jMessage.at("values")[i].at(jmessageValueSizeOne);
128        if (jMessage.at("values")[i].at(jmessageValueSizeTwo).is_null()) {
129            taskProcessItem.processName = "";
130        } else {
131            taskProcessItem.processName = jMessage.at("values")[i].at(jmessageValueSizeTwo);
132        }
133        if (!jMessage.at("values")[i].at(jmessageValueSizeThree).is_null()) {
134            taskProcessItem.threadName =
135                base::SplitStringToVec(jMessage.at("values")[i].at(jmessageValueSizeThree), ",");
136        }
137        taskNameStrategy_.emplace_back(taskProcessItem);
138    }
139    return;
140}
141void Metrics::InitTraceStatsStrategy(const std::string &result)
142{
143    json jMessage = json::parse(result);
144    const uint32_t statItemName = 0;
145    const uint32_t statItemCount = 2;
146    const uint32_t statItemSource = 3;
147    const uint32_t statItemSeverity = 4;
148    for (int i = 0; i < jMessage.at("values").size(); i++) {
149        StatItem statItem;
150        statItem.name = jMessage.at("values")[i].at(statItemName);
151        statItem.count = jMessage.at("values")[i].at(statItemCount);
152        statItem.source = jMessage.at("values")[i].at(statItemSource);
153        statItem.severity = jMessage.at("values")[i].at(statItemSeverity);
154        statStrategy_.emplace_back(statItem);
155    }
156    return;
157}
158void Metrics::InitTraceMetaDataStrategy(const std::string &result)
159{
160    json jMessage = json::parse(result);
161    const uint32_t traceMetaDataItemName = 0;
162    const uint32_t traceMetaDataItemValue = 1;
163    for (int i = 0; i < jMessage.at("values").size(); i++) {
164        TraceMetadataItem traceMetadataItem;
165        traceMetadataItem.name = jMessage.at("values")[i].at(traceMetaDataItemName);
166        traceMetadataItem.value = jMessage.at("values")[i].at(traceMetaDataItemValue);
167        metaDataStrategy_.emplace_back(traceMetadataItem);
168    }
169    return;
170}
171void Metrics::InitSysCallStrategy(const std::string &result)
172{
173    json jMessage = json::parse(result);
174    for (int i = 0; i < jMessage.at("values").size(); i++) {
175        FunctionItem functionItem;
176        functionItem.functionName = jMessage.at("values")[i].at(FUNCTION_ITEM_FUNCTION_NAME);
177        if (!jMessage.at("values")[i].at(FUNCTION_ITEM_DUR_MAX).is_null()) {
178            functionItem.durMax = jMessage.at("values")[i].at(FUNCTION_ITEM_DUR_MAX);
179        }
180        if (!jMessage.at("values")[i].at(FUNCTION_ITEM_DUR_MIN).is_null()) {
181            functionItem.durMin = jMessage.at("values")[i].at(FUNCTION_ITEM_DUR_MIN);
182        }
183        if (!jMessage.at("values")[i].at(FUNCTION_ITEM_DUR_AVG).is_null()) {
184            functionItem.durAvg = jMessage.at("values")[i].at(FUNCTION_ITEM_DUR_AVG);
185        }
186        sysCallStrategy_.emplace_back(functionItem);
187    }
188    return;
189}
190void Metrics::PrintMetricsResult(uint32_t metricsIndex, ResultCallBack callback)
191{
192    std::string res = "\r\n";
193    std::string metricsName = "";
194    std::string repeateValue = "";
195    switch (metricsIndex) {
196        case METRICS_TRACE_MEM:
197            UpdataRepeateValueByTraceMem(repeateValue, metricsName);
198            break;
199        case METRICS_TRACE_MEM_TOP_TEN:
200            UpdataRepeateValueByTopTen(repeateValue, metricsName);
201            break;
202        case METRICS_TRACE_MEM_UNAGG:
203            UpdataRepeateValueByMemUnagg(repeateValue, metricsName);
204            break;
205        case METRICS_TRACE_TASK_NAMES:
206            UpdataRepeateValueByTaskNames(repeateValue, metricsName);
207            break;
208        case METRICS_TRACE_STATS:
209            UpdataRepeateValueByStats(repeateValue, metricsName);
210            break;
211        case METRICS_TRACE_METADATA:
212            UpdataRepeateValueByMetadata(repeateValue, metricsName);
213            break;
214        case METRICS_SYS_CALLS:
215            UpdataRepeateValueBySysCalls(repeateValue, metricsName);
216            break;
217        default:
218            break;
219    }
220    if (repeateValue != "") {
221        repeateValue.pop_back();
222    }
223    res += metricsName + ": {" + repeateValue + "}";
224    res = JsonFormat(res) + "\r\n";
225    std::regex strRegex(",");
226    auto str = std::regex_replace(res, strRegex, "");
227#ifndef IS_WASM
228    printf("%s", str.c_str());
229#else
230    callback(str, SEND_FINISH);
231#endif
232    return;
233}
234void Metrics::UpdataRepeateValueByTraceMem(std::string &repeateValue, std::string &metricsName)
235{
236    metricsName = TRACE_MEM;
237    for (auto item : memStrategy_) {
238        repeateValue += PROCESS_METRICES + PROCESS_NAME + "\"" + item.processName + "\"," + OVERALL_COUNTERS +
239                        ANON_RSS + MIN + std::to_string(item.overallCounters.min) + "," + MAX +
240                        std::to_string(item.overallCounters.max) + "," + AVG +
241                        std::to_string(item.overallCounters.avg) + "}}},";
242    }
243}
244void Metrics::UpdataRepeateValueByTopTen(std::string &repeateValue, std::string &metricsName)
245{
246    metricsName = TRACE_MEM_TOP_TEN;
247    for (auto item : memStrategy_) {
248        repeateValue += PROCESS_METRICES + PROCESS_NAME + "\"" + item.processName + "\"," + OVERALL_COUNTERS +
249                        ANON_RSS + MIN + std::to_string(item.overallCounters.min) + "," + MAX +
250                        std::to_string(item.overallCounters.max) + "," + AVG +
251                        std::to_string(item.overallCounters.avg) + "}}},";
252    }
253}
254void Metrics::UpdataRepeateValueByMemUnagg(std::string &repeateValue, std::string &metricsName)
255{
256    metricsName = TRACE_MEM_UNAGG;
257    for (auto item : memAggStrategy_) {
258        repeateValue += PROCESS_VALUES + PROCESS_NAME + "\"" + item.processName + "\"," + ANON_RSS + TS +
259                        std::to_string(item.anonRss.ts) + "," + OOM_SCORE + std::to_string(item.anonRss.oomScore) +
260                        "," + VALUE + std::to_string(item.anonRss.value) + "}," + FILE_RSS + TS +
261                        std::to_string(item.fileRss.ts) + "," + OOM_SCORE + std::to_string(item.fileRss.oomScore) +
262                        "," + VALUE + std::to_string(item.fileRss.value) + "}," + SWAP + TS +
263                        std::to_string(item.swap.ts) + "," + OOM_SCORE + std::to_string(item.swap.oomScore) + "," +
264                        VALUE + std::to_string(item.swap.value) + "}},";
265    }
266}
267void Metrics::UpdataRepeateValueByTaskNames(std::string &repeateValue, std::string &metricsName)
268{
269    metricsName = TRACE_TASK_NAMES;
270    for (auto item : taskNameStrategy_) {
271        repeateValue += PROCESS + PID + std::to_string(item.pid) + "," + PROCESS_NAME + "\"" + item.processName + "\",";
272        for (auto threadItem : item.threadName) {
273            repeateValue += THREAD_NAME + "\"" + threadItem + "\",";
274        }
275        repeateValue.pop_back();
276        repeateValue += "},";
277    }
278}
279void Metrics::UpdataRepeateValueByStats(std::string &repeateValue, std::string &metricsName)
280{
281    metricsName = TRACE_STATS;
282    for (auto item : statStrategy_) {
283        repeateValue += STAT + NAME + "\"" + item.name + "\"," + COUNT + std::to_string(item.count) + "," + SOURCE +
284                        "\"" + item.source + "\"," + SEVERITY + "\"" + item.severity + "\"" + "},";
285    }
286}
287void Metrics::UpdataRepeateValueByMetadata(std::string &repeateValue, std::string &metricsName)
288{
289    metricsName = TRACE_METADATA;
290    for (auto item : metaDataStrategy_) {
291        repeateValue +=
292            TRACE_METADATA + ":{" + NAME + "\"" + item.name + "\"," + VALUE + "\"" + item.value + "\"" + "},";
293    }
294}
295void Metrics::UpdataRepeateValueBySysCalls(std::string &repeateValue, std::string &metricsName)
296{
297    metricsName = SYS_CALLS;
298    for (auto item : sysCallStrategy_) {
299        repeateValue += FUNCTION + FUNCTION_NAME + "\"" + item.functionName + "\"," + DUR_MAX +
300                        std::to_string(item.durMax) + "," + DUR_MIN + std::to_string(item.durMin) + "," + DUR_AVG +
301                        std::to_string(item.durAvg) + "},";
302    }
303}
304std::string Metrics::GetLevelSpace(int level)
305{
306    std::string levelStr = "";
307    for (int i = 0; i < level; i++) {
308        levelStr += "    ";
309    }
310    return levelStr;
311}
312std::string Metrics::JsonFormat(std::string json)
313{
314    std::string result = "";
315    int level = 0;
316    for (std::string::size_type index = 0; index < json.size(); index++) {
317        char value = json[index];
318        if (level > 0 && json[json.size() - 1] == '\n') {
319            result += GetLevelSpace(level);
320        }
321        switch (value) {
322            case '{':
323            case '[':
324                result = result + value + "\n";
325                level++;
326                result += GetLevelSpace(level);
327                break;
328            case ',':
329                result = result + value + "\n";
330                result += GetLevelSpace(level);
331                break;
332            case '}':
333            case ']':
334                result += "\n";
335                level--;
336                result += GetLevelSpace(level);
337                result += value;
338                break;
339            default:
340                result += value;
341                break;
342        }
343    }
344    return result;
345}
346} // namespace TraceStreamer
347} // namespace SysTuning
348