xref: /aosp_15_r20/external/perfetto/src/profiling/perf/perf_producer_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/profiling/perf/perf_producer.h"
18 
19 #include <stdint.h>
20 #include <optional>
21 
22 #include "perfetto/base/logging.h"
23 #include "test/gtest_and_gmock.h"
24 
25 namespace perfetto {
26 namespace profiling {
27 namespace {
28 
ShouldReject(pid_t pid,std::string cmdline,const TargetFilter & filter,bool skip_cmd,base::FlatSet<std::string> * additional_cmdlines)29 bool ShouldReject(pid_t pid,
30                   std::string cmdline,
31                   const TargetFilter& filter,
32                   bool skip_cmd,
33                   base::FlatSet<std::string>* additional_cmdlines) {
34   return PerfProducer::ShouldRejectDueToFilter(
35       pid, filter, skip_cmd, additional_cmdlines, [cmdline](std::string* out) {
36         *out = cmdline;
37         return true;
38       });
39 }
40 
TEST(TargetFilterTest,EmptyFilter)41 TEST(TargetFilterTest, EmptyFilter) {
42   {
43     bool skip_cmd = false;
44     base::FlatSet<std::string> extra_cmds;
45     TargetFilter filter;
46 
47     // empty filter allows everything
48     EXPECT_FALSE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
49     EXPECT_FALSE(ShouldReject(77, "/bin/echo", filter, skip_cmd, &extra_cmds));
50   }
51   {
52     bool skip_cmd = false;
53     base::FlatSet<std::string> extra_cmds;
54     TargetFilter filter;
55     filter.exclude_pids.insert(1);
56 
57     // allow everything besides the explicit exclusions
58     EXPECT_FALSE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
59     EXPECT_FALSE(ShouldReject(77, "/bin/echo", filter, skip_cmd, &extra_cmds));
60 
61     EXPECT_TRUE(ShouldReject(1, "/sbin/init", filter, skip_cmd, &extra_cmds));
62   }
63 }
64 
TEST(TargetFilterTest,TargetPids)65 TEST(TargetFilterTest, TargetPids) {
66   bool skip_cmd = false;
67   base::FlatSet<std::string> extra_cmds;
68   TargetFilter filter;
69   filter.pids.insert(32);
70   filter.pids.insert(42);
71 
72   EXPECT_FALSE(ShouldReject(32, "/bin/echo", filter, skip_cmd, &extra_cmds));
73   EXPECT_FALSE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
74 
75   EXPECT_TRUE(ShouldReject(77, "/bin/echo", filter, skip_cmd, &extra_cmds));
76 }
77 
TEST(TargetFilterTest,ExcludePids)78 TEST(TargetFilterTest, ExcludePids) {
79   bool skip_cmd = false;
80   base::FlatSet<std::string> extra_cmds;
81   TargetFilter filter;
82   filter.exclude_pids.insert(32);
83   filter.exclude_pids.insert(42);
84 
85   EXPECT_FALSE(ShouldReject(77, "/bin/echo", filter, skip_cmd, &extra_cmds));
86 
87   EXPECT_TRUE(ShouldReject(32, "/bin/echo", filter, skip_cmd, &extra_cmds));
88   EXPECT_TRUE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
89 }
90 
TEST(TargetFilterTest,TargetCmdlines)91 TEST(TargetFilterTest, TargetCmdlines) {
92   {
93     bool skip_cmd = false;
94     base::FlatSet<std::string> extra_cmds;
95     TargetFilter filter;
96     filter.cmdlines.emplace_back("echo");
97     filter.cmdlines.emplace_back("/bin/cat");
98 
99     EXPECT_FALSE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
100     EXPECT_FALSE(ShouldReject(42, "/bin/cat", filter, skip_cmd, &extra_cmds));
101 
102     EXPECT_TRUE(ShouldReject(42, "/bin/top", filter, skip_cmd, &extra_cmds));
103   }
104   {
105     bool skip_cmd = true;
106     base::FlatSet<std::string> extra_cmds;
107     TargetFilter filter;
108     filter.cmdlines.emplace_back("echo");
109     filter.cmdlines.emplace_back("/bin/cat");
110 
111     // As above but with |skip_cmd| making none of the cmdline checks apply.
112     // Therefore everything gets rejected because it's still considered to be a
113     // filter that only requested specific targets (and none of these match).
114     EXPECT_TRUE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
115     EXPECT_TRUE(ShouldReject(42, "/bin/cat", filter, skip_cmd, &extra_cmds));
116     EXPECT_TRUE(ShouldReject(42, "/bin/top", filter, skip_cmd, &extra_cmds));
117   }
118 }
119 
TEST(TargetFilterTest,ExcludeCmdlines)120 TEST(TargetFilterTest, ExcludeCmdlines) {
121   bool skip_cmd = false;
122   base::FlatSet<std::string> extra_cmds;
123   TargetFilter filter;
124   filter.exclude_cmdlines.emplace_back("echo");
125   filter.exclude_cmdlines.emplace_back("/bin/cat");
126 
127   EXPECT_FALSE(ShouldReject(42, "/bin/top", filter, skip_cmd, &extra_cmds));
128 
129   EXPECT_TRUE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
130   EXPECT_TRUE(ShouldReject(42, "/bin/cat", filter, skip_cmd, &extra_cmds));
131 }
132 
TEST(TargetFilterTest,ExclusionPrioritised)133 TEST(TargetFilterTest, ExclusionPrioritised) {
134   bool skip_cmd = false;
135   base::FlatSet<std::string> extra_cmds;
136   TargetFilter filter;
137   filter.pids.insert(42);
138   filter.exclude_pids.insert(42);
139   filter.cmdlines.push_back("echo");
140   filter.exclude_cmdlines.push_back("echo");
141 
142   EXPECT_TRUE(ShouldReject(42, "/bin/cat", filter, skip_cmd, &extra_cmds));
143   EXPECT_TRUE(ShouldReject(100, "/bin/echo", filter, skip_cmd, &extra_cmds));
144 }
145 
TEST(TargetFilterTest,ProcessSharding)146 TEST(TargetFilterTest, ProcessSharding) {
147   {
148     bool skip_cmd = false;
149     base::FlatSet<std::string> extra_cmds;
150     TargetFilter filter;
151     filter.process_sharding =
152         ProcessSharding{/*shard_count=*/4, /*chosen_shard=*/1};
153 
154     EXPECT_FALSE(ShouldReject(1, "/bin/echo", filter, skip_cmd, &extra_cmds));
155     EXPECT_FALSE(ShouldReject(41, "/bin/echo", filter, skip_cmd, &extra_cmds));
156 
157     EXPECT_TRUE(ShouldReject(0, "/bin/echo", filter, skip_cmd, &extra_cmds));
158     EXPECT_TRUE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
159   }
160   {
161     // as above but with an explicit exclude_pid
162     bool skip_cmd = false;
163     base::FlatSet<std::string> extra_cmds;
164     TargetFilter filter;
165     filter.exclude_pids.insert(41);
166     filter.process_sharding =
167         ProcessSharding{/*shard_count=*/4, /*chosen_shard=*/1};
168 
169     EXPECT_FALSE(ShouldReject(1, "/bin/echo", filter, skip_cmd, &extra_cmds));
170 
171     // explicit exclusion applies even if pid is in the accepted shard
172     EXPECT_TRUE(ShouldReject(41, "/bin/echo", filter, skip_cmd, &extra_cmds));
173     EXPECT_TRUE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
174   }
175 }
176 
TEST(TargetFilterTest,AdditionalCmdlines)177 TEST(TargetFilterTest, AdditionalCmdlines) {
178   bool skip_cmd = false;
179   base::FlatSet<std::string> extra_cmds;
180   TargetFilter filter;
181   filter.additional_cmdline_count = 2;
182 
183   // first two distinct cmdlines remembered and allowed:
184   EXPECT_FALSE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
185   EXPECT_FALSE(ShouldReject(43, "/bin/echo", filter, skip_cmd, &extra_cmds));
186   EXPECT_FALSE(ShouldReject(44, "/bin/cat", filter, skip_cmd, &extra_cmds));
187 
188   // further cmdlines rejected:
189   EXPECT_TRUE(ShouldReject(45, "/bin/top", filter, skip_cmd, &extra_cmds));
190 
191   // remembered cmdlines still allowed:
192   EXPECT_FALSE(ShouldReject(46, "/bin/echo", filter, skip_cmd, &extra_cmds));
193 
194   EXPECT_EQ(extra_cmds.size(), 2u);
195   EXPECT_EQ(extra_cmds.count("/bin/echo"), 1u);
196   EXPECT_EQ(extra_cmds.count("/bin/cat"), 1u);
197   EXPECT_EQ(extra_cmds.count("/bin/top"), 0u);
198 }
199 
200 }  // namespace
201 }  // namespace profiling
202 }  // namespace perfetto
203