10b57cec5SDimitry Andric //===-- Signposts.cpp - Interval debug annotations ------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric //                     The LLVM Compiler Infrastructure
40b57cec5SDimitry Andric //
50b57cec5SDimitry Andric // This file is distributed under the University of Illinois Open Source
60b57cec5SDimitry Andric // License. See LICENSE.TXT for details.
70b57cec5SDimitry Andric //
80b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
90b57cec5SDimitry Andric 
100b57cec5SDimitry Andric #include "llvm/Support/Signposts.h"
110b57cec5SDimitry Andric #include "llvm/Support/Timer.h"
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/Config/config.h"
140b57cec5SDimitry Andric #if LLVM_SUPPORT_XCODE_SIGNPOSTS
150b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
160b57cec5SDimitry Andric #include <os/signpost.h>
170b57cec5SDimitry Andric #endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace llvm;
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #if LLVM_SUPPORT_XCODE_SIGNPOSTS
220b57cec5SDimitry Andric namespace {
230b57cec5SDimitry Andric os_log_t *LogCreator() {
240b57cec5SDimitry Andric   os_log_t *X = new os_log_t;
250b57cec5SDimitry Andric   *X = os_log_create("org.llvm.signposts", OS_LOG_CATEGORY_POINTS_OF_INTEREST);
260b57cec5SDimitry Andric   return X;
270b57cec5SDimitry Andric }
280b57cec5SDimitry Andric void LogDeleter(os_log_t *X) {
290b57cec5SDimitry Andric   os_release(*X);
300b57cec5SDimitry Andric   delete X;
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric } // end anonymous namespace
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric namespace llvm {
350b57cec5SDimitry Andric class SignpostEmitterImpl {
360b57cec5SDimitry Andric   using LogPtrTy =
370b57cec5SDimitry Andric       std::unique_ptr<os_log_t, std::function<void(os_log_t *)>>;
380b57cec5SDimitry Andric   using LogTy = LogPtrTy::element_type;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   LogPtrTy SignpostLog;
410b57cec5SDimitry Andric   DenseMap<const Timer *, os_signpost_id_t> Signposts;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   LogTy &getLogger() const { return *SignpostLog; }
440b57cec5SDimitry Andric   os_signpost_id_t getSignpostForTimer(const Timer *T) {
450b57cec5SDimitry Andric     const auto &I = Signposts.find(T);
460b57cec5SDimitry Andric     if (I != Signposts.end())
470b57cec5SDimitry Andric       return I->second;
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric     const auto &Inserted = Signposts.insert(
500b57cec5SDimitry Andric         std::make_pair(T, os_signpost_id_make_with_pointer(getLogger(), T)));
510b57cec5SDimitry Andric     return Inserted.first->second;
520b57cec5SDimitry Andric   }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric public:
550b57cec5SDimitry Andric   SignpostEmitterImpl() : SignpostLog(LogCreator(), LogDeleter), Signposts() {}
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   bool isEnabled() const { return os_signpost_enabled(*SignpostLog); }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   void startTimerInterval(Timer *T) {
600b57cec5SDimitry Andric     if (isEnabled()) {
610b57cec5SDimitry Andric       // Both strings used here are required to be constant literal strings
620b57cec5SDimitry Andric       os_signpost_interval_begin(getLogger(), getSignpostForTimer(T),
630b57cec5SDimitry Andric                                  "Pass Timers", "Begin %s",
640b57cec5SDimitry Andric                                  T->getName().c_str());
650b57cec5SDimitry Andric     }
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   void endTimerInterval(Timer *T) {
690b57cec5SDimitry Andric     if (isEnabled()) {
700b57cec5SDimitry Andric       // Both strings used here are required to be constant literal strings
710b57cec5SDimitry Andric       os_signpost_interval_end(getLogger(), getSignpostForTimer(T),
720b57cec5SDimitry Andric                                "Pass Timers", "End %s", T->getName().c_str());
730b57cec5SDimitry Andric     }
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric };
760b57cec5SDimitry Andric } // end namespace llvm
770b57cec5SDimitry Andric #endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric #if LLVM_SUPPORT_XCODE_SIGNPOSTS
800b57cec5SDimitry Andric #define HAVE_ANY_SIGNPOST_IMPL 1
810b57cec5SDimitry Andric #endif
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric SignpostEmitter::SignpostEmitter() {
840b57cec5SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
850b57cec5SDimitry Andric   Impl = new SignpostEmitterImpl();
860b57cec5SDimitry Andric #else // if HAVE_ANY_SIGNPOST_IMPL
870b57cec5SDimitry Andric   Impl = nullptr;
880b57cec5SDimitry Andric #endif // if !HAVE_ANY_SIGNPOST_IMPL
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric SignpostEmitter::~SignpostEmitter() {
920b57cec5SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
930b57cec5SDimitry Andric   delete Impl;
940b57cec5SDimitry Andric #endif // if HAVE_ANY_SIGNPOST_IMPL
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric bool SignpostEmitter::isEnabled() const {
980b57cec5SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
990b57cec5SDimitry Andric   return Impl->isEnabled();
1000b57cec5SDimitry Andric #else
1010b57cec5SDimitry Andric   return false;
1020b57cec5SDimitry Andric #endif // if !HAVE_ANY_SIGNPOST_IMPL
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric void SignpostEmitter::startTimerInterval(Timer *T) {
1060b57cec5SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
1070b57cec5SDimitry Andric   if (Impl == nullptr)
1080b57cec5SDimitry Andric     return;
1090b57cec5SDimitry Andric   return Impl->startTimerInterval(T);
1100b57cec5SDimitry Andric #endif // if !HAVE_ANY_SIGNPOST_IMPL
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric void SignpostEmitter::endTimerInterval(Timer *T) {
1140b57cec5SDimitry Andric #if HAVE_ANY_SIGNPOST_IMPL
1150b57cec5SDimitry Andric   if (Impl == nullptr)
1160b57cec5SDimitry Andric     return;
1170b57cec5SDimitry Andric   Impl->endTimerInterval(T);
1180b57cec5SDimitry Andric #endif // if !HAVE_ANY_SIGNPOST_IMPL
1190b57cec5SDimitry Andric }
120