1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2021. 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 #include <chrono>
16 #include <fcntl.h>
17 #include <gtest/gtest.h>
18 #include <thread>
19 #include <unistd.h>
20
21 #include "file_utils.h"
22 #include "ftrace_fs_ops.h"
23 #include "ftrace_parser.h"
24 #include "securec.h"
25 #include "sub_event_parser.h"
26
27 using FTRACE_NS::EventFormat;
28 using FTRACE_NS::FtraceFsOps;
29 using FTRACE_NS::FtraceParser;
30 using FTRACE_NS::SubEventParser;
31 using testing::ext::TestSize;
32
33 namespace {
34 #ifndef PAGE_SIZE
35 constexpr uint32_t PAGE_SIZE = 4096;
36 #endif
37 constexpr auto TEST_DELAY = std::chrono::milliseconds(10);
38 constexpr uint32_t SCHED_SWITCH_EVENT_ID = 189;
39 const std::string SCHED_SWITCH_FORMAT_DESC = R"(
40 name: sched_switch
41 ID: 189
42 format:
43 field:unsigned short common_type; offset:0; size:2; signed:0;
44 field:unsigned char common_flags; offset:2; size:1; signed:0;
45 field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
46 field:int common_pid; offset:4; size:4; signed:1;
47
48 field:char prev_comm[16]; offset:8; size:16; signed:0;
49 field:pid_t prev_pid; offset:24; size:4; signed:1;
50 field:int prev_prio; offset:28; size:4; signed:1;
51 field:long prev_state; offset:32; size:4; signed:1;
52 field:char next_comm[16]; offset:36; size:16; signed:0;
53 field:pid_t next_pid; offset:52; size:4; signed:1;
54 field:int next_prio; offset:56; size:4; signed:1;
55
56 print fmt: "prev_comm=%s prev_pid=%d prev_prio=%d prev_state=%s%s ==> next_comm=%s next_pid=%d next_prio=%d", ...
57 )";
58
59 using SubEventParser = SubEventParser<FtraceEvent>;
60
61 class SubEventParserTest : public ::testing::Test {
62 protected:
63 void SetUp() override
64 {
65 SubEventParser::GetInstance().idToFunctions_.clear();
66 }
67
68 void TearDown() override
69 {
70 SubEventParser::GetInstance().idToFunctions_.clear();
71 }
72 };
73
74 /*
75 * @tc.name: IsSupportName
76 * @tc.desc: test SubEventParser::IsSupport with normal case.
77 * @tc.type: FUNC
78 */
HWTEST_F(SubEventParserTest, IsSupportName, TestSize.Level1)79 HWTEST_F(SubEventParserTest, IsSupportName, TestSize.Level1)
80 {
81 EXPECT_FALSE(SubEventParser::GetInstance().IsSupport("xxx"));
82 EXPECT_TRUE(SubEventParser::GetInstance().IsSupport("sched_switch"));
83 }
84
85 /*
86 * @tc.name: SetupEvent
87 * @tc.desc: test SubEventParser::SetupEvent with normal case.
88 * @tc.type: FUNC
89 */
HWTEST_F(SubEventParserTest, SetupEvent, TestSize.Level1)90 HWTEST_F(SubEventParserTest, SetupEvent, TestSize.Level1)
91 {
92 EventFormat format;
93 FtraceParser ftraceParser;
94 format.eventType = "sched";
95 format.eventName = "sched_switch";
96 EXPECT_TRUE(ftraceParser.ParseEventFormat(SCHED_SWITCH_FORMAT_DESC, format));
97
98 EXPECT_TRUE(nullptr == SubEventParser::GetInstance().GetParseEventCtx(format.eventId));
99 EXPECT_TRUE(SubEventParser::GetInstance().SetupEvent(format));
100 EXPECT_TRUE(nullptr != SubEventParser::GetInstance().GetParseEventCtx(format.eventId));
101 }
102
103 /*
104 * @tc.name: IsSupportId
105 * @tc.desc: test SubEventParser::IsSupport with normal case.
106 * @tc.type: FUNC
107 */
HWTEST_F(SubEventParserTest, IsSupportId, TestSize.Level1)108 HWTEST_F(SubEventParserTest, IsSupportId, TestSize.Level1)
109 {
110 EventFormat format;
111 FtraceParser ftraceParser;
112 format.eventType = "sched";
113 format.eventName = "sched_switch";
114 EXPECT_TRUE(ftraceParser.ParseEventFormat(SCHED_SWITCH_FORMAT_DESC, format));
115
116 SubEventParser::GetInstance().schedSwitchCtx = nullptr;
117 EXPECT_TRUE(nullptr == SubEventParser::GetInstance().GetParseEventCtx(format.eventId));
118 EXPECT_TRUE(SubEventParser::GetInstance().SetupEvent(format));
119 EXPECT_TRUE(nullptr != SubEventParser::GetInstance().GetParseEventCtx(format.eventId));
120 }
121
122 /*
123 * @tc.name: ParseEvent
124 * @tc.desc: test SubEventParser::ParseEvent with normal case.
125 * @tc.type: FUNC
126 */
HWTEST_F(SubEventParserTest, ParseEvent, TestSize.Level1)127 HWTEST_F(SubEventParserTest, ParseEvent, TestSize.Level1)
128 {
129 EventFormat format;
130 FtraceParser ftraceParser;
131 format.eventType = "sched";
132 format.eventName = "sched_switch";
133 EXPECT_TRUE(ftraceParser.ParseEventFormat(SCHED_SWITCH_FORMAT_DESC, format));
134 EXPECT_TRUE(SubEventParser::GetInstance().SetupEvent(format));
135 EXPECT_EQ(format.eventId, SCHED_SWITCH_EVENT_ID);
136
137 std::vector<uint8_t> buffer(PAGE_SIZE, 0);
138 std::vector<uint8_t> zeros(PAGE_SIZE, 0);
139 std::string traceRaw;
140 if (FtraceFsOps::GetInstance().IsHmKernel()) {
141 traceRaw = FtraceFsOps::GetInstance().GetHmRawTracePath();
142 } else {
143 traceRaw = FtraceFsOps::GetInstance().GetRawTracePath(0);
144 }
145 int fd = open(traceRaw.c_str(), O_EXCL);
146 EXPECT_NE(fd, -1);
147
148 EXPECT_TRUE(FtraceFsOps::GetInstance().ClearTraceBuffer());
149 EXPECT_TRUE(FtraceFsOps::GetInstance().EnableEvent("sched", "sched_switch"));
150 EXPECT_TRUE(FtraceFsOps::GetInstance().EnableTracing());
151
152 std::this_thread::sleep_for(TEST_DELAY);
153 EXPECT_EQ(read(fd, buffer.data(), buffer.size()), static_cast<int>(PAGE_SIZE));
154 EXPECT_TRUE(FtraceFsOps::GetInstance().DisableTracing());
155 EXPECT_EQ(close(fd), 0);
156 EXPECT_NE(buffer, zeros);
157
158 FtraceEvent event = {};
159 auto* ctx = SubEventParser::GetInstance().GetParseEventCtx(format.eventId);
160 EXPECT_TRUE(ctx != nullptr);
161 SubEventParser::GetInstance().ParseEvent(event, buffer.data(), buffer.size(), ctx);
162 }
163 } // namespace
164