/*
 * Copyright (C) 2015 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.
 */

#include "event_selection_set.h"

#include <algorithm>
#include <atomic>
#include <thread>
#include <unordered_map>

#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>

#include "ETMRecorder.h"
#include "IOEventLoop.h"
#include "RecordReadThread.h"
#include "environment.h"
#include "event_attr.h"
#include "event_type.h"
#include "perf_regs.h"
#include "tracing.h"
#include "utils.h"

namespace simpleperf {

using android::base::StringPrintf;

bool IsBranchSamplingSupported() {
  const EventType* type = FindEventTypeByName("cpu-cycles");
  if (type == nullptr) {
    return false;
  }
  perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
  attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
  attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY;
  return IsEventAttrSupported(attr, type->name);
}

bool IsDwarfCallChainSamplingSupported() {
  if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(3, 18)) {
    // Skip test on kernel >= 3.18, which has all patches needed to support dwarf callchain.
    return true;
  }
  const EventType* type = FindEventTypeByName("cpu-clock");
  if (type == nullptr) {
    return false;
  }
  perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
  attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
  attr.exclude_callchain_user = 1;
  attr.sample_regs_user = GetSupportedRegMask(GetTargetArch());
  attr.sample_stack_user = 8192;
  return IsEventAttrSupported(attr, type->name);
}

bool IsDumpingRegsForTracepointEventsSupported() {
  if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(4, 2)) {
    // Kernel >= 4.2 has patch "5b09a094f2 arm64: perf: Fix callchain parse error with kernel
    // tracepoint events". So no need to test.
    return true;
  }
  const EventType* event_type = FindEventTypeByName("sched:sched_switch", false);
  if (event_type == nullptr) {
    return false;
  }
  std::atomic<bool> done(false);
  std::atomic<pid_t> thread_id(0);
  std::thread thread([&]() {
    thread_id = gettid();
    while (!done) {
      usleep(1);
    }
    usleep(1);  // Make a sched out to generate one sample.
  });
  while (thread_id == 0) {
    usleep(1);
  }
  perf_event_attr attr = CreateDefaultPerfEventAttr(*event_type);
  attr.freq = 0;
  attr.sample_period = 1;
  std::unique_ptr<EventFd> event_fd =
      EventFd::OpenEventFile(attr, thread_id, -1, nullptr, event_type->name);
  if (event_fd == nullptr || !event_fd->CreateMappedBuffer(4, true)) {
    done = true;
    thread.join();
    return false;
  }
  done = true;
  thread.join();

  // There are small chances that we don't see samples immediately after joining the thread on
  // cuttlefish, probably due to data synchronization between cpus. To avoid flaky tests, use a
  // loop to wait for samples.
  for (int timeout = 0; timeout < 1000; timeout++) {
    std::vector<char> buffer = event_fd->GetAvailableMmapData();
    std::vector<std::unique_ptr<Record>> records =
        ReadRecordsFromBuffer(attr, buffer.data(), buffer.size());
    for (auto& r : records) {
      if (r->type() == PERF_RECORD_SAMPLE) {
        auto& record = *static_cast<SampleRecord*>(r.get());
        return record.ip_data.ip != 0;
      }
    }
    usleep(1);
  }
  return false;
}

bool IsSettingClockIdSupported() {
  // Do the real check only once and keep the result in a static variable.
  static int is_supported = -1;
  if (is_supported == -1) {
    is_supported = 0;
    if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(4, 1)) {
      // Kernel >= 4.1 has patch "34f43927 perf: Add per event clockid support". So no need to test.
      is_supported = 1;
    } else if (const EventType* type = FindEventTypeByName("cpu-clock"); type != nullptr) {
      // Check if the kernel supports setting clockid, which was added in kernel 4.0. Just check
      // with one clockid is enough. Because all needed clockids were supported before kernel 4.0.
      perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
      attr.use_clockid = 1;
      attr.clockid = CLOCK_MONOTONIC;
      is_supported = IsEventAttrSupported(attr, type->name) ? 1 : 0;
    }
  }
  return is_supported;
}

