Index: llvm/trunk/cmake/modules/HandleLLVMOptions.cmake =================================================================== --- llvm/trunk/cmake/modules/HandleLLVMOptions.cmake +++ llvm/trunk/cmake/modules/HandleLLVMOptions.cmake @@ -916,3 +916,26 @@ get_compile_definitions() option(LLVM_FORCE_ENABLE_STATS "Enable statistics collection for builds that wouldn't normally enable it" OFF) + +check_symbol_exists(os_signpost_interval_begin "os/signpost.h" _signposts_available) +if(_signposts_available) + set(LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS "WITH_ASSERTS" CACHE STRING + "Enable support for Xcode signposts. Can be WITH_ASSERTS, FORCE_ON, FORCE_OFF") + string(TOUPPER "${LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS}" + uppercase_LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS) + if( uppercase_LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS STREQUAL "WITH_ASSERTS" ) + if( LLVM_ENABLE_ASSERTIONS ) + set( LLVM_SUPPORT_XCODE_SIGNPOSTS 1 ) + endif() + elseif( uppercase_LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS STREQUAL "FORCE_ON" ) + set( LLVM_SUPPORT_XCODE_SIGNPOSTS 1 ) + elseif( uppercase_LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS STREQUAL "FORCE_OFF" ) + # We don't need to do anything special to turn off signposts. + elseif( NOT DEFINED LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS ) + # Treat LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS like "FORCE_OFF" when it has not been + # defined. + else() + message(FATAL_ERROR "Unknown value for LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS:" + " \"${LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS}\"!") + endif() +endif() Index: llvm/trunk/include/llvm/Config/config.h.cmake =================================================================== --- llvm/trunk/include/llvm/Config/config.h.cmake +++ llvm/trunk/include/llvm/Config/config.h.cmake @@ -350,4 +350,7 @@ /* Define to the default GlobalISel coverage file prefix */ #cmakedefine LLVM_GISEL_COV_PREFIX "${LLVM_GISEL_COV_PREFIX}" +/* Whether Timers signpost passes in Xcode Instruments */ +#cmakedefine01 LLVM_SUPPORT_XCODE_SIGNPOSTS + #endif Index: llvm/trunk/include/llvm/Support/Signposts.h =================================================================== --- llvm/trunk/include/llvm/Support/Signposts.h +++ llvm/trunk/include/llvm/Support/Signposts.h @@ -0,0 +1,43 @@ +//===-- llvm/Support/Signposts.h - Interval debug annotations ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file Some OS's provide profilers that allow applications to provide custom +/// annotations to the profiler. For example, on Xcode 10 and later 'signposts' +/// can be emitted by the application and these will be rendered to the Points +/// of Interest track on the instruments timeline. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SIGNPOSTS_H +#define LLVM_SUPPORT_SIGNPOSTS_H + +namespace llvm { +class SignpostEmitterImpl; +class Timer; + +/// Manages the emission of signposts into the recording method supported by +/// the OS. +class SignpostEmitter { + SignpostEmitterImpl *Impl; + +public: + SignpostEmitter(); + ~SignpostEmitter(); + + bool isEnabled() const; + + /// Begin a signposted interval for the given timer. + void startTimerInterval(Timer *T); + /// End a signposted interval for the given timer. + void endTimerInterval(Timer *T); +}; + +} // end namespace llvm + +#endif // ifndef LLVM_SUPPORT_SIGNPOSTS_H Index: llvm/trunk/lib/Support/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Support/CMakeLists.txt +++ llvm/trunk/lib/Support/CMakeLists.txt @@ -116,6 +116,7 @@ ScaledNumber.cpp ScopedPrinter.cpp SHA1.cpp + Signposts.cpp SmallPtrSet.cpp SmallVector.cpp SourceMgr.cpp Index: llvm/trunk/lib/Support/Signposts.cpp =================================================================== --- llvm/trunk/lib/Support/Signposts.cpp +++ llvm/trunk/lib/Support/Signposts.cpp @@ -0,0 +1,119 @@ +//===-- Signposts.cpp - Interval debug annotations ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Signposts.h" +#include "llvm/Support/Timer.h" + +#include "llvm/Config/config.h" +#if LLVM_SUPPORT_XCODE_SIGNPOSTS +#include "llvm/ADT/DenseMap.h" +#include +#endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS + +using namespace llvm; + +#if LLVM_SUPPORT_XCODE_SIGNPOSTS +namespace { +os_log_t *LogCreator() { + os_log_t *X = new os_log_t; + *X = os_log_create("org.llvm.signposts", OS_LOG_CATEGORY_POINTS_OF_INTEREST); + return X; +} +void LogDeleter(os_log_t *X) { + os_release(*X); + delete X; +} +} // end anonymous namespace + +namespace llvm { +class SignpostEmitterImpl { + using LogPtrTy = + std::unique_ptr>; + using LogTy = LogPtrTy::element_type; + + LogPtrTy SignpostLog; + DenseMap Signposts; + + LogTy &getLogger() const { return *SignpostLog; } + os_signpost_id_t getSignpostForTimer(const Timer *T) { + const auto &I = Signposts.find(T); + if (I != Signposts.end()) + return I->second; + + const auto &Inserted = Signposts.insert( + std::make_pair(T, os_signpost_id_make_with_pointer(getLogger(), T))); + return Inserted.first->second; + } + +public: + SignpostEmitterImpl() : SignpostLog(LogCreator(), LogDeleter), Signposts() {} + + bool isEnabled() const { return os_signpost_enabled(*SignpostLog); } + + void startTimerInterval(Timer *T) { + if (isEnabled()) { + // Both strings used here are required to be constant literal strings + os_signpost_interval_begin(getLogger(), getSignpostForTimer(T), + "Pass Timers", "Begin %s", + T->getName().c_str()); + } + } + + void endTimerInterval(Timer *T) { + if (isEnabled()) { + // Both strings used here are required to be constant literal strings + os_signpost_interval_end(getLogger(), getSignpostForTimer(T), + "Pass Timers", "End %s", T->getName().c_str()); + } + } +}; +} // end namespace llvm +#endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS + +#if LLVM_SUPPORT_XCODE_SIGNPOSTS +#define HAVE_ANY_SIGNPOST_IMPL 1 +#endif + +SignpostEmitter::SignpostEmitter() { +#if HAVE_ANY_SIGNPOST_IMPL + Impl = new SignpostEmitterImpl(); +#else // if HAVE_ANY_SIGNPOST_IMPL + Impl = nullptr; +#endif // if !HAVE_ANY_SIGNPOST_IMPL +} + +SignpostEmitter::~SignpostEmitter() { +#if HAVE_ANY_SIGNPOST_IMPL + delete Impl; +#endif // if HAVE_ANY_SIGNPOST_IMPL +} + +bool SignpostEmitter::isEnabled() const { +#if HAVE_ANY_SIGNPOST_IMPL + return Impl->isEnabled(); +#else + return false; +#endif // if !HAVE_ANY_SIGNPOST_IMPL +} + +void SignpostEmitter::startTimerInterval(Timer *T) { +#if HAVE_ANY_SIGNPOST_IMPL + if (Impl == nullptr) + return; + return Impl->startTimerInterval(T); +#endif // if !HAVE_ANY_SIGNPOST_IMPL +} + +void SignpostEmitter::endTimerInterval(Timer *T) { +#if HAVE_ANY_SIGNPOST_IMPL + if (Impl == nullptr) + return; + Impl->endTimerInterval(T); +#endif // if !HAVE_ANY_SIGNPOST_IMPL +} Index: llvm/trunk/lib/Support/Timer.cpp =================================================================== --- llvm/trunk/lib/Support/Timer.cpp +++ llvm/trunk/lib/Support/Timer.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Process.h" +#include "llvm/Support/Signposts.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include @@ -39,6 +40,9 @@ static ManagedStatic > TimerLock; +/// Allows llvm::Timer to emit signposts when supported. +static ManagedStatic Signposts; + namespace { static cl::opt TrackSpace("track-memory", cl::desc("Enable -time-passes memory " @@ -133,6 +137,7 @@ void Timer::startTimer() { assert(!Running && "Cannot start a running timer"); Running = Triggered = true; + Signposts->startTimerInterval(this); StartTime = TimeRecord::getCurrentTime(true); } @@ -141,6 +146,7 @@ Running = false; Time += TimeRecord::getCurrentTime(false); Time -= StartTime; + Signposts->endTimerInterval(this); } void Timer::clear() {