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