// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef GARNET_LIB_PERFMON_CONFIG_H_
#define GARNET_LIB_PERFMON_CONFIG_H_

#include <functional>
#include <stdint.h>
#include <string>
#include <unordered_set>

#include <lib/zircon-internal/device/cpu-trace/perf-mon.h>

#include "garnet/lib/perfmon/types.h"

namespace perfmon {

// Description of what data to collect in a trace run.
// This is internally basically a copy of the FIDL struct, kept separate and
// filled in programmatically to not pass a FIDL dependency on to our clients.
class Config {
 public:
  // Data for one event. Passed to |IterateFunc|.
  struct EventConfig {
    // Event to collect data for.
    // The values are architecture specific ids.
    EventId event;

    // Sampling rate.
    // - If rate is non-zero then when the event gets this many hits data is
    //   collected (e.g., pc, time).
    //   The rate can be non-zero for counting based events only.
    // - If rate is zero then:
    //     If there is a timebase event then data for this event is collected
    //     when data for the timebase event is collected.
    //     Otherwise data for the event is collected once, when tracing stops.
    EventRate rate;

    // Flags for each event in |events|.
    // The values are |Config::kFlag*|.
    uint32_t flags;
  };

  // Callback for |IterateOverEvents()|.
  using IterateFunc = std::function<void(const EventConfig& event)>;

  // Bits for event flags.
  // TODO(dje): hypervisor, host/guest os/user
  static constexpr uint32_t kFlagMask = 0x1f;

  // Collect os data.
  // If neither |kFlagOs,KflagPc| are specified then both are collected.
  static constexpr uint32_t kFlagOs   = 0x1;

  // Collect userspace data.
  // If neither |kFlagOs,KflagPc| are specified then both are collected.
  static constexpr uint32_t kFlagUser = 0x2;

  // Collect aspace+pc values.
  static constexpr uint32_t kFlagPc   = 0x4;

  // If set then this event is used as the "timebase": data for events that
  // aren't their own time base is collected when data for this event is
  // collected. Events that are their own timebase have a non-zero rate.
  // It is an error to have this set and have the rate be zero.
  // There can be only one "timebase" event.
  static constexpr uint32_t kFlagTimebase = 0x8;

  // Collect the available set of last branches.
  // Branch data is emitted as PERFMON_RECORD_LAST_BRANCH records.
  // This is only available when the underlying system supports it.
  // TODO(dje): Provide knob to specify how many branches.
  static constexpr uint32_t kFlagLastBranch = 0x10;

  // These flags may only be specified with a non-zero rate.
  static constexpr uint32_t kNonZeroRateOnlyFlags =
    kFlagPc + kFlagLastBranch + kFlagTimebase;

  enum class Status {
    OK,
    // An invalid argument of some kind.
    INVALID_ARGS,
    // No room for more events.
    MAX_EVENTS,
  };

  static std::string StatusToString(Status status);

  Config() = default;
  ~Config() = default;

  // Use the default default copy/move constructors.

  // Remove existing contents.
  void Reset();

  // Collect data for event |event|.
  // If |rate| is zero then |flags| may only contain |kFlagOs,kFlagUser|.
  // If |rate| is non-zero then |flags| may contain any valid combination.
  // If |flags| contains |kFlagTimebase| then events with a zero rate are
  // collected at the same time as this event. Only one event may be added with
  // |kFlagTimebase|.
  // A value of zero for |flags| is equivalent to |kFlagOs|kFlagUser|.
  Status AddEvent(EventId event, EventRate rate, uint32_t flags);

  // Return the number of events.
  size_t GetEventCount() const;

  // Return the "mode" of data collection.
  CollectionMode GetMode() const;

  // Call |func| for each event.
  // The iteration order is unspecified.
  void IterateOverEvents(IterateFunc func) const;

  // Return a string form of the configuration, for display purposes.
  // The order of appearance of events in the string is unspecified.
  std::string ToString();

 private:
  struct EventHash {
    inline std::size_t operator()(const EventConfig& event) const {
      return event.event;
    }
  };
  struct EventEqual {
    inline bool operator()(const EventConfig& e1, const EventConfig& e2) const {
      return e1.event == e2.event;
    }
  };

  // Each event may appear at most once.
  std::unordered_set<EventConfig, EventHash, EventEqual> events_;
};

}  // namespace perfmon

#endif  // GARNET_LIB_PERFMON_CONFIG_H_
