summaryrefslogtreecommitdiff
path: root/simpleperf/RecordFilter.h
blob: 40206914090ef84b26734176b483e35d7d1f3922 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <sys/types.h>

#include <map>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>

#include "RegEx.h"
#include "command.h"
#include "record.h"
#include "thread_tree.h"

namespace simpleperf {

#define RECORD_FILTER_OPTION_HELP_MSG_FOR_RECORDING                                                \
  "--exclude-pid pid1,pid2,...   Exclude samples for selected processes.\n"                        \
  "--exclude-tid tid1,tid2,...   Exclude samples for selected threads.\n"                          \
  "--exclude-process-name process_name_regex   Exclude samples for processes with name\n"          \
  "                                            containing the regular expression.\n"               \
  "--exclude-thread-name thread_name_regex     Exclude samples for threads with name containing\n" \
  "                                            the regular expression.\n"                          \
  "--exclude-uid uid1,uid2,...   Exclude samples for processes belonging to selected uids.\n"      \
  "--include-pid pid1,pid2,...   Only include samples for selected processes.\n"                   \
  "--include-tid tid1,tid2,...   Only include samples for selected threads.\n"                     \
  "--include-process-name process_name_regex   Only include samples for processes with name\n"     \
  "                                            containing the regular expression.\n"               \
  "--include-thread-name thread_name_regex     Only include samples for threads with name\n"       \
  "                                            containing the regular expression.\n"               \
  "--include-uid uid1,uid2,...   Only include samples for processes belonging to selected uids.\n"

#define RECORD_FILTER_OPTION_HELP_MSG_FOR_REPORTING                                                \
  "--cpu cpu_item1,cpu_item2,... Only include samples for the selected cpus. cpu_item can be a\n"  \
  "                              number like 1, or a range like 0-3.\n"                            \
  "--exclude-pid pid1,pid2,...   Exclude samples for selected processes.\n"                        \
  "--exclude-tid tid1,tid2,...   Exclude samples for selected threads.\n"                          \
  "--exclude-process-name process_name_regex   Exclude samples for processes with name\n"          \
  "                                            containing the regular expression.\n"               \
  "--exclude-thread-name thread_name_regex     Exclude samples for threads with name containing\n" \
  "                                            the regular expression.\n"                          \
  "--include-pid pid1,pid2,...   Only include samples for selected processes.\n"                   \
  "--include-tid tid1,tid2,...   Only include samples for selected threads.\n"                     \
  "--include-process-name process_name_regex   Only include samples for processes with name\n"     \
  "                                            containing the regular expression.\n"               \
  "--include-thread-name thread_name_regex     Only include samples for threads with name\n"       \
  "                                            containing the regular expression.\n"               \
  "--filter-file <file>          Use filter file to filter samples based on timestamps. The\n"     \
  "                              file format is in doc/sampler_filter.md.\n"

inline OptionFormatMap GetRecordFilterOptionFormats(bool for_recording) {
  OptionFormatMap option_formats = {
      {"--exclude-pid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
      {"--exclude-tid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
      {"--exclude-process-name",
       {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
      {"--exclude-thread-name",
       {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
      {"--include-pid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
      {"--include-tid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
      {"--include-process-name",
       {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
      {"--include-thread-name",
       {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
  };
  if (for_recording) {
    option_formats.emplace(
        "--exclude-uid",
        OptionFormat({OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}));
    option_formats.emplace(
        "--include-uid",
        OptionFormat({OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}));
  } else {
    option_formats.emplace("--cpu", OptionFormat({OptionValueType::STRING, OptionType::MULTIPLE,
                                                  AppRunnerType::ALLOWED}));
    option_formats.emplace(
        "--filter-file",
        OptionFormat({OptionValueType::STRING, OptionType::SINGLE, AppRunnerType::ALLOWED}));
  }
  return option_formats;
}

class RecordFilterCondition {
 public:
  virtual ~RecordFilterCondition() {}

  // Return true if the record passes this condition.
  virtual bool Check(const SampleRecord& sample) = 0;
};

// Filter a SampleRecord based on its fields:
//   pid, process_name, tid, thread_name, user_id, time (via FilterFile).
// Each field is checked separately. To pass the filter, a sample should pass the check of each
// field. For example, if we set to include pid 1 and exclude tid 2, a sample should have
// `pid == 1 && tid != 2` to pass.
class RecordFilter {
 public:
  RecordFilter(const ThreadTree& thread_tree);
  ~RecordFilter();
  bool ParseOptions(OptionValueMap& options);
  void AddCpus(const std::set<int>& cpus);
  void AddPids(const std::set<pid_t>& pids, bool exclude);
  void AddTids(const std::set<pid_t>& tids, bool exclude);
  bool AddProcessNameRegex(const std::string& process_name, bool exclude);
  bool AddThreadNameRegex(const std::string& thread_name, bool exclude);
  void AddUids(const std::set<uint32_t>& uids, bool exclude);
  bool SetFilterFile(const std::string& filename);

  // Return true if the record passes filter.
  bool Check(const SampleRecord& r);

  // Check if the clock matches the clock for timestamps in the filter file.
  bool CheckClock(const std::string& clock);

  // Clear filter conditions.
  void Clear();

 private:
  const ThreadTree& thread_tree_;
  std::map<std::string, std::unique_ptr<RecordFilterCondition>> conditions_;
};

}  // namespace simpleperf