1 //===-- Signposts.cpp - Interval debug annotations ------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/Support/Signposts.h"
11 #include "llvm/Support/Timer.h"
12 
13 #include "llvm/Config/config.h"
14 #if LLVM_SUPPORT_XCODE_SIGNPOSTS
15 #include "llvm/ADT/DenseMap.h"
16 #include "llvm/Support/Mutex.h"
17 #include <os/signpost.h>
18 #endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS
19 
20 using namespace llvm;
21 
22 #if LLVM_SUPPORT_XCODE_SIGNPOSTS
23 namespace {
24 os_log_t *LogCreator() {
25   os_log_t *X = new os_log_t;
26   *X = os_log_create("org.llvm.signposts", OS_LOG_CATEGORY_POINTS_OF_INTEREST);
27   return X;
28 }
29 void LogDeleter(os_log_t *X) {
30   os_release(*X);
31   delete X;
32 }
33 } // end anonymous namespace
34 
35 namespace llvm {
36 class SignpostEmitterImpl {
37   using LogPtrTy = std::unique_ptr<os_log_t, std::function<void(os_log_t *)>>;
38   using LogTy = LogPtrTy::element_type;
39 
40   LogPtrTy SignpostLog;
41   DenseMap<const void *, os_signpost_id_t> Signposts;
42   sys::SmartMutex<true> Mutex;
43 
44   LogTy &getLogger() const { return *SignpostLog; }
45   os_signpost_id_t getSignpostForObject(const void *O) {
46     sys::SmartScopedLock<true> Lock(Mutex);
47     const auto &I = Signposts.find(O);
48     if (I != Signposts.end())
49       return I->second;
50 
51     const auto &Inserted = Signposts.insert(
52         std::make_pair(O, os_signpost_id_make_with_pointer(getLogger(), O)));
53     return Inserted.first->second;
54   }
55 
56 public:
57   SignpostEmitterImpl() : SignpostLog(LogCreator(), LogDeleter), Signposts() {}
58 
59   bool isEnabled() const { return os_signpost_enabled(*SignpostLog); }
60 
61   void startInterval(const void *O, llvm::StringRef Name) {
62     if (isEnabled()) {
63       // Both strings used here are required to be constant literal strings.
64       os_signpost_interval_begin(getLogger(), getSignpostForObject(O),
65                                  "LLVM Timers", "Begin %s", Name.data());
66     }
67   }
68 
69   void endInterval(const void *O, llvm::StringRef Name) {
70     if (isEnabled()) {
71       // Both strings used here are required to be constant literal strings.
72       os_signpost_interval_end(getLogger(), getSignpostForObject(O),
73                                "LLVM Timers", "End %s", Name.data());
74     }
75   }
76 };
77 } // end namespace llvm
78 #endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS
79 
80 #if LLVM_SUPPORT_XCODE_SIGNPOSTS
81 #define HAVE_ANY_SIGNPOST_IMPL 1
82 #else
83 #define HAVE_ANY_SIGNPOST_IMPL 0
84 #endif
85 
86 SignpostEmitter::SignpostEmitter() {
87 #if HAVE_ANY_SIGNPOST_IMPL
88   Impl = new SignpostEmitterImpl();
89 #else  // if HAVE_ANY_SIGNPOST_IMPL
90   Impl = nullptr;
91 #endif // if !HAVE_ANY_SIGNPOST_IMPL
92 }
93 
94 SignpostEmitter::~SignpostEmitter() {
95 #if HAVE_ANY_SIGNPOST_IMPL
96   delete Impl;
97 #endif // if HAVE_ANY_SIGNPOST_IMPL
98 }
99 
100 bool SignpostEmitter::isEnabled() const {
101 #if HAVE_ANY_SIGNPOST_IMPL
102   return Impl->isEnabled();
103 #else
104   return false;
105 #endif // if !HAVE_ANY_SIGNPOST_IMPL
106 }
107 
108 void SignpostEmitter::startInterval(const void *O, StringRef Name) {
109 #if HAVE_ANY_SIGNPOST_IMPL
110   if (Impl == nullptr)
111     return;
112   return Impl->startInterval(O, Name);
113 #endif // if !HAVE_ANY_SIGNPOST_IMPL
114 }
115 
116 void SignpostEmitter::endInterval(const void *O, StringRef Name) {
117 #if HAVE_ANY_SIGNPOST_IMPL
118   if (Impl == nullptr)
119     return;
120   Impl->endInterval(O, Name);
121 #endif // if !HAVE_ANY_SIGNPOST_IMPL
122 }
123