bool IsMmap2Supported() {
  if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(3, 12)) {
    // Kernel >= 3.12 has patch "13d7a2410 perf: Add attr->mmap2 attribute to an event". So no need
    // to test.
    return true;
  }
  const EventType* type = FindEventTypeByName("cpu-clock");
  if (type == nullptr) {
    return false;
  }
  perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
  attr.mmap2 = 1;
  return IsEventAttrSupported(attr, type->name);
}

bool IsHardwareEventSupported() {
  const EventType* type = FindEventTypeByName("cpu-cycles");
  if (type == nullptr) {
    return false;
  }
  perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
  return IsEventAttrSupported(attr, type->name);
}

bool IsSwitchRecordSupported() {
  // Kernel >= 4.3 has patch "45ac1403f perf: Add PERF_RECORD_SWITCH to indicate context switches".
  auto version = GetKernelVersion();
  return version && version.value() >= std::make_pair(4, 3);
}

std::string AddrFilter::ToString() const {
  switch (type) {
    case FILE_RANGE:
      return StringPrintf("filter 0x%" PRIx64 "/0x%" PRIx64 "@%s", addr, size, file_path.c_str());
    case AddrFilter::FILE_START:
      return StringPrintf("start 0x%" PRIx64 "@%s", addr, file_path.c_str());
    case AddrFilter::FILE_STOP:
      return StringPrintf("stop 0x%" PRIx64 "@%s", addr, file_path.c_str());
    case AddrFilter::KERNEL_RANGE:
      return StringPrintf("filter 0x%" PRIx64 "/0x%" PRIx64, addr, size);
    case AddrFilter::KERNEL_START:
      return StringPrintf("start 0x%" PRIx64, addr);
    case AddrFilter::KERNEL_STOP:
      return StringPrintf("stop 0x%" PRIx64, addr);
  }
}

EventSelectionSet::EventSelectionSet(bool for_stat_cmd)
    : for_stat_cmd_(for_stat_cmd), loop_(new IOEventLoop) {}

EventSelectionSet::~EventSelectionSet() {}

bool EventSelectionSet::BuildAndCheckEventSelection(const std::string& event_name, bool first_event,
                                                    EventSelection* selection) {
  std::unique_ptr<EventTypeAndModifier> event_type = ParseEventType(event_name);
  if (event_type == nullptr) {
    return false;
  }
  if (for_stat_cmd_) {
    if (event_type->event_type.name == "cpu-clock" || event_type->event_type.name == "task-clock") {
      if (event_type->exclude_user || event_type->exclude_kernel) {
        LOG(ERROR) << "Modifier u and modifier k used in event type " << event_type->event_type.name
                   << " are not supported by the kernel.";
        return false;
      }
    }
  }
  selection->event_type_modifier = *event_type;
  selection->event_attr = CreateDefaultPerfEventAttr(event_type->event_type);
  selection->event_attr.exclude_user = event_type->exclude_user;
  selection->event_attr.exclude_kernel = event_type->exclude_kernel;
  selection->event_attr.exclude_hv = event_type->exclude_hv;
  selection->event_attr.exclude_host = event_type->exclude_host;
  selection->event_attr.exclude_guest = event_type->exclude_guest;
  selection->event_attr.precise_ip = event_type->precise_ip;
  if (IsEtmEventType(event_type->event_type.type)) {
    auto& etm_recorder = ETMRecorder::GetInstance();
    if (!etm_recorder.CheckEtmSupport()) {
      return false;
    }
    ETMRecorder::GetInstance().SetEtmPerfEventAttr(&selection->event_attr);
  }
  bool set_default_sample_freq = false;
  if (!for_stat_cmd_) {
    if (event_type->event_type.type == PERF_TYPE_TRACEPOINT) {
      selection->event_attr.freq = 0;
      selection->event_attr.sample_period = DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT;
    } else if (IsEtmEventType(event_type->event_type.type)) {
      // ETM recording has no sample frequency to adjust. Using sample frequency only wastes time
      // enabling/disabling etm devices. So don't adjust frequency by default.
      selection->event_attr.freq = 0;
      selection->event_attr.sample_period = 1;
    } else {
      selection->event_attr.freq = 1;
      // Set default sample freq here may print msg "Adjust sample freq to max allowed sample
      // freq". But this is misleading. Because default sample freq may not be the final sample
      // freq we use. So use minimum sample freq (1) here.
      selection->event_attr.sample_freq = 1;
      set_default_sample_freq = true;
    }
    // We only need to dump mmap and comm records for the first event type. Because all event types
    // are monitoring the same processes.
    if (first_event) {
      selection->event_attr.mmap = 1;
      selection->event_attr.comm = 1;
      if (IsMmap2Supported()) {
        selection->event_attr.mmap2 = 1;
      }
    }
  }
  // PMU events are provided by kernel, so they should be supported
  if (!event_type->event_type.IsPmuEvent() &&
      !IsEventAttrSupported(selection->event_attr, selection->event_type_modifier.name)) {
    LOG(ERROR) << "Event type '" << event_type->name << "' is not supported on the device";
    return false;
  }
  if (set_default_sample_freq) {
    selection->event_attr.sample_freq = DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT;
  }

  selection->event_fds.clear();

  for (const auto& group : groups_) {
    for (const auto& sel : group) {
      if (sel.event_type_modifier.name == selection->event_type_modifier.name) {
        LOG(ERROR) << "Event type '" << sel.event_type_modifier.name << "' appears more than once";
        return false;
      }
    }
  }
  return true;
}

