// Copyright 2017 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.

#include "garnet/lib/measure/duration.h"

#include "src/lib/fxl/logging.h"

namespace tracing {
namespace measure {

MeasureDuration::MeasureDuration(std::vector<DurationSpec> specs)
    : specs_(std::move(specs)) {}

bool MeasureDuration::Process(const trace::Record::Event& event) {
  switch (event.type()) {
    case trace::EventType::kAsyncBegin:
    case trace::EventType::kFlowBegin:
      return ProcessAsyncOrFlowBegin(event);
    case trace::EventType::kAsyncEnd:
    case trace::EventType::kFlowEnd:
      return ProcessAsyncOrFlowEnd(event);
    case trace::EventType::kDurationBegin:
      return ProcessDurationBegin(event);
    case trace::EventType::kDurationEnd:
      return ProcessDurationEnd(event);
    case trace::EventType::kDurationComplete:
      return ProcessDurationComplete(event);
    default:
      return true;
  }
}

MeasureDuration::PendingBeginKey MeasureDuration::MakeKey(
    const trace::Record::Event& event) {
  PendingBeginKey key;
  key.category = event.category;
  key.name = event.name;
  switch (event.type()) {
    case trace::EventType::kAsyncBegin:
      key.type = PendingBeginKey::Type::Async;
      key.id = event.data.GetAsyncBegin().id;
      break;
    case trace::EventType::kAsyncEnd:
      key.type = PendingBeginKey::Type::Async;
      key.id = event.data.GetAsyncEnd().id;
      break;
    case trace::EventType::kFlowBegin:
      key.type = PendingBeginKey::Type::Flow;
      key.id = event.data.GetFlowBegin().id;
      break;
    case trace::EventType::kFlowEnd:
      key.type = PendingBeginKey::Type::Flow;
      key.id = event.data.GetFlowEnd().id;
      break;
    default:
      FXL_NOTREACHED();
  }
  return key;
}

bool MeasureDuration::ProcessAsyncOrFlowBegin(
    const trace::Record::Event& event) {
  const PendingBeginKey key = MakeKey(event);
  if (pending_begins_.count(key)) {
    FXL_LOG(WARNING)
        << "Ignoring a trace event: duplicate async or flow begin event";
    return false;
  }
  pending_begins_[key] = event.timestamp;
  return true;
}

bool MeasureDuration::ProcessAsyncOrFlowEnd(const trace::Record::Event& event) {
  const PendingBeginKey key = MakeKey(event);
  if (pending_begins_.count(key) == 0) {
    FXL_LOG(WARNING)
        << "Ignoring a trace event: async or flow end not preceded by begin.";
    return false;
  }

  const auto begin_timestamp = pending_begins_[key];
  pending_begins_.erase(key);
  for (const DurationSpec& spec : specs_) {
    if (!EventMatchesSpec(event, spec.event)) {
      continue;
    }

    AddResult(spec.common.id, begin_timestamp, event.timestamp);
  }
  return true;
}

bool MeasureDuration::ProcessDurationBegin(const trace::Record::Event& event) {
  FXL_DCHECK(event.type() == trace::EventType::kDurationBegin);
  duration_stacks_[event.process_thread].push(event.timestamp);
  return true;
}

bool MeasureDuration::ProcessDurationEnd(const trace::Record::Event& event) {
  FXL_DCHECK(event.type() == trace::EventType::kDurationEnd);
  const auto key = event.process_thread;
  if (duration_stacks_.count(key) == 0 || duration_stacks_[key].empty()) {
    FXL_LOG(WARNING)
        << "Ignoring trace event " << event.category.c_str() << ":"
        << event.name.c_str() << " @" << event.timestamp
        << ": duration end not matched by a previous duration begin.";
    return false;
  }

  const auto begin_timestamp = duration_stacks_[key].top();
  duration_stacks_[key].pop();
  if (duration_stacks_[key].empty()) {
    duration_stacks_.erase(key);
  }

  for (const DurationSpec& spec : specs_) {
    if (!EventMatchesSpec(event, spec.event)) {
      continue;
    }
    AddResult(spec.common.id, begin_timestamp, event.timestamp);
  }
  return true;
}

bool MeasureDuration::ProcessDurationComplete(
    const trace::Record::Event& event) {
  FXL_DCHECK(event.type() == trace::EventType::kDurationComplete);
  for (const DurationSpec& spec : specs_) {
    if (!EventMatchesSpec(event, spec.event)) {
      continue;
    }
    AddResult(spec.common.id, event.timestamp,
              event.data.GetDurationComplete().end_time);
  }
  return true;
}

void MeasureDuration::AddResult(uint64_t spec_id, trace_ticks_t from,
                                trace_ticks_t to) {
  results_[spec_id].push_back(to - from);
}

bool MeasureDuration::PendingBeginKey::operator<(
    const PendingBeginKey& other) const {
  if (type != other.type) {
    return type < other.type;
  }
  if (category != other.category) {
    return category < other.category;
  }
  if (name != other.name) {
    return name < other.name;
  }
  return id < other.id;
}

}  // namespace measure
}  // namespace tracing
