blob: 2f63f787594499f2df697914d4293c8d51fe462c [file] [log] [blame]
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_COMPILER_COMPILER_TIMINGS_H_
#define RUNTIME_VM_COMPILER_COMPILER_TIMINGS_H_
#include <memory>
#include "platform/allocation.h"
#include "vm/compiler/compiler_pass.h"
#include "vm/thread.h"
#include "vm/timer.h"
#if defined(DART_PRECOMPILED_RUNTIME)
#error "AOT runtime should not use compiler sources (including header files)"
#endif // defined(DART_PRECOMPILED_RUNTIME)
#define PRECOMPILER_TIMERS_LIST(V) \
V(CompileAll) \
V(Iterate) \
V(CompileFunction) \
V(AddCalleesOf) \
V(CheckForNewDynamicFunctions) \
V(CollectCallbackFields) \
V(PrecompileConstructors) \
V(AttachOptimizedTypeTestingStub) \
V(TraceForRetainedFunctions) \
V(FinalizeDispatchTable) \
V(ReplaceFunctionStaticCallEntries) \
V(Drop) \
V(Obfuscate) \
V(Dedup) \
V(SymbolsCompact)
#define INLINING_TIMERS_LIST(V) \
V(CollectGraphInfo) \
V(PopulateWithICData) \
V(FindCallSites) \
V(SetInliningId) \
V(MakeInliningDecision) \
V(CheckForPragma) \
V(InlineCall) \
V(InlineRecognizedMethod) \
V(DiscoverBlocks) \
V(BuildDecisionGraph) \
V(PrepareGraphs)
// Note: COMPILER_PASS_LIST must be the first element of the list below because
// we expect that pass ids are the same as ids of corresponding timers.
#define COMPILER_TIMERS_LIST(V) \
COMPILER_PASS_LIST(V) \
PRECOMPILER_TIMERS_LIST(V) \
INLINING_TIMERS_LIST(V) \
V(BuildGraph) \
V(EmitCode) \
V(FinalizeCode)
namespace dart {
// |CompilerTimings| provides a way to track time taken by various compiler
// passes via a fixed number of timers (specified in |COMPILER_TIMERS_LIST|).
//
// It supports arbitrary nesting of timers e.g. if |DiscoverBlocks| is invoked
// within two different compiler passes like |IfConvert| and |BranchSimplify|
// then |CompilerTimings| will separate these two invocations and measure each
// separately.
class CompilerTimings : public MallocAllocated {
private:
#define INC(Name) +1
static constexpr intptr_t kNumTimers = 0 COMPILER_TIMERS_LIST(INC);
#undef INC
struct Timers : public MallocAllocated {
Timer timers_[kNumTimers];
std::unique_ptr<Timers> nested_[kNumTimers];
};
public:
enum TimerId {
#define DECLARE_TIMER_ID(Name) k##Name,
COMPILER_TIMERS_LIST(DECLARE_TIMER_ID)
#undef DECLARE_TIMER_ID
};
// Timing scope which starts and stop the timer with the given |id|.
class Scope : public StackResource {
public:
Scope(Thread* thread, TimerId id)
: StackResource(thread), stats_(thread->compiler_timings()) {
if (stats_ != nullptr) {
outer_nested_ = stats_->nested_;
if (*outer_nested_ == nullptr) {
// Created array of nested timers if we don't have one yet.
*outer_nested_ = std::make_unique<Timers>();
}
timer_ = &(*outer_nested_)->timers_[id];
stats_->nested_ = &(*outer_nested_)->nested_[id];
timer_->Start();
}
}
~Scope() {
if (stats_ != nullptr) {
timer_->Stop();
stats_->nested_ = outer_nested_;
}
}
private:
CompilerTimings* const stats_;
Timer* timer_;
std::unique_ptr<Timers>* outer_nested_;
};
CompilerTimings() { total_.Start(); }
void RecordInliningStatsByOutcome(bool success, const Timer& timer) {
if (success) {
try_inlining_success_.AddTotal(timer);
} else {
try_inlining_failure_.AddTotal(timer);
}
}
void Print();
private:
void PrintTimers(Zone* zone,
const std::unique_ptr<CompilerTimings::Timers>& timers,
const Timer& total,
intptr_t level);
Timer total_;
std::unique_ptr<Timers> root_ = std::make_unique<Timers>();
// Timers nested under the currently running timer(s).
std::unique_ptr<Timers>* nested_ = &root_;
Timer try_inlining_success_;
Timer try_inlining_failure_;
};
#define TIMER_SCOPE_NAME2(counter) timer_scope_##counter
#define TIMER_SCOPE_NAME(counter) TIMER_SCOPE_NAME2(counter)
#define COMPILER_TIMINGS_TIMER_SCOPE(thread, timer_id) \
CompilerTimings::Scope TIMER_SCOPE_NAME(__COUNTER__)( \
thread, CompilerTimings::k##timer_id)
#define COMPILER_TIMINGS_PASS_TIMER_SCOPE(thread, pass_id) \
CompilerTimings::Scope TIMER_SCOPE_NAME(__COUNTER__)( \
thread, static_cast<CompilerTimings::TimerId>(pass_id))
#define PRECOMPILER_TIMER_SCOPE(precompiler, timer_id) \
CompilerTimings::Scope TIMER_SCOPE_NAME(__COUNTER__)( \
(precompiler)->thread(), CompilerTimings::k##timer_id)
} // namespace dart
#endif // RUNTIME_VM_COMPILER_COMPILER_TIMINGS_H_