bool EventSelectionSet::AddEventType(const std::string& event_name, size_t* group_id) {
  return AddEventGroup(std::vector<std::string>(1, event_name), group_id);
}

bool EventSelectionSet::AddEventGroup(const std::vector<std::string>& event_names,
                                      size_t* group_id) {
  EventSelectionGroup group;
  bool first_event = groups_.empty();
  bool first_in_group = true;
  for (const auto& event_name : event_names) {
    EventSelection selection;
    if (!BuildAndCheckEventSelection(event_name, first_event, &selection)) {
      return false;
    }
    if (IsEtmEventType(selection.event_attr.type)) {
      has_aux_trace_ = true;
    }
    if (first_in_group) {
      auto& event_type = selection.event_type_modifier.event_type;
      if (event_type.IsPmuEvent()) {
        selection.allowed_cpus = event_type.GetPmuCpumask();
      }
    }
    first_event = false;
    first_in_group = false;
    group.push_back(std::move(selection));
  }
  groups_.push_back(std::move(group));
  UnionSampleType();
  if (group_id != nullptr) {
    *group_id = groups_.size() - 1;
  }
  return true;
}

bool EventSelectionSet::AddCounters(const std::vector<std::string>& event_names) {
  CHECK(!groups_.empty());
  if (groups_.size() > 1) {
    LOG(ERROR) << "Failed to add counters. Only one event group is allowed.";
    return false;
  }
  for (const auto& event_name : event_names) {
    EventSelection selection;
    if (!BuildAndCheckEventSelection(event_name, false, &selection)) {
      return false;
    }
    // Use a big sample_period to avoid getting samples for added counters.
    selection.event_attr.freq = 0;
    selection.event_attr.sample_period = INFINITE_SAMPLE_PERIOD;
    selection.event_attr.inherit = 0;
    groups_[0].emplace_back(std::move(selection));
  }
  // Add counters in each sample.
  for (auto& selection : groups_[0]) {
    selection.event_attr.sample_type |= PERF_SAMPLE_READ;
    selection.event_attr.read_format |= PERF_FORMAT_GROUP;
  }
  return true;
}

std::vector<const EventType*> EventSelectionSet::GetEvents() const {
  std::vector<const EventType*> result;
  for (const auto& group : groups_) {
    for (const auto& selection : group) {
      result.push_back(&selection.event_type_modifier.event_type);
    }
  }
  return result;
}

std::vector<const EventType*> EventSelectionSet::GetTracepointEvents() const {
  std::vector<const EventType*> result;
  for (const auto& group : groups_) {
    for (const auto& selection : group) {
      if (selection.event_type_modifier.event_type.type == PERF_TYPE_TRACEPOINT) {
        result.push_back(&selection.event_type_modifier.event_type);
      }
    }
  }
  return result;
}

bool EventSelectionSet::ExcludeKernel() const {
  for (const auto& group : groups_) {
    for (const auto& selection : group) {
      if (!selection.event_type_modifier.exclude_kernel) {
        return false;
      }
    }
  }
  return true;
}

