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 "gpu_data_plugin.h"
17#include <ctime>
18#include "gpu_plugin_result.pbencoder.h"
19
20namespace {
21using namespace OHOS::Developtools::Profiler;
22const std::string GPU_PATH = "/sys/class/devfreq/gpufreq/gpu_scene_aware/utilisation";
23} // namespace
24
25int GpuDataPlugin::Start(const uint8_t* configData, uint32_t configSize)
26{
27    CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, RET_FAIL,
28               "%s:parseFromArray failed!", __func__);
29
30    if (protoConfig_.pid() > 0) {
31        pid_ = protoConfig_.pid();
32    }
33
34    file_.open(GPU_PATH);
35    if (!file_.is_open()) {
36        PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to open(%s)", __func__, GPU_PATH.c_str());
37        return RET_FAIL;
38    }
39    PROFILER_LOG_INFO(LOG_CORE, "%s:start success!", __func__);
40    return RET_SUCC;
41}
42
43int GpuDataPlugin::ReportOptimize(RandomWriteCtx* randomWrite)
44{
45    ProtoEncoder::GpuData dataProto(randomWrite);
46    WriteGpuDataInfo(dataProto);
47    int msgSize = dataProto.Finish();
48    return msgSize;
49}
50
51int GpuDataPlugin::Report(uint8_t* data, uint32_t dataSize)
52{
53    GpuData dataProto;
54    uint32_t length;
55    WriteGpuDataInfo(dataProto);
56
57    length = dataProto.ByteSizeLong();
58    if (length > dataSize) {
59        return -length;
60    }
61    if (dataProto.SerializeToArray(data, length) > 0) {
62        return length;
63    }
64    return 0;
65}
66
67int GpuDataPlugin::Stop()
68{
69    file_.close();
70    PROFILER_LOG_INFO(LOG_CORE, "%s:stop success!", __func__);
71    return 0;
72}
73
74int GpuDataPlugin::ReadFile()
75{
76    file_.clear();
77    file_.seekg(0);
78    std::string line;
79    std::getline(file_, line);
80    if (line == "") {
81        return RET_FAIL;
82    }
83    for (char charac : line) {
84        if (!isdigit(charac)) {
85            PROFILER_LOG_ERROR(LOG_CORE, "invalid file content for (%s)", GPU_PATH.c_str());
86            return RET_FAIL;
87        }
88    }
89    return stoi(line);
90}
91
92template <typename T> void GpuDataPlugin::WriteGpuDataInfo(T& gpuData)
93{
94    int ret = ReadFile();
95    if (ret == RET_FAIL) {
96        return;
97    }
98
99    constexpr uint64_t nanoSeconds = 1000000000;
100    struct timespec ts;
101    clock_gettime(CLOCK_BOOTTIME, &ts);
102    uint64_t boottime = (static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
103        static_cast<uint64_t>(ts.tv_nsec)) / 1000000;
104    gpuData.set_boottime(boottime);
105    gpuData.set_gpu_utilisation(static_cast<uint64_t>(ret));
106}
107