diff --git a/zircon/kernel/arch/arm64/perf_mon.cpp b/zircon/kernel/arch/arm64/perf_mon.cpp index 6cfb24bb227940c6538bb697ee85296d03d2cbcd..b52a9f58bee01275971290615f1c408855fb8509 100644 --- a/zircon/kernel/arch/arm64/perf_mon.cpp +++ b/zircon/kernel/arch/arm64/perf_mon.cpp @@ -762,17 +762,18 @@ static void arm64_perfmon_stop_task(void* raw_context) TA_NO_THREAD_SAFETY_ANALY arm64_perfmon_clear_overflow_indicators(); } -// Stop collecting data. -// It's ok to call this multiple times. -// Returns an error if called before ALLOC or after FREE. -zx_status_t arch_perfmon_stop() { - Guard<Mutex> guard(PerfmonLock::Get()); - +void arch_perfmon_stop_locked() TA_REQ(PerfmonLock::Get()) { if (!perfmon_supported) { - return ZX_ERR_NOT_SUPPORTED; + // Nothing to do. + return; } if (!perfmon_state) { - return ZX_ERR_BAD_STATE; + // Nothing to do. + return; + } + if (!atomic_load(&perfmon_active)) { + // Nothing to do. + return; } TRACEF("Disabling perfmon\n"); @@ -791,8 +792,12 @@ zx_status_t arch_perfmon_stop() { // Make sure to do this after we've turned everything off so that we // don't get another PMI after this. arm64_perfmon_unmap_buffers_locked(state); +} - return ZX_OK; +// Stop collecting data. +void arch_perfmon_stop() { + Guard<Mutex> guard(PerfmonLock::Get()); + arch_perfmon_stop_locked(); } // Worker for arm64_perfmon_fini to be executed on all cpus. @@ -821,22 +826,22 @@ static void arm64_perfmon_reset_task(void* raw_context) TA_NO_THREAD_SAFETY_ANAL // Finish data collection, reset h/w back to initial state and undo // everything arm64_perfmon_init did. -// Must be called while tracing is stopped. -// It's ok to call this multiple times. -zx_status_t arch_perfmon_fini() { +void arch_perfmon_fini() { Guard<Mutex> guard(PerfmonLock::Get()); if (!perfmon_supported) { - return ZX_ERR_NOT_SUPPORTED; + // Nothing to do. + return; } + if (atomic_load(&perfmon_active)) { - return ZX_ERR_BAD_STATE; + arch_perfmon_stop_locked(); + DEBUG_ASSERT(!atomic_load(&perfmon_active)); } mp_sync_exec(MP_IPI_TARGET_ALL, 0, arm64_perfmon_reset_task, nullptr); perfmon_state.reset(); - return ZX_OK; } // Interrupt handling. diff --git a/zircon/kernel/arch/x86/perf_mon.cpp b/zircon/kernel/arch/x86/perf_mon.cpp index e30c31f9ff902f49bf638563d0536fd1276fb16c..307bae00d7957932c1e3d26305acdf28588b5c9a 100644 --- a/zircon/kernel/arch/x86/perf_mon.cpp +++ b/zircon/kernel/arch/x86/perf_mon.cpp @@ -1673,16 +1673,19 @@ static void x86_perfmon_stop_cpu_task(void* raw_context) TA_NO_THREAD_SAFETY_ANA x86_perfmon_clear_overflow_indicators(); } -// Stop collecting data. -// It's ok to call this multiple times. -// Returns an error if called before ALLOC or after FREE. -zx_status_t arch_perfmon_stop() { - Guard<Mutex> guard(PerfmonLock::Get()); - - if (!perfmon_supported) - return ZX_ERR_NOT_SUPPORTED; - if (!perfmon_state) - return ZX_ERR_BAD_STATE; +void arch_perfmon_stop_locked() TA_REQ(PerfmonLock::Get()) { + if (!perfmon_supported) { + // Nothing to do. + return; + } + if (!perfmon_state) { + // Nothing to do. + return; + } + if (!atomic_load(&perfmon_active)) { + // Nothing to do. + return; + } TRACEF("Disabling perfmon\n"); @@ -1700,8 +1703,12 @@ zx_status_t arch_perfmon_stop() { // Make sure to do this after we've turned everything off so that we // don't get another PMI after this. x86_perfmon_unmap_buffers_locked(state); +} - return ZX_OK; +// Stop collecting data. +void arch_perfmon_stop() { + Guard<Mutex> guard(PerfmonLock::Get()); + arch_perfmon_stop_locked(); } // Worker for x86_perfmon_fini to be executed on all cpus. @@ -1730,21 +1737,22 @@ static void x86_perfmon_reset_task(void* raw_context) TA_NO_THREAD_SAFETY_ANALYS // Finish data collection, reset h/w back to initial state and undo // everything x86_perfmon_init did. -// Must be called while tracing is stopped. -// It's ok to call this multiple times. -zx_status_t arch_perfmon_fini() { +void arch_perfmon_fini() { Guard<Mutex> guard(PerfmonLock::Get()); - if (!perfmon_supported) - return ZX_ERR_NOT_SUPPORTED; - if (atomic_load(&perfmon_active)) - return ZX_ERR_BAD_STATE; + if (!perfmon_supported) { + // Nothing to do. + return; + } + + if (atomic_load(&perfmon_active)) { + arch_perfmon_stop_locked(); + DEBUG_ASSERT(!atomic_load(&perfmon_active)); + } mp_sync_exec(MP_IPI_TARGET_ALL, 0, x86_perfmon_reset_task, nullptr); perfmon_state.reset(); - - return ZX_OK; } // Interrupt handling. diff --git a/zircon/kernel/lib/mtrace/mtrace-pmu.cpp b/zircon/kernel/lib/mtrace/mtrace-pmu.cpp index e0624ce6c478fb4d17792c4021efdcd30e0520fd..490c72864f57f16e311b8b480e90bfae7ecb72f1 100644 --- a/zircon/kernel/lib/mtrace/mtrace-pmu.cpp +++ b/zircon/kernel/lib/mtrace/mtrace-pmu.cpp @@ -95,12 +95,14 @@ zx_status_t mtrace_perfmon_control(uint32_t action, uint32_t options, case MTRACE_PERFMON_STOP: if (options != 0 || size != 0) return ZX_ERR_INVALID_ARGS; - return arch_perfmon_stop(); + arch_perfmon_stop(); + return ZX_OK; case MTRACE_PERFMON_FINI: if (options != 0 || size != 0) return ZX_ERR_INVALID_ARGS; - return arch_perfmon_fini(); + arch_perfmon_fini(); + return ZX_OK; default: return ZX_ERR_INVALID_ARGS; diff --git a/zircon/kernel/lib/perfmon/include/lib/perfmon.h b/zircon/kernel/lib/perfmon/include/lib/perfmon.h index b627026816ed4b637db59eed42a421eef48a9d64..605cadb1cd0dfcd19ebc2462c07fe7e5bb8b8366 100644 --- a/zircon/kernel/lib/perfmon/include/lib/perfmon.h +++ b/zircon/kernel/lib/perfmon/include/lib/perfmon.h @@ -83,11 +83,13 @@ zx_status_t arch_perfmon_start(); // Perform MTRACE_PERFMON_STOP: Stop data collection, including collecting // the final values of the counters and unmapping the VMOs. -zx_status_t arch_perfmon_stop(); +// It's ok to call this multiple times. +void arch_perfmon_stop(); // Perform MTRACE_PERFMON_FINI: Terminate data collection, reset all PMU -// registers. -zx_status_t arch_perfmon_fini(); +// registers. Data collection is stopped first if necessary. +// It's ok to call this multiple times. +void arch_perfmon_fini(); // This section contains helper routines to write perfmon records. diff --git a/zircon/system/dev/misc/cpu-trace/perf-mon.cpp b/zircon/system/dev/misc/cpu-trace/perf-mon.cpp index 7a4124295aa6dcb2494bdf38fb9f051eb4bbbb05..2d5218701aebd749820aa72a9a20b4f23a457b33 100644 --- a/zircon/system/dev/misc/cpu-trace/perf-mon.cpp +++ b/zircon/system/dev/misc/cpu-trace/perf-mon.cpp @@ -516,36 +516,32 @@ zx_status_t PerfmonDevice::PmuStart() { fail: { - zx_status_t status2 = + [[maybe_unused]] zx_status_t status2 = zx_mtrace_control(resource, MTRACE_KIND_PERFMON, MTRACE_PERFMON_FINI, 0, nullptr, 0); - if (status2 != ZX_OK) { - zxlogf(TRACE, "%s: MTRACE_PERFMON_FINI failed: %d\n", __func__, status2); - } assert(status2 == ZX_OK); return status; } } -zx_status_t PerfmonDevice::PmuStop() { +void PerfmonDevice::PmuStop() { zxlogf(TRACE, "%s called\n", __func__); PmuPerTraceState* per_trace = per_trace_state_.get(); if (!per_trace) { - return ZX_ERR_BAD_STATE; + return; } // Please do not use get_root_resource() in new code. See ZX-1467. zx_handle_t resource = get_root_resource(); - zx_status_t status = + [[maybe_unused]] zx_status_t status = zx_mtrace_control(resource, MTRACE_KIND_PERFMON, MTRACE_PERFMON_STOP, 0, nullptr, 0); - if (status == ZX_OK) { - active_ = false; - status = zx_mtrace_control(resource, MTRACE_KIND_PERFMON, - MTRACE_PERFMON_FINI, 0, nullptr, 0); - } - return status; + assert(status == ZX_OK); + active_ = false; + status = zx_mtrace_control(resource, MTRACE_KIND_PERFMON, + MTRACE_PERFMON_FINI, 0, nullptr, 0); + assert(status == ZX_OK); } // Dispatch the various kinds of requests. @@ -603,7 +599,8 @@ zx_status_t PerfmonDevice::IoctlWorker(uint32_t op, if (cmdlen != 0 || replymax != 0) { return ZX_ERR_INVALID_ARGS; } - return PmuStop(); + PmuStop(); + return ZX_OK; default: return ZX_ERR_INVALID_ARGS; diff --git a/zircon/system/dev/misc/cpu-trace/perf-mon.h b/zircon/system/dev/misc/cpu-trace/perf-mon.h index e761c3dfcd868bc280222aa53ca709d6e15b68ce..1c7d8c56375235a1b26dac4ea02b9eb6bc146754 100644 --- a/zircon/system/dev/misc/cpu-trace/perf-mon.h +++ b/zircon/system/dev/misc/cpu-trace/perf-mon.h @@ -143,7 +143,7 @@ class PerfmonDevice : public DeviceType { zx_status_t PmuStageConfig(const void* cmd, size_t cmdlen); zx_status_t PmuGetConfig(void* reply, size_t replymax, size_t* out_actual); zx_status_t PmuStart(); - zx_status_t PmuStop(); + void PmuStop(); zx_status_t IoctlWorker(uint32_t op, const void* cmd, size_t cmdlen, void* reply, size_t replymax, size_t* out_actual);