| // Copyright 2022 The Fuchsia Authors |
| // |
| // Use of this source code is governed by a MIT-style |
| // license that can be found in the LICENSE file or at |
| // https://opensource.org/licenses/MIT |
| |
| #ifndef ZIRCON_KERNEL_INCLUDE_KERNEL_SPIN_TRACING_H_ |
| #define ZIRCON_KERNEL_INCLUDE_KERNEL_SPIN_TRACING_H_ |
| |
| #include <lib/ktrace.h> |
| |
| #include <fbl/bits.h> |
| #include <kernel/spin_tracing_config.h> |
| |
| namespace spin_tracing { |
| |
| template <bool Enabled = kSchedulerLockSpinTracingEnabled> |
| class SpinTracingTimestamp; |
| |
| template <> |
| class SpinTracingTimestamp<false> { |
| public: |
| constexpr SpinTracingTimestamp() = default; |
| constexpr uint64_t value() const { return 0; } |
| }; |
| |
| template <> |
| class SpinTracingTimestamp<true> { |
| public: |
| SpinTracingTimestamp() = default; |
| uint64_t value() const { return value_; } |
| |
| private: |
| const uint64_t value_{ktrace_timestamp()}; |
| }; |
| |
| template <bool TraceInstrumented = false> |
| class Tracer { |
| public: |
| constexpr Tracer() = default; |
| constexpr explicit Tracer(zx_ticks_t) {} |
| constexpr void Finish(FinishType, EncodedLockId, |
| SpinTracingTimestamp<false> = SpinTracingTimestamp<false>{}) const {} |
| }; |
| |
| template <> |
| class Tracer<true> { |
| public: |
| Tracer() = default; |
| explicit constexpr Tracer(zx_ticks_t ticks) : start_{static_cast<uint64_t>(ticks)} {} |
| |
| void Finish(FinishType finish_type, EncodedLockId elid, |
| SpinTracingTimestamp<true> end_time = SpinTracingTimestamp<true>{}) const { |
| const uint16_t class_name = static_cast<uint16_t>( |
| (elid.class_name() != fxt::InternedString::kInvalidId) ? elid.class_name() |
| : "<unknown>"_intern.GetId()); |
| |
| if constexpr (!kSchedulerLockSpinTracingCompressed) { |
| const uint64_t lock_id = elid.id(); |
| const auto& lock_type = |
| elid.lock_type() == LockType::kSpinlock ? "Spinlock"_intern : "Mutex"_intern; |
| const bool blocked_after = (finish_type == FinishType::kBlocked); |
| |
| FXT_EVENT_COMMON(true, ktrace_category_enabled, ktrace::EmitComplete, "kernel:sched", |
| "lock_spin"_intern, start_, end_time.value(), TraceContext::Thread, |
| ("lock_id", lock_id), |
| ("lock_class", fxt::StringRef<fxt::RefType::kId>{class_name}), |
| ("lock_type", lock_type), ("blocked_after", blocked_after)); |
| } else { |
| // TODO(johngro): We could compress this even more if we omitted the |
| // dedicated lock_class field (we can extract the value from the elid |
| // instead). To do this, I need to update my external scripts to process |
| // the native FXT format. Currently, it depends on conversion to JSON |
| // before processing, which strips the string table from the data |
| // (embedding it directly into the JSON instead). |
| FXT_EVENT_COMMON(true, ktrace_category_enabled, ktrace::EmitComplete, "kernel:sched", |
| "lock_spin"_intern, start_, end_time.value(), TraceContext::Thread, |
| ("lock_class", fxt::StringRef<fxt::RefType::kId>{class_name}), |
| ("elid", elid.FinishedValue(finish_type))); |
| } |
| } |
| |
| private: |
| uint64_t start_ = ktrace_timestamp(); |
| }; |
| |
| } // namespace spin_tracing |
| |
| #endif // ZIRCON_KERNEL_INCLUDE_KERNEL_SPIN_TRACING_H_ |