1 /*
2 * Copyright (C) 2021 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 #pragma once
18
19 #include <sys/types.h>
20
21 #include <optional>
22 #include <set>
23 #include <string>
24 #include <unordered_map>
25 #include <vector>
26
27 #include "RegEx.h"
28 #include "command.h"
29 #include "record.h"
30 #include "thread_tree.h"
31
32 namespace simpleperf {
33
34 #define RECORD_FILTER_OPTION_HELP_MSG_FOR_RECORDING \
35 "--exclude-pid pid1,pid2,... Exclude samples for selected processes.\n" \
36 "--exclude-tid tid1,tid2,... Exclude samples for selected threads.\n" \
37 "--exclude-process-name process_name_regex Exclude samples for processes with name\n" \
38 " containing the regular expression.\n" \
39 "--exclude-thread-name thread_name_regex Exclude samples for threads with name containing\n" \
40 " the regular expression.\n" \
41 "--exclude-uid uid1,uid2,... Exclude samples for processes belonging to selected uids.\n" \
42 "--include-pid pid1,pid2,... Include samples for selected processes.\n" \
43 "--include-tid tid1,tid2,... Include samples for selected threads.\n" \
44 "--include-process-name process_name_regex Include samples for processes with name\n" \
45 " containing the regular expression.\n" \
46 "--include-thread-name thread_name_regex Include samples for threads with name containing\n" \
47 " the regular expression.\n" \
48 "--include-uid uid1,uid2,... Include samples for processes belonging to selected uids.\n"
49
50 #define RECORD_FILTER_OPTION_HELP_MSG_FOR_REPORTING \
51 "--exclude-pid pid1,pid2,... Exclude samples for selected processes.\n" \
52 "--exclude-tid tid1,tid2,... Exclude samples for selected threads.\n" \
53 "--exclude-process-name process_name_regex Exclude samples for processes with name\n" \
54 " containing the regular expression.\n" \
55 "--exclude-thread-name thread_name_regex Exclude samples for threads with name containing\n" \
56 " the regular expression.\n" \
57 "--include-pid pid1,pid2,... Include samples for selected processes.\n" \
58 "--include-tid tid1,tid2,... Include samples for selected threads.\n" \
59 "--include-process-name process_name_regex Include samples for processes with name\n" \
60 " containing the regular expression.\n" \
61 "--include-thread-name thread_name_regex Include samples for threads with name containing\n" \
62 " the regular expression.\n" \
63 "--filter-file <file> Use filter file to filter samples based on timestamps. The\n" \
64 " file format is in doc/sampler_filter.md.\n"
65
GetRecordFilterOptionFormats(bool for_recording)66 inline OptionFormatMap GetRecordFilterOptionFormats(bool for_recording) {
67 OptionFormatMap option_formats = {
68 {"--exclude-pid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
69 {"--exclude-tid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
70 {"--exclude-process-name",
71 {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
72 {"--exclude-thread-name",
73 {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
74 {"--include-pid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
75 {"--include-tid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
76 {"--include-process-name",
77 {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
78 {"--include-thread-name",
79 {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
80 };
81 if (for_recording) {
82 option_formats.emplace(
83 "--exclude-uid",
84 OptionFormat({OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}));
85 option_formats.emplace(
86 "--include-uid",
87 OptionFormat({OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}));
88 } else {
89 option_formats.emplace(
90 "--filter-file",
91 OptionFormat({OptionValueType::STRING, OptionType::SINGLE, AppRunnerType::ALLOWED}));
92 }
93 return option_formats;
94 }
95
96 struct RecordFilterCondition {
97 bool used = false;
98 std::set<pid_t> pids;
99 std::set<pid_t> tids;
100 std::vector<std::unique_ptr<RegEx>> process_name_regs;
101 std::vector<std::unique_ptr<RegEx>> thread_name_regs;
102 std::set<uint32_t> uids;
103 };
104
105 class TimeFilter;
106
107 // Filter SampleRecords based on the rule below:
108 // out_sample_records = (in_sample_records & ~exclude_conditions) & include_conditions
109 // By default, exclude_conditions = 0, include_conditions = 1.
110 class RecordFilter {
111 public:
112 RecordFilter(const ThreadTree& thread_tree);
113 ~RecordFilter();
114 bool ParseOptions(OptionValueMap& options);
115 void AddPids(const std::set<pid_t>& pids, bool exclude);
116 void AddTids(const std::set<pid_t>& tids, bool exclude);
117 bool AddProcessNameRegex(const std::string& process_name, bool exclude);
118 bool AddThreadNameRegex(const std::string& thread_name, bool exclude);
119 void AddUids(const std::set<uint32_t>& uids, bool exclude);
120 bool SetFilterFile(const std::string& filename);
121
122 // Return true if the record passes filter.
123 bool Check(const SampleRecord* r);
124
125 // Check if the clock matches the clock for timestamps in the filter file.
126 bool CheckClock(const std::string& clock);
127
GetCondition(bool exclude)128 RecordFilterCondition& GetCondition(bool exclude) {
129 return exclude ? exclude_condition_ : include_condition_;
130 }
131 void Clear();
132
133 private:
134 bool CheckCondition(const SampleRecord* r, const RecordFilterCondition& condition);
135 bool SearchInRegs(std::string_view s, const std::vector<std::unique_ptr<RegEx>>& regs);
136 std::optional<uint32_t> GetUidForProcess(pid_t pid);
137
138 const ThreadTree& thread_tree_;
139 RecordFilterCondition exclude_condition_;
140 RecordFilterCondition include_condition_;
141 std::unordered_map<pid_t, std::optional<uint32_t>> pid_to_uid_map_;
142 std::unique_ptr<TimeFilter> time_filter_;
143 };
144
145 } // namespace simpleperf
146