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
16 #include "ebpf_splitter.h"
17 #include <cinttypes>
18
19 namespace SysTuning {
20 namespace TraceStreamer {
21 // using namespace SysTuning::base;
22 using namespace SysTuning::EbpfStdtype;
SetEbpfDataOffset(uint64_t offset)23 void EbpfSplitter::SetEbpfDataOffset(uint64_t offset)
24 {
25 // 记录ebpf的1024头相对于文件的位置。
26 offsetOfEbpfDataInFile_ = offset;
27 }
28
SetSpliteTimeRange(uint64_t splitFileMinTs,uint64_t splitFileMaxTs)29 void EbpfSplitter::SetSpliteTimeRange(uint64_t splitFileMinTs, uint64_t splitFileMaxTs)
30 {
31 splitFileMinTs_ = splitFileMinTs;
32 splitFileMaxTs_ = splitFileMaxTs;
33 TS_LOGI("splitFileMinTs_ = %" PRIu64 ", splitFileMaxTs_ = %" PRIu64 "", splitFileMinTs_, splitFileMaxTs_);
34 }
SplitEbpfHeader(std::deque<uint8_t> & dequeBuffer)35 bool EbpfSplitter::SplitEbpfHeader(std::deque<uint8_t>& dequeBuffer)
36 {
37 splitEbpfHeader_ = std::make_unique<EbpfDataHeader>();
38 std::copy_n(dequeBuffer.begin(), EbpfDataHeader::EBPF_DATA_HEADER_SIZE,
39 reinterpret_cast<char*>(splitEbpfHeader_.get()));
40 if (splitEbpfHeader_->header.magic != EbpfDataHeader::HEADER_MAGIC) {
41 TS_LOGE("Get EBPF file header failed! magic = %" PRIx64 "", splitEbpfHeader_->header.magic);
42 return false;
43 }
44 if (splitEbpfHeader_->header.headSize != EbpfDataHeader::EBPF_DATA_HEADER_SIZE) {
45 TS_LOGE("Get ebpf file header failed! headSize = %u", splitEbpfHeader_->header.headSize);
46 return false;
47 }
48 TS_LOGI("EBPF data header : magic = %" PRIu64 ", headSize = %u, clock = %u, cmdline = %s",
49 splitEbpfHeader_->header.magic, splitEbpfHeader_->header.headSize, splitEbpfHeader_->header.clock,
50 splitEbpfHeader_->cmdline);
51 splittedLen_ += EbpfDataHeader::EBPF_DATA_HEADER_SIZE;
52 dequeBuffer.erase(dequeBuffer.begin(), dequeBuffer.begin() + EbpfDataHeader::EBPF_DATA_HEADER_SIZE);
53 return true;
54 }
55
AddAndSplitEbpfData(std::deque<uint8_t> & dequeBuffer)56 bool EbpfSplitter::AddAndSplitEbpfData(std::deque<uint8_t>& dequeBuffer)
57 {
58 if (!splitEbpfHeader_) {
59 HtraceSplitResult ebpfHtraceHead = {.type = (int32_t)SplitDataDataType::SPLIT_FILE_DATA,
60 .buffer = {.address = reinterpret_cast<uint8_t*>(&profilerHeader_),
61 .size = sizeof(ProfilerTraceFileHeader)}};
62 ebpfSplitResult_.emplace_back(ebpfHtraceHead);
63 if (dequeBuffer.size() >= EbpfDataHeader::EBPF_DATA_HEADER_SIZE) {
64 auto ret = SplitEbpfHeader(dequeBuffer);
65 HtraceSplitResult ebpfHead = {.type = (int32_t)SplitDataDataType::SPLIT_FILE_DATA,
66 .buffer = {.address = reinterpret_cast<uint8_t*>(splitEbpfHeader_.get()),
67 .size = EbpfDataHeader::EBPF_DATA_HEADER_SIZE}};
68 ebpfSplitResult_.emplace_back(ebpfHead);
69 TS_ASSERT(ret);
70 } else {
71 return false;
72 }
73 }
74
75 SplitEbpfBodyData(dequeBuffer);
76 uint64_t unUsedLength = profilerHeader_.data.length - sizeof(ProfilerTraceFileHeader) - splittedLen_;
77 if (unUsedLength < EBPF_TITLE_SIZE) {
78 profilerHeader_.data.length = usefulDataLen_ + sizeof(ProfilerTraceFileHeader) + sizeof(EbpfDataHeader);
79
80 dequeBuffer.erase(dequeBuffer.begin(), dequeBuffer.begin() + unUsedLength);
81 return true;
82 }
83 return false;
84 }
AppendSplitOriginSegResult(uint32_t segLen)85 void EbpfSplitter::AppendSplitOriginSegResult(uint32_t segLen)
86 {
87 HtraceSplitResult publicDataOffset{.type = (int32_t)SplitDataDataType::SPLIT_FILE_JSON,
88 .originSeg = {.offset = offsetOfEbpfDataInFile_ + splittedLen_, .size = segLen}};
89 usefulDataLen_ += segLen;
90 ebpfSplitResult_.emplace_back(publicDataOffset);
91 }
SplitEbpfBodyData(std::deque<uint8_t> & dequeBuffer)92 void EbpfSplitter::SplitEbpfBodyData(std::deque<uint8_t>& dequeBuffer)
93 {
94 while (profilerHeader_.data.length - sizeof(ProfilerTraceFileHeader) - splittedLen_ > EBPF_TITLE_SIZE &&
95 dequeBuffer.size() > EBPF_TITLE_SIZE) {
96 EbpfTypeAndLength dataTitle;
97 std::copy_n(dequeBuffer.begin(), EBPF_TITLE_SIZE, reinterpret_cast<char*>(&dataTitle));
98 if (dataTitle.length + EBPF_TITLE_SIZE > dequeBuffer.size()) {
99 return;
100 }
101 auto segLen = EBPF_TITLE_SIZE + dataTitle.length;
102 switch (dataTitle.type) {
103 case ITEM_EVENT_MAPS:
104 case ITEM_SYMBOL_INFO:
105 case ITEM_EVENT_STR:
106 case ITEM_EVENT_KENEL_SYMBOL_INFO: {
107 AppendSplitOriginSegResult(segLen);
108 } break;
109 case ITEM_EVENT_FS: {
110 FsFixedHeader fsFixedHeader;
111 AppendSplitResultWithFixedHeader(segLen, dequeBuffer, fsFixedHeader);
112 } break;
113 case ITEM_EVENT_VM: {
114 PagedMemoryFixedHeader pagedMemoryFixedHeader;
115 AppendSplitResultWithFixedHeader(segLen, dequeBuffer, pagedMemoryFixedHeader);
116 } break;
117 case ITEM_EVENT_BIO: {
118 BIOFixedHeader bioFixedHeader;
119 AppendSplitResultWithFixedHeader(segLen, dequeBuffer, bioFixedHeader);
120 } break;
121 default:
122 TS_LOGI("Do not support EBPF type: %d, length: %d", dataTitle.type, dataTitle.length);
123 }
124 dequeBuffer.erase(dequeBuffer.begin(), dequeBuffer.begin() + segLen);
125 splittedLen_ += segLen;
126 }
127 }
128 } // namespace TraceStreamer
129 } // namespace SysTuning
130