std::vector<EventAttrWithId> EventSelectionSet::GetEventAttrWithId() const {
  std::vector<EventAttrWithId> result;
  for (const auto& group : groups_) {
    for (const auto& selection : group) {
      EventAttrWithId attr_id;
      attr_id.attr = &selection.event_attr;
      for (const auto& fd : selection.event_fds) {
        attr_id.ids.push_back(fd->Id());
      }
      result.push_back(attr_id);
    }
  }
  return result;
}

std::unordered_map<uint64_t, std::string> EventSelectionSet::GetEventNamesById() const {
  std::unordered_map<uint64_t, std::string> result;
  for (const auto& group : groups_) {
    for (const auto& selection : group) {
      for (const auto& fd : selection.event_fds) {
        result[fd->Id()] = selection.event_type_modifier.name;
      }
    }
  }
  return result;
}

// Union the sample type of different event attrs can make reading sample
// records in perf.data easier.
void EventSelectionSet::UnionSampleType() {
  uint64_t sample_type = 0;
  for (const auto& group : groups_) {
    for (const auto& selection : group) {
      sample_type |= selection.event_attr.sample_type;
    }
  }
  for (auto& group : groups_) {
    for (auto& selection : group) {
      selection.event_attr.sample_type = sample_type;
    }
  }
}

void EventSelectionSet::SetEnableOnExec(bool enable) {
  for (auto& group : groups_) {
    for (auto& selection : group) {
      // If sampling is enabled on exec, then it is disabled at startup,
      // otherwise it should be enabled at startup. Don't use
      // ioctl(PERF_EVENT_IOC_ENABLE) to enable it after perf_event_open().
      // Because some android kernels can't handle ioctl() well when cpu-hotplug
      // happens. See http://b/25193162.
      if (enable) {
        selection.event_attr.enable_on_exec = 1;
        selection.event_attr.disabled = 1;
      } else {
        selection.event_attr.enable_on_exec = 0;
        selection.event_attr.disabled = 0;
      }
    }
  }
}

bool EventSelectionSet::GetEnableOnExec() {
  for (const auto& group : groups_) {
    for (const auto& selection : group) {
      if (selection.event_attr.enable_on_exec == 0) {
        return false;
      }
    }
  }
  return true;
}

void EventSelectionSet::SampleIdAll() {
  for (auto& group : groups_) {
    for (auto& selection : group) {
      selection.event_attr.sample_id_all = 1;
    }
  }
}

void EventSelectionSet::SetSampleSpeed(size_t group_id, const SampleSpeed& speed) {
  CHECK_LT(group_id, groups_.size());
  for (auto& selection : groups_[group_id]) {
    if (speed.UseFreq()) {
      selection.event_attr.freq = 1;
      selection.event_attr.sample_freq = speed.sample_freq;
    } else {
      selection.event_attr.freq = 0;
      selection.event_attr.sample_period = speed.sample_period;
    }
  }
}

bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) {
  if (branch_sample_type != 0 &&
      (branch_sample_type & (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL |
                             PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) {
    LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex << branch_sample_type;
    return false;
  }
  if (branch_sample_type != 0 && !IsBranchSamplingSupported()) {
    LOG(ERROR) << "branch stack sampling is not supported on this device.";
    return false;
  }
  for (auto& group : groups_) {
    for (auto& selection : group) {
      perf_event_attr& attr = selection.event_attr;
      if (branch_sample_type != 0) {
        attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
      } else {
        attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK;
      }
      attr.branch_sample_type = branch_sample_type;
    }
  }
  return true;
}

void EventSelectionSet::EnableFpCallChainSampling() {
  for (auto& group : groups_) {
    for (auto& selection : group) {
      selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
    }
  }
}

bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) {
  if (!IsDwarfCallChainSamplingSupported()) {
    LOG(ERROR) << "dwarf callchain sampling is not supported on this device.";
    return false;
  }
  for (auto& group : groups_) {
    for (auto& selection : group) {
      selection.event_attr.sample_type |=
          PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
      selection.event_attr.exclude_callchain_user = 1;
      selection.event_attr.sample_regs_user = GetSupportedRegMask(GetMachineArch());
      selection.event_attr.sample_stack_user = dump_stack_size;
    }
  }
  return true;
}

void EventSelectionSet::SetInherit(bool enable) {
  for (auto& group : groups_) {
    for (auto& selection : group) {
      selection.event_attr.inherit = (enable ? 1 : 0);
    }
  }
}

void EventSelectionSet::SetClockId(int clock_id) {
  for (auto& group : groups_) {
    for (auto& selection : group) {
      selection.event_attr.use_clockid = 1;
      selection.event_attr.clockid = clock_id;
    }
  }
}

bool EventSelectionSet::NeedKernelSymbol() const {
  return !ExcludeKernel();
}

void EventSelectionSet::SetRecordNotExecutableMaps(bool record) {
  // We only need to dump non-executable mmap records for the first event type.
  groups_[0][0].event_attr.mmap_data = record ? 1 : 0;
}

bool EventSelectionSet::RecordNotExecutableMaps() const {
  return groups_[0][0].event_attr.mmap_data == 1;
}

void EventSelectionSet::EnableSwitchRecord() {
  groups_[0][0].event_attr.context_switch = 1;
}

void EventSelectionSet::WakeupPerSample() {
  for (auto& group : groups_) {
    for (auto& selection : group) {
      selection.event_attr.watermark = 0;
      selection.event_attr.wakeup_events = 1;
    }
  }
}

bool EventSelectionSet::SetTracepointFilter(const std::string& filter) {
  // 1. Find the tracepoint event to set filter.
  EventSelection* selection = nullptr;
  if (!groups_.empty()) {
    auto& group = groups_.back();
    if (group.size() == 1) {
      if (group[0].event_attr.type == PERF_TYPE_TRACEPOINT) {
        selection = &group[0];
      }
    }
  }
  if (selection == nullptr) {
    LOG(ERROR) << "No tracepoint event before filter: " << filter;
    return false;
  }

  // 2. Check the format of the filter.
  bool use_quote = false;
  // Quotes are needed for string operands in kernel >= 4.19, probably after patch "tracing: Rewrite
  // filter logic to be simpler and faster".
  if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(4, 19)) {
    use_quote = true;
  }

  FieldNameSet used_fields;
  auto adjusted_filter = AdjustTracepointFilter(filter, use_quote, &used_fields);
  if (!adjusted_filter) {
    return false;
  }

  // 3. Check if used fields are available in the tracepoint event.
  auto& event_type = selection->event_type_modifier.event_type;
  if (auto opt_fields = GetFieldNamesForTracepointEvent(event_type); opt_fields) {
    FieldNameSet& fields = opt_fields.value();
    for (const auto& field : used_fields) {
      if (fields.find(field) == fields.end()) {
        LOG(ERROR) << "field name " << field << " used in \"" << filter << "\" doesn't exist in "
                   << event_type.name << ". Available fields are "
                   << android::base::Join(fields, ",");
        return false;
      }
    }
  }

  // 4. Connect the filter to the event.
  selection->tracepoint_filter = adjusted_filter.value();
  return true;
}

static bool CheckIfCpusOnline(const std::vector<int>& cpus) {
  std::vector<int> online_cpus = GetOnlineCpus();
  for (const auto& cpu : cpus) {
    if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == online_cpus.end()) {
      LOG(ERROR) << "cpu " << cpu << " is not online.";
      return false;
    }
  }
  return true;
}

bool EventSelectionSet::OpenEventFilesOnGroup(EventSelectionGroup& group, pid_t tid, int cpu,
                                              std::string* failed_event_type) {
  std::vector<std::unique_ptr<EventFd>> event_fds;
  // Given a tid and cpu, events on the same group should be all opened
  // successfully or all failed to open.
  EventFd* group_fd = nullptr;
  for (auto& selection : group) {
    std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(
        selection.event_attr, tid, cpu, group_fd, selection.event_type_modifier.name, false);
    if (!event_fd) {
      *failed_event_type = selection.event_type_modifier.name;
      return false;
    }
    LOG(VERBOSE) << "OpenEventFile for " << event_fd->Name();
    event_fds.push_back(std::move(event_fd));
    if (group_fd == nullptr) {
      group_fd = event_fds.back().get();
    }
  }
  for (size_t i = 0; i < group.size(); ++i) {
    group[i].event_fds.push_back(std::move(event_fds[i]));
  }
  return true;
}

