1e6d15924SDimitry Andric //===-- Signposts.cpp - Interval debug annotations ------------------------===//
2e6d15924SDimitry Andric //
3c0981da4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c0981da4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5c0981da4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e6d15924SDimitry Andric //
7e6d15924SDimitry Andric //===----------------------------------------------------------------------===//
8e6d15924SDimitry Andric
9e6d15924SDimitry Andric #include "llvm/Support/Signposts.h"
10145449b1SDimitry Andric #include "llvm/ADT/StringRef.h"
11c0981da4SDimitry Andric #include "llvm/Config/config.h"
12145449b1SDimitry Andric
13e6d15924SDimitry Andric #if LLVM_SUPPORT_XCODE_SIGNPOSTS
14e6d15924SDimitry Andric #include "llvm/ADT/DenseMap.h"
15b60736ecSDimitry Andric #include "llvm/Support/Mutex.h"
16c0981da4SDimitry Andric #include <Availability.h>
17c0981da4SDimitry Andric #include <os/signpost.h>
18c0981da4SDimitry Andric #endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS
19e6d15924SDimitry Andric
20e6d15924SDimitry Andric using namespace llvm;
21e6d15924SDimitry Andric
22e6d15924SDimitry Andric #if LLVM_SUPPORT_XCODE_SIGNPOSTS
23c0981da4SDimitry Andric #define SIGNPOSTS_AVAILABLE() \
24c0981da4SDimitry Andric __builtin_available(macos 10.14, iOS 12, tvOS 12, watchOS 5, *)
25e6d15924SDimitry Andric namespace {
LogCreator()26e6d15924SDimitry Andric os_log_t *LogCreator() {
27e6d15924SDimitry Andric os_log_t *X = new os_log_t;
28145449b1SDimitry Andric *X = os_log_create("org.llvm.signposts", "toolchain");
29e6d15924SDimitry Andric return X;
30e6d15924SDimitry Andric }
31344a3780SDimitry Andric struct LogDeleter {
operator ()__anon9a91db3b0111::LogDeleter32344a3780SDimitry Andric void operator()(os_log_t *X) const {
33e6d15924SDimitry Andric os_release(*X);
34e6d15924SDimitry Andric delete X;
35e6d15924SDimitry Andric }
36344a3780SDimitry Andric };
37e6d15924SDimitry Andric } // end anonymous namespace
38e6d15924SDimitry Andric
39e6d15924SDimitry Andric namespace llvm {
40e6d15924SDimitry Andric class SignpostEmitterImpl {
41344a3780SDimitry Andric using LogPtrTy = std::unique_ptr<os_log_t, LogDeleter>;
42c0981da4SDimitry Andric using LogTy = LogPtrTy::element_type;
43e6d15924SDimitry Andric
44e6d15924SDimitry Andric LogPtrTy SignpostLog;
45b60736ecSDimitry Andric DenseMap<const void *, os_signpost_id_t> Signposts;
46b60736ecSDimitry Andric sys::SmartMutex<true> Mutex;
47e6d15924SDimitry Andric
getLogger() const48c0981da4SDimitry Andric LogTy &getLogger() const { return *SignpostLog; }
getSignpostForObject(const void * O)49b60736ecSDimitry Andric os_signpost_id_t getSignpostForObject(const void *O) {
50b60736ecSDimitry Andric sys::SmartScopedLock<true> Lock(Mutex);
51b60736ecSDimitry Andric const auto &I = Signposts.find(O);
52e6d15924SDimitry Andric if (I != Signposts.end())
53e6d15924SDimitry Andric return I->second;
54344a3780SDimitry Andric os_signpost_id_t ID = {};
55344a3780SDimitry Andric if (SIGNPOSTS_AVAILABLE()) {
56344a3780SDimitry Andric ID = os_signpost_id_make_with_pointer(getLogger(), O);
57344a3780SDimitry Andric }
58344a3780SDimitry Andric const auto &Inserted = Signposts.insert(std::make_pair(O, ID));
59e6d15924SDimitry Andric return Inserted.first->second;
60e6d15924SDimitry Andric }
61e6d15924SDimitry Andric
62c0981da4SDimitry Andric public:
SignpostEmitterImpl()63344a3780SDimitry Andric SignpostEmitterImpl() : SignpostLog(LogCreator()) {}
64e6d15924SDimitry Andric
isEnabled() const65344a3780SDimitry Andric bool isEnabled() const {
66344a3780SDimitry Andric if (SIGNPOSTS_AVAILABLE())
67344a3780SDimitry Andric return os_signpost_enabled(*SignpostLog);
68344a3780SDimitry Andric return false;
69344a3780SDimitry Andric }
70e6d15924SDimitry Andric
startInterval(const void * O,llvm::StringRef Name)71b60736ecSDimitry Andric void startInterval(const void *O, llvm::StringRef Name) {
72e6d15924SDimitry Andric if (isEnabled()) {
73344a3780SDimitry Andric if (SIGNPOSTS_AVAILABLE()) {
74b60736ecSDimitry Andric // Both strings used here are required to be constant literal strings.
75b60736ecSDimitry Andric os_signpost_interval_begin(getLogger(), getSignpostForObject(O),
76344a3780SDimitry Andric "LLVM Timers", "%s", Name.data());
77344a3780SDimitry Andric }
78e6d15924SDimitry Andric }
79e6d15924SDimitry Andric }
80e6d15924SDimitry Andric
endInterval(const void * O,llvm::StringRef Name)81c0981da4SDimitry Andric void endInterval(const void *O, llvm::StringRef Name) {
82e6d15924SDimitry Andric if (isEnabled()) {
83344a3780SDimitry Andric if (SIGNPOSTS_AVAILABLE()) {
84b60736ecSDimitry Andric // Both strings used here are required to be constant literal strings.
85b60736ecSDimitry Andric os_signpost_interval_end(getLogger(), getSignpostForObject(O),
86344a3780SDimitry Andric "LLVM Timers", "");
87344a3780SDimitry Andric }
88e6d15924SDimitry Andric }
89e6d15924SDimitry Andric }
90e6d15924SDimitry Andric };
91e6d15924SDimitry Andric } // end namespace llvm
92344a3780SDimitry Andric #else
93344a3780SDimitry Andric /// Definition necessary for use of std::unique_ptr in SignpostEmitter::Impl.
94344a3780SDimitry Andric class llvm::SignpostEmitterImpl {};
95e6d15924SDimitry Andric #endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS
96e6d15924SDimitry Andric
97e6d15924SDimitry Andric #if LLVM_SUPPORT_XCODE_SIGNPOSTS
98e6d15924SDimitry Andric #define HAVE_ANY_SIGNPOST_IMPL 1
991d5ae102SDimitry Andric #else
1001d5ae102SDimitry Andric #define HAVE_ANY_SIGNPOST_IMPL 0
101e6d15924SDimitry Andric #endif
102e6d15924SDimitry Andric
SignpostEmitter()103e6d15924SDimitry Andric SignpostEmitter::SignpostEmitter() {
104e6d15924SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
105344a3780SDimitry Andric Impl = std::make_unique<SignpostEmitterImpl>();
106e6d15924SDimitry Andric #endif // if !HAVE_ANY_SIGNPOST_IMPL
107e6d15924SDimitry Andric }
108e6d15924SDimitry Andric
109344a3780SDimitry Andric SignpostEmitter::~SignpostEmitter() = default;
110e6d15924SDimitry Andric
isEnabled() const111e6d15924SDimitry Andric bool SignpostEmitter::isEnabled() const {
112e6d15924SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
113e6d15924SDimitry Andric return Impl->isEnabled();
114e6d15924SDimitry Andric #else
115e6d15924SDimitry Andric return false;
116e6d15924SDimitry Andric #endif // if !HAVE_ANY_SIGNPOST_IMPL
117e6d15924SDimitry Andric }
118e6d15924SDimitry Andric
startInterval(const void * O,StringRef Name)119b60736ecSDimitry Andric void SignpostEmitter::startInterval(const void *O, StringRef Name) {
120e6d15924SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
121e6d15924SDimitry Andric if (Impl == nullptr)
122e6d15924SDimitry Andric return;
123b60736ecSDimitry Andric return Impl->startInterval(O, Name);
124e6d15924SDimitry Andric #endif // if !HAVE_ANY_SIGNPOST_IMPL
125e6d15924SDimitry Andric }
126e6d15924SDimitry Andric
endInterval(const void * O,StringRef Name)127c0981da4SDimitry Andric void SignpostEmitter::endInterval(const void *O, StringRef Name) {
128e6d15924SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
129e6d15924SDimitry Andric if (Impl == nullptr)
130e6d15924SDimitry Andric return;
131c0981da4SDimitry Andric Impl->endInterval(O, Name);
132e6d15924SDimitry Andric #endif // if !HAVE_ANY_SIGNPOST_IMPL
133e6d15924SDimitry Andric }
134