Skip to content

Commit 8d0fa6f

Browse files
committed
[Runtime] Add tracing for section scans.
Section scans (for metadata, protocols, etc.) can be costly. This change adds tracing calls to those scans so we can more easily see how much time is spent in these scans and where they're initiated. This adds an os_signpost implementation controlled by SWIFT_STDLIB_TRACING, and a default empty implementation for when that's disabled. rdar://110266743
1 parent 2ab4d7b commit 8d0fa6f

File tree

10 files changed

+269
-5
lines changed

10 files changed

+269
-5
lines changed

stdlib/cmake/modules/AddSwiftStdlib.cmake

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,10 @@ function(_add_target_variant_c_compile_flags)
417417
list(APPEND result "-DSWIFT_STDLIB_ENABLE_UNICODE_DATA")
418418
endif()
419419

420+
if(SWIFT_STDLIB_TRACING)
421+
list(APPEND result "-DSWIFT_STDLIB_TRACING")
422+
endif()
423+
420424
if(SWIFT_STDLIB_CONCURRENCY_TRACING)
421425
list(APPEND result "-DSWIFT_STDLIB_CONCURRENCY_TRACING")
422426
endif()
@@ -897,7 +901,7 @@ function(add_swift_target_library_single target name)
897901

898902
# Define availability macros.
899903
foreach(def ${SWIFT_STDLIB_AVAILABILITY_DEFINITIONS})
900-
list(APPEND SWIFTLIB_SINGLE_SWIFT_COMPILE_FLAGS "-Xfrontend" "-define-availability" "-Xfrontend" "${def}")
904+
list(APPEND SWIFTLIB_SINGLE_SWIFT_COMPILE_FLAGS "-Xfrontend" "-define-availability" "-Xfrontend" "${def}")
901905
endforeach()
902906

903907
# Enable -target-min-inlining-version

