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 <map>
22 #include <optional>
23 #include <set>
24 #include <string>
25 #include <unordered_map>
26 #include <vector>
27
28 #include "RegEx.h"
29 #include "command.h"
30 #include "record.h"
31 #include "thread_tree.h"
32
33 namespace simpleperf {
34
35 #define RECORD_FILTER_OPTION_HELP_MSG_FOR_RECORDING \
36 "--exclude-pid pid1,pid2,... Exclude samples for selected processes.\n" \
37 "--exclude-tid tid1,tid2,... Exclude samples for selected threads.\n" \
38 "--exclude-process-name process_name_regex Exclude samples for processes with name\n" \
39 " containing the regular expression.\n" \
40 "--exclude-thread-name thread_name_regex Exclude samples for threads with name containing\n" \
41 " the regular expression.\n" \
42 "--exclude-uid uid1,uid2,... Exclude samples for processes belonging to selected uids.\n" \
43 "--include-pid pid1,pid2,... Only include samples for selected processes.\n" \
44 "--include-tid tid1,tid2,... Only include samples for selected threads.\n" \
45 "--include-process-name process_name_regex Only include samples for processes with name\n" \
46 " containing the regular expression.\n" \
47 "--include-thread-name thread_name_regex Only include samples for threads with name\n" \
48 " containing the regular expression.\n" \
49 "--include-uid uid1,uid2,... Only include samples for processes belonging to selected uids.\n"
50
51 #define RECORD_FILTER_OPTION_HELP_MSG_FOR_REPORTING \
52 "--cpu cpu_item1,cpu_item2,... Only include samples for the selected cpus. cpu_item can be a\n" \
53 " number like 1, or a range like 0-3.\n" \
54 "--exclude-pid pid1,pid2,... Exclude samples for selected processes.\n" \
55 "--exclude-tid tid1,tid2,... Exclude samples for selected threads.\n" \
56 "--exclude-process-name process_name_regex Exclude samples for processes with name\n" \
57 " containing the regular expression.\n" \
58 "--exclude-thread-name thread_name_regex Exclude samples for threads with name containing\n" \
59 " the regular expression.\n" \
60 "--include-pid pid1,pid2,... Only include samples for selected processes.\n" \
61 "--include-tid tid1,tid2,... Only include samples for selected threads.\n" \
62 "--include-process-name process_name_regex Only include samples for processes with name\n" \
63 " containing the regular expression.\n" \
64 "--include-thread-name thread_name_regex Only include samples for threads with name\n" \
65 " containing the regular expression.\n" \
66 "--filter-file <file> Use filter file to filter samples based on timestamps. The\n" \
67 " file format is in doc/sampler_filter.md.\n"
68
GetRecordFilterOptionFormats(bool for_recording)69 inline OptionFormatMap GetRecordFilterOptionFormats(bool for_recording) {
70 OptionFormatMap option_formats = {
71 {"--exclude-pid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
72 {"--exclude-tid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
73 {"--exclude-process-name",
74 {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
75 {"--exclude-thread-name",
76 {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
77 {"--include-pid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
78 {"--include-tid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
79 {"--include-process-name",
80 {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
81 {"--include-thread-name",
82 {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
83 };
84 if (for_recording) {
85 option_formats.emplace(
86 "--exclude-uid",
87 OptionFormat({OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}));
88 option_formats.emplace(
89 "--include-uid",
90 OptionFormat({OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}));
91 } else {
92 option_formats.emplace("--cpu", OptionFormat({OptionValueType::STRING, OptionType::MULTIPLE,
93 AppRunnerType::ALLOWED}));
94 option_formats.emplace(
95 "--filter-file",
96 OptionFormat({OptionValueType::STRING, OptionType::SINGLE, AppRunnerType::ALLOWED}));
97 }
98 return option_formats;
99 }
100
101 class RecordFilterCondition {
102 public:
~RecordFilterCondition()103 virtual ~RecordFilterCondition() {}
104
105 // Return true if the record passes this condition.
106 virtual bool Check(const SampleRecord& sample) = 0;
107 };
108
109 // Filter a SampleRecord based on its fields:
110 // pid, process_name, tid, thread_name, user_id, time (via FilterFile).
111 // Each field is checked separately. To pass the filter, a sample should pass the check of each
112 // field. For example, if we set to include pid 1 and exclude tid 2, a sample should have
113 // `pid == 1 && tid != 2` to pass.
114 class RecordFilter {
115 public:
116 RecordFilter(const ThreadTree& thread_tree);
117 ~RecordFilter();
118 bool ParseOptions(OptionValueMap& options);
119 void AddCpus(const std::set<int>& cpus);
120 void AddPids(const std::set<pid_t>& pids, bool exclude);
121 void AddTids(const std::set<pid_t>& tids, bool exclude);
122 bool AddProcessNameRegex(const std::string& process_name, bool exclude);
123 bool AddThreadNameRegex(const std::string& thread_name, bool exclude);
124 void AddUids(const std::set<uint32_t>& uids, bool exclude);
125 bool SetFilterFile(const std::string& filename);
126
127 // Return true if the record passes filter.
128 bool Check(const SampleRecord& r);
129
130 // Check if the clock matches the clock for timestamps in the filter file.
131 bool CheckClock(const std::string& clock);
132
133 // Clear filter conditions.
134 void Clear();
135
136 private:
137 const ThreadTree& thread_tree_;
138 std::map<std::string, std::unique_ptr<RecordFilterCondition>> conditions_;
139 };
140
141 } // namespace simpleperf
142