static std::set<pid_t> PrepareThreads(const std::set<pid_t>& processes,
                                      const std::set<pid_t>& threads) {
  std::set<pid_t> result = threads;
  for (auto& pid : processes) {
    std::vector<pid_t> tids = GetThreadsInProcess(pid);
    result.insert(tids.begin(), tids.end());
  }
  return result;
}

bool EventSelectionSet::OpenEventFiles(const std::vector<int>& cpus) {
  std::vector<int> monitored_cpus;
  if (cpus.empty()) {
    monitored_cpus = GetOnlineCpus();
  } else if (cpus.size() == 1 && cpus[0] == -1) {
    monitored_cpus = {-1};
  } else {
    if (!CheckIfCpusOnline(cpus)) {
      return false;
    }
    monitored_cpus = cpus;
  }
  std::set<pid_t> threads = PrepareThreads(processes_, threads_);
  for (auto& group : groups_) {
    size_t success_count = 0;
    std::string failed_event_type;
    for (const auto tid : threads) {
      const std::vector<int>* pcpus = &monitored_cpus;
      if (!group[0].allowed_cpus.empty()) {
        // override cpu list if event's PMU has a cpumask as those PMUs are
        // agnostic to cpu and it's meaningless to specify cpus for them.
        pcpus = &group[0].allowed_cpus;
      }
      for (const auto& cpu : *pcpus) {
        if (OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) {
          success_count++;
        }
      }
    }
    // We can't guarantee to open perf event file successfully for each thread on each cpu.
    // Because threads may exit between PrepareThreads() and OpenEventFilesOnGroup(), and
    // cpus may be offlined between GetOnlineCpus() and OpenEventFilesOnGroup().
    // So we only check that we can at least monitor one thread for each event group.
    if (success_count == 0) {
      int error_number = errno;
      PLOG(ERROR) << "failed to open perf event file for event_type " << failed_event_type;
      if (error_number == EMFILE) {
        LOG(ERROR) << "Please increase hard limit of open file numbers.";
      }
      return false;
    }
  }
  return ApplyFilters();
}

bool EventSelectionSet::ApplyFilters() {
  return ApplyAddrFilters() && ApplyTracepointFilters();
}

bool EventSelectionSet::ApplyAddrFilters() {
  if (addr_filters_.empty()) {
    return true;
  }
  if (!has_aux_trace_) {
    LOG(ERROR) << "addr filters only take effect in cs-etm instruction tracing";
    return false;
  }

  // Check filter count limit.
  size_t required_etm_filter_count = 0;
  for (auto& filter : addr_filters_) {
    // A range filter needs two etm filters.
    required_etm_filter_count +=
        (filter.type == AddrFilter::FILE_RANGE || filter.type == AddrFilter::KERNEL_RANGE) ? 2 : 1;
  }
  size_t etm_filter_count = ETMRecorder::GetInstance().GetAddrFilterPairs() * 2;
  if (etm_filter_count < required_etm_filter_count) {
    LOG(ERROR) << "needed " << required_etm_filter_count << " etm filters, but only "
               << etm_filter_count << " filters are available.";
    return false;
  }

  std::string filter_str;
  for (auto& filter : addr_filters_) {
    if (!filter_str.empty()) {
      filter_str += ',';
    }
    filter_str += filter.ToString();
  }

  for (auto& group : groups_) {
    for (auto& selection : group) {
      if (IsEtmEventType(selection.event_type_modifier.event_type.type)) {
        for (auto& event_fd : selection.event_fds) {
          if (!event_fd->SetFilter(filter_str)) {
            return false;
          }
        }
      }
    }
  }
  return true;
}

bool EventSelectionSet::ApplyTracepointFilters() {
  for (auto& group : groups_) {
    for (auto& selection : group) {
      if (!selection.tracepoint_filter.empty()) {
        for (auto& event_fd : selection.event_fds) {
          if (!event_fd->SetFilter(selection.tracepoint_filter)) {
            return false;
          }
        }
      }
    }
  }
  return true;
}

static bool ReadCounter(EventFd* event_fd, CounterInfo* counter) {
  if (!event_fd->ReadCounter(&counter->counter)) {
    return false;
  }
  counter->tid = event_fd->ThreadId();
  counter->cpu = event_fd->Cpu();
  return true;
}

bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
  counters->clear();
  for (size_t i = 0; i < groups_.size(); ++i) {
    for (auto& selection : groups_[i]) {
      CountersInfo counters_info;
      counters_info.group_id = i;
      counters_info.event_name = selection.event_type_modifier.event_type.name;
      counters_info.event_modifier = selection.event_type_modifier.modifier;
      counters_info.counters = selection.hotplugged_counters;
      for (auto& event_fd : selection.event_fds) {
        CounterInfo counter;
        if (!ReadCounter(event_fd.get(), &counter)) {
          return false;
        }
        counters_info.counters.push_back(counter);
      }
      counters->push_back(counters_info);
    }
  }
  return true;
}

bool EventSelectionSet::MmapEventFiles(size_t min_mmap_pages, size_t max_mmap_pages,
                                       size_t aux_buffer_size, size_t record_buffer_size,
                                       bool allow_cutting_samples, bool exclude_perf) {
  record_read_thread_.reset(new simpleperf::RecordReadThread(
      record_buffer_size, groups_[0][0].event_attr, min_mmap_pages, max_mmap_pages, aux_buffer_size,
      allow_cutting_samples, exclude_perf));
  return true;
}

bool EventSelectionSet::PrepareToReadMmapEventData(const std::function<bool(Record*)>& callback) {
  // Prepare record callback function.
  record_callback_ = callback;
  if (!record_read_thread_->RegisterDataCallback(*loop_,
                                                 [this]() { return ReadMmapEventData(true); })) {
    return false;
  }
  std::vector<EventFd*> event_fds;
  for (auto& group : groups_) {
    for (auto& selection : group) {
      for (auto& event_fd : selection.event_fds) {
        event_fds.push_back(event_fd.get());
      }
    }
  }
  return record_read_thread_->AddEventFds(event_fds);
}

bool EventSelectionSet::SyncKernelBuffer() {
  return record_read_thread_->SyncKernelBuffer();
}

// Read records from the RecordBuffer. If with_time_limit is false, read until the RecordBuffer is
// empty, otherwise stop after 100 ms or when the record buffer is empty.
bool EventSelectionSet::ReadMmapEventData(bool with_time_limit) {
  uint64_t start_time_in_ns;
  if (with_time_limit) {
    start_time_in_ns = GetSystemClock();
  }
  std::unique_ptr<Record> r;
  while ((r = record_read_thread_->GetRecord()) != nullptr) {
    if (!record_callback_(r.get())) {
      return false;
    }
    if (with_time_limit && (GetSystemClock() - start_time_in_ns) >= 1e8) {
      break;
    }
  }
  return true;
}

bool EventSelectionSet::FinishReadMmapEventData() {
  // Stop the read thread, so we don't get more records beyond current time.
  if (!SyncKernelBuffer() || !record_read_thread_->StopReadThread()) {
    return false;
  }
  if (!ReadMmapEventData(false)) {
    return false;
  }
  return true;
}

void EventSelectionSet::CloseEventFiles() {
  if (record_read_thread_) {
    record_read_thread_->StopReadThread();
  }
  for (auto& group : groups_) {
    for (auto& event : group) {
      event.event_fds.clear();
    }
  }
}

bool EventSelectionSet::StopWhenNoMoreTargets(double check_interval_in_sec) {
  return loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
                                 [&]() { return CheckMonitoredTargets(); });
}

bool EventSelectionSet::CheckMonitoredTargets() {
  if (!HasSampler()) {
    return loop_->ExitLoop();
  }
  for (const auto& tid : threads_) {
    if (IsThreadAlive(tid)) {
      return true;
    }
  }
  for (const auto& pid : processes_) {
    if (IsThreadAlive(pid)) {
      return true;
    }
  }
  return loop_->ExitLoop();
}

bool EventSelectionSet::HasSampler() {
  for (auto& group : groups_) {
    for (auto& sel : group) {
      if (!sel.event_fds.empty()) {
        return true;
      }
    }
  }
  return false;
}

bool EventSelectionSet::SetEnableEvents(bool enable) {
  for (auto& group : groups_) {
    for (auto& sel : group) {
      for (auto& fd : sel.event_fds) {
        if (!fd->SetEnableEvent(enable)) {
          return false;
        }
      }
    }
  }
  return true;
}

}  // namespace simpleperf
