//===--- Tracing.h - Support code for runtime tracing --------------*- C++ -*-// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // Support code for tracing events in the Swift runtime // //===----------------------------------------------------------------------===// #ifndef SWIFT_TRACING_H #define SWIFT_TRACING_H #include "llvm/ADT/StringRef.h" #include "swift/ABI/Metadata.h" #include "swift/Demangling/Demangler.h" #include "swift/Runtime/TracingCommon.h" #if SWIFT_STDLIB_TRACING #include #include "swift/Runtime/HeapObject.h" #define SWIFT_LOG_SECTION_SCAN "section_scan" namespace swift { namespace runtime { namespace trace { extern os_log_t ScanLog; extern swift::once_t LogsToken; extern bool TracingEnabled; void setupLogs(void *unused); // Every function does ENSURE_LOGS() before making any os_signpost calls, so // we can skip availability checking on all the individual calls. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunguarded-availability" #pragma clang diagnostic ignored "-Wunguarded-availability-new" // Check a representative os_signpost function for NULL rather than doing a // standard availability check, for better performance if the check doesn't get // optimized out. #define ENSURE_LOG(log) \ do { \ if (!tracingReady()) \ return {}; \ swift::once(LogsToken, setupLogs, nullptr); \ if (!TracingEnabled) \ return {}; \ } while (0) /// A struct that captures the state of a scan tracing signpost. When the scan /// is complete, call end() with the result of the scan. If the state struct /// goes out of scope without calling end(), then it will automatically do the /// equivalent of end(nullptr). struct ScanTraceState { os_signpost_id_t signpostID; bool ended = false; template T *end(T *result) { ended = true; os_signpost_interval_end(ScanLog, signpostID, SWIFT_LOG_SECTION_SCAN, "result=%p", result); return result; } ~ScanTraceState() { if (!ended) end((void *)nullptr); } }; static inline ScanTraceState accessible_function_scan_begin(llvm::StringRef name) { ENSURE_LOG(ScanLog); auto id = os_signpost_id_generate(ScanLog); os_signpost_interval_begin(ScanLog, id, SWIFT_LOG_SECTION_SCAN, "accessible function scan for '%.*s'", (int)name.size(), name.data()); return {id}; } static inline ScanTraceState metadata_scan_begin(Demangle::NodePointer node) { ENSURE_LOG(ScanLog); auto id = os_signpost_id_generate(ScanLog); os_signpost_interval_begin(ScanLog, id, SWIFT_LOG_SECTION_SCAN, "metadata scan for %s", node ? nodeToString(node).c_str() : ""); return {id}; } static inline ScanTraceState protocol_conformance_scan_begin(Demangle::NodePointer node) { ENSURE_LOG(ScanLog); auto id = os_signpost_id_generate(ScanLog); os_signpost_interval_begin(ScanLog, id, SWIFT_LOG_SECTION_SCAN, "protocol conformance scan for %s", node ? nodeToString(node).c_str() : ""); return {id}; } static inline ScanTraceState protocol_conformance_scan_begin(const Metadata *type, const ProtocolDescriptor *protocol) { ENSURE_LOG(ScanLog); auto id = os_signpost_id_generate(ScanLog); // Check for enablement separately to avoid the potentially expensive // swift_getTypeName call when tracing is not enabled. if (os_signpost_enabled(ScanLog)) { auto typeName = swift_getTypeName(type, /*qualified*/ true); auto protoName = protocol ? protocol->Name.get() : ""; os_signpost_interval_begin(ScanLog, id, SWIFT_LOG_SECTION_SCAN, "protocol conformance scan for %.*s(%p): %s(%p)", (int)typeName.length, typeName.data, type, protoName, protocol); } return {id}; } static inline ScanTraceState protocol_scan_begin(Demangle::NodePointer node) { ENSURE_LOG(ScanLog); auto id = os_signpost_id_generate(ScanLog); os_signpost_interval_begin(ScanLog, id, SWIFT_LOG_SECTION_SCAN, "protocol scan for '%s'", node ? nodeToString(node).c_str() : ""); return {id}; } #pragma clang diagnostic pop } // namespace trace } // namespace runtime } // namespace swift #else namespace swift { namespace runtime { namespace trace { struct ScanTraceState { template T *end(T *result) { return result; } }; static inline ScanTraceState accessible_function_scan_begin(llvm::StringRef name) { return {}; } static inline ScanTraceState metadata_scan_begin(Demangle::NodePointer node) { return {}; } static inline ScanTraceState protocol_conformance_scan_begin(Demangle::NodePointer node) { return {}; } static inline ScanTraceState protocol_conformance_scan_begin(const Metadata *type, const ProtocolDescriptor *protocol) { return {}; } static inline ScanTraceState protocol_scan_begin(Demangle::NodePointer node) { return {}; } } // namespace trace } // namespace runtime } // namespace swift #endif #endif // SWIFT_TRACING_H