stdlib/cmake/modules/StdlibOptions.cmake

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,18 @@ set(SWIFT_STDLIB_ENABLE_LTO OFF CACHE STRING "Build Swift stdlib with LTO. One
221221
option only affects the standard library and runtime, not tools.")
222222

223223
if("${SWIFT_HOST_VARIANT_SDK}" IN_LIST SWIFT_DARWIN_PLATFORMS)
224+
set(SWIFT_STDLIB_TRACING_default TRUE)
224225
set(SWIFT_STDLIB_CONCURRENCY_TRACING_default TRUE)
225226
else()
227+
set(SWIFT_STDLIB_TRACING_default FALSE)
226228
set(SWIFT_STDLIB_CONCURRENCY_TRACING_default FALSE)
227229
endif()
228230

231+
option(SWIFT_STDLIB_TRACING
232+
"Enable tracing in the runtime; assumes the presence of os_log(3)
233+
and the os_signpost(3) API."
234+
"${SWIFT_STDLIB_TRACING_default}")
235+
229236
option(SWIFT_STDLIB_CONCURRENCY_TRACING
230237
"Enable concurrency tracing in the runtime; assumes the presence of os_log(3)
231238
and the os_signpost(3) API."

stdlib/public/runtime/AccessibleFunction.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/Runtime/AccessibleFunction.h"
2222
#include "swift/Runtime/Concurrent.h"
2323
#include "swift/Runtime/Metadata.h"
24+
#include "Tracing.h"
2425

2526
#include <cstdint>
2627
#include <new>
@@ -120,12 +121,14 @@ void swift::addImageAccessibleFunctionsBlockCallback(
120121

121122
static const AccessibleFunctionRecord *
122123
_searchForFunctionRecord(AccessibleFunctionsState &S, llvm::StringRef name) {
124+
auto traceState = runtime::trace::accessible_function_scan_begin(name);
125+
123126
for (const auto &section : S.SectionsToScan.snapshot()) {
124127
for (auto &record : section) {
125128
auto recordName =
126129
swift::Demangle::makeSymbolicMangledNameStringRef(record.Name.get());
127130
if (recordName == name)
128-
return &record;
131+
return traceState.end(&record);
129132
}
130133
}
131134
return nullptr;

stdlib/public/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ set(swift_runtime_sources
7676
SwiftDtoa.cpp
7777
SwiftTLSContext.cpp
7878
ThreadingError.cpp
79+
Tracing.cpp
7980
AccessibleFunction.cpp
8081
Win32.cpp)
8182

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "../CompatibilityOverride/CompatibilityOverride.h"
1818
#include "ImageInspection.h"
1919
#include "Private.h"
20+
#include "Tracing.h"
2021
#include "swift/ABI/TypeIdentity.h"
2122
#include "swift/Basic/Lazy.h"
2223
#include "swift/Demangling/Demangler.h"
@@ -742,11 +743,13 @@ _searchTypeMetadataRecords(TypeMetadataPrivateState &T,
742743
return nullptr;
743744
#endif
744745

746+
auto traceState = runtime::trace::metadata_scan_begin(node);
747+
745748
for (auto &section : T.SectionsToScan.snapshot()) {
746749
for (const auto &record : section) {
747750
if (auto context = record.getContextDescriptor()) {
748751
if (_contextDescriptorMatchesMangling(context, node)) {
749-
return context;
752+
return traceState.end(context);
750753
}
751754
}
752755
}
@@ -970,11 +973,13 @@ void swift::swift_registerProtocols(const ProtocolRecord *begin,
970973
static const ProtocolDescriptor *
971974
_searchProtocolRecords(ProtocolMetadataPrivateState &C,
972975
NodePointer node) {
976+
auto traceState = runtime::trace::protocol_scan_begin(node);
977+
973978
for (auto &section : C.SectionsToScan.snapshot()) {
974979
for (const auto &record : section) {
975980
if (auto protocol = record.Protocol.getPointer()) {
976981
if (_contextDescriptorMatchesMangling(protocol, node))
977-
return protocol;
982+
return traceState.end(protocol);
978983
}
979984
}
980985
}

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "../CompatibilityOverride/CompatibilityOverride.h"
3131
#include "ImageInspection.h"
3232
#include "Private.h"
33+
#include "Tracing.h"
3334

3435
#include <new>
3536
#include <vector>
@@ -1089,6 +1090,9 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
10891090
}
10901091
};
10911092

1093+
auto traceState =
1094+
runtime::trace::protocol_conformance_scan_begin(type, protocol);
1095+
10921096
auto snapshot = C.SectionsToScan.snapshot();
10931097
if (C.scanSectionsBackwards) {
10941098
for (auto &section : llvm::reverse(snapshot))
@@ -1125,6 +1129,8 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
11251129
}
11261130
noteFinalMetadataState(superclassIterator.state);
11271131

1132+
traceState.end(foundWitness);
1133+
11281134
// If it's for a superclass or if we didn't find anything, then add an
11291135
// authoritative entry for this type.
11301136
if (foundType != type)
@@ -1170,13 +1176,15 @@ swift_conformsToProtocolImpl(const Metadata *const type,
11701176

11711177
const ContextDescriptor *
11721178
swift::_searchConformancesByMangledTypeName(Demangle::NodePointer node) {
1179+
auto traceState = runtime::trace::protocol_conformance_scan_begin(node);
1180+
11731181
auto &C = Conformances.get();
11741182

11751183
for (auto &section : C.SectionsToScan.snapshot()) {
11761184
for (const auto &record : section) {
11771185
if (auto ntd = record->getTypeDescriptor()) {
11781186
if (_contextDescriptorMatchesMangling(ntd, node))
1179-
return ntd;
1187+
return traceState.end(ntd);
11801188
}
11811189
}
11821190
}

stdlib/public/runtime/Tracing.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===--- Tracing.cpp - Support code for runtime tracing ------------*- C++ -*-//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Support code for tracing events in the Swift runtime
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "Tracing.h"
18+
19+
#if SWIFT_STDLIB_TRACING
20+
21+
#define SWIFT_LOG_SUBSYSTEM "com.apple.swift"
22+
#define SWIFT_LOG_SECTION_SCAN_CATEGORY "SectionScan"
23+
24+
namespace swift {
25+
namespace runtime {
26+
namespace trace {
27+
28+
os_log_t ScanLog;
29+
swift::once_t LogsToken;
30+
31+
void setupLogs(void *unused) {
32+
ScanLog = os_log_create(SWIFT_LOG_SUBSYSTEM, SWIFT_LOG_SECTION_SCAN_CATEGORY);
33+
}
34+
35+
} // namespace trace
36+
} // namespace runtime
37+
} // namespace swift
38+
39+
#endif

stdlib/public/runtime/Tracing.h

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
//===--- Tracing.h - Support code for runtime tracing --------------*- C++ -*-//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Support code for tracing events in the Swift runtime
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_TRACING_H
18+
#define SWIFT_TRACING_H
19+
20+
#include "llvm/ADT/StringRef.h"
21+
#include "swift/ABI/Metadata.h"
22+
#include "swift/Demangling/Demangler.h"
23+
24+
#if SWIFT_STDLIB_TRACING
25+
#include <os/signpost.h>
26+
27+
#include "swift/Runtime/HeapObject.h"
28+
29+
#define SWIFT_LOG_SECTION_SCAN "section_scan"
30+
31+
namespace swift {
32+
namespace runtime {
33+
namespace trace {
34+
35+
extern os_log_t ScanLog;
36+
extern swift::once_t LogsToken;
37+
38+
void setupLogs(void *unused);
39+
40+
// Every function does ENSURE_LOGS() before making any os_signpost calls, so
41+
// we can skip availability checking on all the individual calls.
42+
#pragma clang diagnostic push
43+
#pragma clang diagnostic ignored "-Wunguarded-availability"
44+
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
45+
46+
// Check a representative os_signpost function for NULL rather than doing a
47+
// standard availability check, for better performance if the check doesn't get
48+
// optimized out.
49+
#define ENSURE_LOG(log) \
50+
do { \
51+
if (!SWIFT_RUNTIME_WEAK_CHECK(os_signpost_enabled)) \
52+
return {}; \
53+
swift::once(LogsToken, setupLogs, nullptr); \
54+
} while (0)
55+
56+
/// A struct that captures the state of a scan tracing signpost. When the scan
57+
/// is complete, call end() with the result of the scan. If the state struct
58+
/// goes out of scope without calling end(), then it will automatically do the
59+
/// equivalent of end(nullptr).
60+
struct ScanTraceState {
61+
os_signpost_id_t signpostID;
62+
63+
bool ended = false;
64+
65+
template <typename T>
66+
T *end(T *result) {
67+
ended = true;
68+
os_signpost_interval_end(ScanLog, signpostID, SWIFT_LOG_SECTION_SCAN,
69+
"result=%p", result);
70+
return result;
71+
}
72+
73+
~ScanTraceState() {
74+
if (!ended)
75+
end((void *)nullptr);
76+
}
77+
};
78+
79+
static inline ScanTraceState
80+
accessible_function_scan_begin(llvm::StringRef name) {
81+
ENSURE_LOG(ScanLog);
82+
83+
auto id = os_signpost_id_generate(ScanLog);
84+
os_signpost_interval_begin(ScanLog, id, SWIFT_LOG_SECTION_SCAN,
85+
"accessible function scan for %.*s",
86+
(int)name.size(), name.data());
87+
return {id};
88+
}
89+
90+
static inline ScanTraceState metadata_scan_begin(Demangle::NodePointer node) {
91+
ENSURE_LOG(ScanLog);
92+
93+
auto id = os_signpost_id_generate(ScanLog);
94+
os_signpost_interval_begin(ScanLog, id, SWIFT_LOG_SECTION_SCAN,
95+
"metadata scan for %s",
96+
nodeToString(node).c_str());
97+
return {id};
98+
}
99+
100+
static inline ScanTraceState
101+
protocol_conformance_scan_begin(Demangle::NodePointer node) {
102+
ENSURE_LOG(ScanLog);
103+
104+
auto id = os_signpost_id_generate(ScanLog);
105+
os_signpost_interval_begin(ScanLog, id, SWIFT_LOG_SECTION_SCAN,
106+
"protocol conformance scan for %s",
107+
nodeToString(node).c_str());
108+
return {id};
109+
}
110+
111+
static inline ScanTraceState
112+
protocol_conformance_scan_begin(const Metadata *type,
113+
const ProtocolDescriptor *protocol) {
114+
ENSURE_LOG(ScanLog);
115+
116+
auto id = os_signpost_id_generate(ScanLog);
117+
118+
// Check for enablement separately to avoid the potentially expensive
119+
// swift_getTypeName call when tracing is not enabled.
120+
if (os_signpost_enabled(ScanLog)) {
121+
auto typeName = swift_getTypeName(type, /*qualified*/ true);
122+
os_signpost_interval_begin(ScanLog, id, SWIFT_LOG_SECTION_SCAN,
123+
"protocol conformance scan for %.*s(%p): %s(%p)",
124+
(int)typeName.length, typeName.data, type,
125+
protocol->Name.get(), protocol);
126+
}
127+
return {id};
128+
}
129+
130+
static inline ScanTraceState protocol_scan_begin(Demangle::NodePointer node) {
131+
ENSURE_LOG(ScanLog);
132+
133+
auto id = os_signpost_id_generate(ScanLog);
134+
os_signpost_interval_begin(ScanLog, id, SWIFT_LOG_SECTION_SCAN,
135+
"protocol scan for %s",
136+
nodeToString(node).c_str());
137+
return {id};
138+
}
139+
140+
#pragma clang diagnostic pop
141+
142+
} // namespace trace
143+
} // namespace runtime
144+
} // namespace swift
145+
146+
#else
147+
148+
namespace swift {
149+
namespace runtime {
150+
namespace trace {
151+
152+
struct ScanTraceState {
153+
template <typename T>
154+
T *end(T *result) {
155+
return result;
156+
}
157+
};
158+
159+
static inline ScanTraceState
160+
accessible_function_scan_begin(llvm::StringRef name) {
161+
return {};
162+
}
163+
164+
static inline ScanTraceState metadata_scan_begin(Demangle::NodePointer node) {
165+
return {};
166+
}
167+
168+
static inline ScanTraceState
169+
protocol_conformance_scan_begin(Demangle::NodePointer node) {
170+
return {};
171+
}
172+
173+
static inline ScanTraceState
174+
protocol_conformance_scan_begin(const Metadata *type,
175+
const ProtocolDescriptor *protocol) {
176+
return {};
177+
}
178+
179+
static inline ScanTraceState protocol_scan_begin(Demangle::NodePointer node) {
180+
return {};
181+
}
182+
183+
} // namespace trace
184+
} // namespace runtime
185+
} // namespace swift
186+
187+
#endif
188+
189+
#endif // SWIFT_TRACING_H

utils/build-script-impl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,13 @@ for host in "${ALL_HOSTS[@]}"; do
20442044
)
20452045
fi
20462046

2047+
if [[ "${SWIFT_STDLIB_TRACING}" ]] ; then
2048+
cmake_options=(
2049+
"${cmake_options[@]}"
2050+
-DSWIFT_STDLIB_TRACING:BOOL=$(true_false "${SWIFT_STDLIB_TRACING}")
2051+
)
2052+
fi
2053+
20472054
if [[ "${SWIFT_STDLIB_CONCURRENCY_TRACING}" ]] ; then
20482055
cmake_options=(
20492056
"${cmake_options[@]}"

0 commit comments

Comments
 (0)