1*0b57cec5SDimitry Andric //===-- Signposts.cpp - Interval debug annotations ------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "llvm/Support/Signposts.h"
10*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
11*0b57cec5SDimitry Andric #include "llvm/Config/config.h"
12*0b57cec5SDimitry Andric 
13*0b57cec5SDimitry Andric #if LLVM_SUPPORT_XCODE_SIGNPOSTS
14*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
15*0b57cec5SDimitry Andric #include "llvm/Support/Mutex.h"
16*0b57cec5SDimitry Andric #include <Availability.h>
17*0b57cec5SDimitry Andric #include <os/signpost.h>
18*0b57cec5SDimitry Andric #endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS
19*0b57cec5SDimitry Andric 
20*0b57cec5SDimitry Andric using namespace llvm;
21*0b57cec5SDimitry Andric 
22*0b57cec5SDimitry Andric #if LLVM_SUPPORT_XCODE_SIGNPOSTS
23*0b57cec5SDimitry Andric #define SIGNPOSTS_AVAILABLE()                                                  \
24*0b57cec5SDimitry Andric   __builtin_available(macos 10.14, iOS 12, tvOS 12, watchOS 5, *)
25*0b57cec5SDimitry Andric namespace {
LogCreator()26*0b57cec5SDimitry Andric os_log_t *LogCreator() {
27*0b57cec5SDimitry Andric   os_log_t *X = new os_log_t;
28*0b57cec5SDimitry Andric   *X = os_log_create("org.llvm.signposts", "toolchain");
29*0b57cec5SDimitry Andric   return X;
30*0b57cec5SDimitry Andric }
31*0b57cec5SDimitry Andric struct LogDeleter {
operator ()__anonaa19eb7c0111::LogDeleter32*0b57cec5SDimitry Andric   void operator()(os_log_t *X) const {
33*0b57cec5SDimitry Andric     os_release(*X);
34*0b57cec5SDimitry Andric     delete X;
35*0b57cec5SDimitry Andric   }
36*0b57cec5SDimitry Andric };
37*0b57cec5SDimitry Andric } // end anonymous namespace
38*0b57cec5SDimitry Andric 
39*0b57cec5SDimitry Andric namespace llvm {
40*0b57cec5SDimitry Andric class SignpostEmitterImpl {
41*0b57cec5SDimitry Andric   using LogPtrTy = std::unique_ptr<os_log_t, LogDeleter>;
42*0b57cec5SDimitry Andric   using LogTy = LogPtrTy::element_type;
43*0b57cec5SDimitry Andric 
44*0b57cec5SDimitry Andric   LogPtrTy SignpostLog;
45*0b57cec5SDimitry Andric   DenseMap<const void *, os_signpost_id_t> Signposts;
46*0b57cec5SDimitry Andric   sys::SmartMutex<true> Mutex;
47*0b57cec5SDimitry Andric 
getLogger() const48*0b57cec5SDimitry Andric   LogTy &getLogger() const { return *SignpostLog; }
getSignpostForObject(const void * O)49*0b57cec5SDimitry Andric   os_signpost_id_t getSignpostForObject(const void *O) {
50*0b57cec5SDimitry Andric     sys::SmartScopedLock<true> Lock(Mutex);
51*0b57cec5SDimitry Andric     const auto &I = Signposts.find(O);
52*0b57cec5SDimitry Andric     if (I != Signposts.end())
53*0b57cec5SDimitry Andric       return I->second;
54*0b57cec5SDimitry Andric     os_signpost_id_t ID = {};
55*0b57cec5SDimitry Andric     if (SIGNPOSTS_AVAILABLE()) {
56*0b57cec5SDimitry Andric       ID = os_signpost_id_make_with_pointer(getLogger(), O);
57*0b57cec5SDimitry Andric     }
58*0b57cec5SDimitry Andric     const auto &Inserted = Signposts.insert(std::make_pair(O, ID));
59*0b57cec5SDimitry Andric     return Inserted.first->second;
60*0b57cec5SDimitry Andric   }
61*0b57cec5SDimitry Andric 
62*0b57cec5SDimitry Andric public:
SignpostEmitterImpl()63*0b57cec5SDimitry Andric   SignpostEmitterImpl() : SignpostLog(LogCreator()) {}
64*0b57cec5SDimitry Andric 
isEnabled() const65*0b57cec5SDimitry Andric   bool isEnabled() const {
66*0b57cec5SDimitry Andric     if (SIGNPOSTS_AVAILABLE())
67*0b57cec5SDimitry Andric       return os_signpost_enabled(*SignpostLog);
68*0b57cec5SDimitry Andric     return false;
69*0b57cec5SDimitry Andric   }
70*0b57cec5SDimitry Andric 
startInterval(const void * O,llvm::StringRef Name)71*0b57cec5SDimitry Andric   void startInterval(const void *O, llvm::StringRef Name) {
72*0b57cec5SDimitry Andric     if (isEnabled()) {
73*0b57cec5SDimitry Andric       if (SIGNPOSTS_AVAILABLE()) {
74*0b57cec5SDimitry Andric         // Both strings used here are required to be constant literal strings.
75*0b57cec5SDimitry Andric         os_signpost_interval_begin(getLogger(), getSignpostForObject(O),
76*0b57cec5SDimitry Andric                                    "LLVM Timers", "%s", Name.data());
77*0b57cec5SDimitry Andric       }
78*0b57cec5SDimitry Andric     }
79*0b57cec5SDimitry Andric   }
80*0b57cec5SDimitry Andric 
endInterval(const void * O,llvm::StringRef Name)81*0b57cec5SDimitry Andric   void endInterval(const void *O, llvm::StringRef Name) {
82*0b57cec5SDimitry Andric     if (isEnabled()) {
83*0b57cec5SDimitry Andric       if (SIGNPOSTS_AVAILABLE()) {
84*0b57cec5SDimitry Andric         // Both strings used here are required to be constant literal strings.
85*0b57cec5SDimitry Andric         os_signpost_interval_end(getLogger(), getSignpostForObject(O),
86*0b57cec5SDimitry Andric                                  "LLVM Timers", "");
87*0b57cec5SDimitry Andric       }
88*0b57cec5SDimitry Andric     }
89*0b57cec5SDimitry Andric   }
90*0b57cec5SDimitry Andric };
91*0b57cec5SDimitry Andric } // end namespace llvm
92*0b57cec5SDimitry Andric #else
93*0b57cec5SDimitry Andric /// Definition necessary for use of std::unique_ptr in SignpostEmitter::Impl.
94*0b57cec5SDimitry Andric class llvm::SignpostEmitterImpl {};
95*0b57cec5SDimitry Andric #endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric #if LLVM_SUPPORT_XCODE_SIGNPOSTS
98*0b57cec5SDimitry Andric #define HAVE_ANY_SIGNPOST_IMPL 1
99*0b57cec5SDimitry Andric #else
100*0b57cec5SDimitry Andric #define HAVE_ANY_SIGNPOST_IMPL 0
101*0b57cec5SDimitry Andric #endif
102*0b57cec5SDimitry Andric 
SignpostEmitter()103*0b57cec5SDimitry Andric SignpostEmitter::SignpostEmitter() {
104*0b57cec5SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
105*0b57cec5SDimitry Andric   Impl = std::make_unique<SignpostEmitterImpl>();
106*0b57cec5SDimitry Andric #endif // if !HAVE_ANY_SIGNPOST_IMPL
107*0b57cec5SDimitry Andric }
108*0b57cec5SDimitry Andric 
109*0b57cec5SDimitry Andric SignpostEmitter::~SignpostEmitter() = default;
110*0b57cec5SDimitry Andric 
isEnabled() const111*0b57cec5SDimitry Andric bool SignpostEmitter::isEnabled() const {
112*0b57cec5SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
113*0b57cec5SDimitry Andric   return Impl->isEnabled();
114*0b57cec5SDimitry Andric #else
115*0b57cec5SDimitry Andric   return false;
116*0b57cec5SDimitry Andric #endif // if !HAVE_ANY_SIGNPOST_IMPL
117*0b57cec5SDimitry Andric }
118*0b57cec5SDimitry Andric 
startInterval(const void * O,StringRef Name)119*0b57cec5SDimitry Andric void SignpostEmitter::startInterval(const void *O, StringRef Name) {
120 #if HAVE_ANY_SIGNPOST_IMPL
121   if (Impl == nullptr)
122     return;
123   return Impl->startInterval(O, Name);
124 #endif // if !HAVE_ANY_SIGNPOST_IMPL
125 }
126 
endInterval(const void * O,StringRef Name)127 void SignpostEmitter::endInterval(const void *O, StringRef Name) {
128 #if HAVE_ANY_SIGNPOST_IMPL
129   if (Impl == nullptr)
130     return;
131   Impl->endInterval(O, Name);
132 #endif // if !HAVE_ANY_SIGNPOST_IMPL
133 }
134