• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 
16 #include "lperf_event_record.h"
17 
18 namespace OHOS {
19 namespace HiviewDFX {
20 namespace {
21 #undef LOG_DOMAIN
22 #undef LOG_TAG
23 #define LOG_DOMAIN 0xD002D11
24 #define LOG_TAG "DfxLperfRecordSample"
25 
26 const char* const PERF_RECORD_TYPE_SAMPLE = "sample";
27 }
28 LperfRecordSample LperfRecordFactory::record_ = {};
29 
GetName()30 const char* LperfRecordSample::GetName()
31 {
32     return PERF_RECORD_TYPE_SAMPLE;
33 }
34 
GetType() const35 uint32_t LperfRecordSample::GetType() const
36 {
37     return header_.type;
38 }
39 
InitHeader(uint8_t * data)40 void LperfRecordSample::InitHeader(uint8_t* data)
41 {
42     if (data == nullptr) {
43         header_.type = PERF_RECORD_MMAP;
44         header_.misc = PERF_RECORD_MISC_USER;
45         header_.size = 0;
46         return;
47     }
48     header_ = *(reinterpret_cast<perf_event_header *>(data));
49 }
50 
Init(uint8_t * data)51 bool LperfRecordSample::Init(uint8_t* data)
52 {
53     InitHeader(data);
54     CHECK_TRUE_AND_RET(data != nullptr, false, "LperfRecordSample Init error");
55     data_ = {};
56     uint64_t dataSize = static_cast<uint64_t>(RECORD_SIZE_LIMIT);
57     CHECK_TRUE_AND_RET(SetPointerOffset(data, sizeof(header_), dataSize), false, "set header_ offset error");
58 
59     // parse record according SAMPLE_TYPE
60     bool popId = PopFromBinary2<uint32_t, uint32_t>(sampleType_ & PERF_SAMPLE_TID,
61                                                     data, data_.pid, data_.tid, dataSize);
62     CHECK_TRUE_AND_RET(popId, false, "Init PERF_SAMPLE_TID error");
63     CHECK_TRUE_AND_RET(PopFromBinary<uint64_t>(sampleType_ & PERF_SAMPLE_TIME, data, data_.time, dataSize),
64                        false, "Init PERF_SAMPLE_TIME error");
65     CHECK_TRUE_AND_RET(PopFromBinary<uint64_t>(sampleType_ & PERF_SAMPLE_CALLCHAIN, data, data_.nr, dataSize),
66                        false, "Init PERF_SAMPLE_CALLCHAIN error");
67     if (data_.nr > 0) {
68         // the pointer is from input(data), require caller keep input(data) with *this together
69         // think it in next time
70         data_.ips = reinterpret_cast<uint64_t *>(data);
71         CHECK_TRUE_AND_RET(SetPointerOffset(data, data_.nr * sizeof(uint64_t), dataSize),
72                            false, "set ips offset error");
73     }
74     return true;
75 }
76 
Clear()77 void LperfRecordSample::Clear()
78 {
79     data_.pid = 0;
80     data_.tid = 0;
81     data_.time = 0;
82     data_.nr = 0;
83     data_.ips = nullptr;
84 }
85 
GetLperfRecord(uint32_t type,uint8_t * data)86 LperfRecordSample& LperfRecordFactory::GetLperfRecord(uint32_t type, uint8_t* data)
87 {
88     if (type != PERF_RECORD_SAMPLE || !record_.Init(data)) {
89         record_.Clear();
90         DFXLOGE("Init LperfRecordSample data error");
91     }
92     return record_;
93 }
94 
ClearData()95 void LperfRecordFactory::ClearData()
96 {
97     record_.Clear();
98 }
99 
100 template<typename T>
PopFromBinary(bool condition,uint8_t * & data,T & dest,uint64_t & size)101 inline bool PopFromBinary(bool condition, uint8_t*& data, T& dest, uint64_t& size)
102 {
103     CHECK_TRUE_AND_RET(sizeof(T) <= size, false, "PopFromBinary error");
104     if (condition) {
105         dest = *(reinterpret_cast<const T *>(data));
106         data += sizeof(T);
107         size -= sizeof(T);
108     }
109     return true;
110 }
111 
112 template<typename T1, typename T2>
PopFromBinary2(bool condition,uint8_t * & data,T1 & dest1,T2 & dest2,uint64_t & size)113 inline bool PopFromBinary2(bool condition, uint8_t*& data, T1& dest1, T2& dest2, uint64_t& size)
114 {
115     CHECK_TRUE_AND_RET(sizeof(T1) + sizeof(T2) <= size, false, "PopFromBinary2 error");
116     if (condition) {
117         dest1 = *(reinterpret_cast<const T1 *>(data));
118         data += sizeof(T1);
119         dest2 = *(reinterpret_cast<const T2 *>(data));
120         data += sizeof(T2);
121         size -= (sizeof(T1) + sizeof(T2));
122     }
123     return true;
124 }
125 
SetPointerOffset(uint8_t * & data,uint64_t offset,uint64_t & size)126 inline bool SetPointerOffset(uint8_t*& data, uint64_t offset, uint64_t& size)
127 {
128     CHECK_TRUE_AND_RET(offset <= size && offset <= RECORD_SIZE_LIMIT, false, "SetPointerOffset error");
129     size -= offset;
130     data += offset;
131     return true;
132 }
133 } // namespace HiviewDFX
134 } // namespace OHOS