• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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