• 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 <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