[llvm] r208945 - Add C API for thread yielding callback.

Chandler Carruth chandlerc at google.com
Thu May 15 19:49:36 PDT 2014


Just want to say, thanks for all the work figuring out the right shape for
this. =] This looks really, really nice.


On Thu, May 15, 2014 at 8:33 PM, Juergen Ributzka <juergen at apple.com> wrote:

> Author: ributzka
> Date: Thu May 15 21:33:15 2014
> New Revision: 208945
>
> URL: http://llvm.org/viewvc/llvm-project?rev=208945&view=rev
> Log:
> Add C API for thread yielding callback.
>
> Sometimes a LLVM compilation may take more time then a client would like to
> wait for. The problem is that it is not possible to safely suspend the LLVM
> thread from the outside. When the timing is bad it might be possible that
> the
> LLVM thread holds a global mutex and this would block any progress in any
> other
> thread.
>
> This commit adds a new yield callback function that can be registered with
> a
> context. LLVM will try to yield by calling this callback function, but
> there is
> no guaranteed frequency. LLVM will only do so if it can guarantee that
> suspending the thread won't block any forward progress in other LLVM
> contexts
> in the same process.
>
> Once the client receives the call back it can suspend the thread safely and
> resume it at another time.
>
> Related to <rdar://problem/16728690>
>
> Modified:
>     llvm/trunk/include/llvm-c/Core.h
>     llvm/trunk/include/llvm/IR/LLVMContext.h
>     llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp
>     llvm/trunk/lib/Analysis/LoopPass.cpp
>     llvm/trunk/lib/IR/Core.cpp
>     llvm/trunk/lib/IR/LLVMContext.cpp
>     llvm/trunk/lib/IR/LLVMContextImpl.cpp
>     llvm/trunk/lib/IR/LLVMContextImpl.h
>     llvm/trunk/lib/IR/LegacyPassManager.cpp
>     llvm/trunk/lib/IR/PassManager.cpp
>     llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
>
> Modified: llvm/trunk/include/llvm-c/Core.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/Core.h?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm-c/Core.h (original)
> +++ llvm/trunk/include/llvm-c/Core.h Thu May 15 21:33:15 2014
> @@ -467,6 +467,7 @@ void LLVMEnablePrettyStackTrace(void);
>   */
>
>  typedef void (*LLVMDiagnosticHandler)(LLVMDiagnosticInfoRef, void *);
> +typedef void (*LLVMYieldCallback)(LLVMContextRef, void *);
>
>  /**
>   * Create a new context.
> @@ -489,6 +490,14 @@ void LLVMContextSetDiagnosticHandler(LLV
>                                       void *DiagnosticContext);
>
>  /**
> + * Set the yield callback function for this context.
> + *
> + * @see LLVMContext::setYieldCallback()
> + */
> +void LLVMContextSetYieldCallback(LLVMContextRef C, LLVMYieldCallback
> Callback,
> +                                 void *OpaqueHandle);
> +
> +/**
>   * Destroy a context instance.
>   *
>   * This should be called for every call to LLVMContextCreate() or memory
>
> Modified: llvm/trunk/include/llvm/IR/LLVMContext.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/LLVMContext.h?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/LLVMContext.h (original)
> +++ llvm/trunk/include/llvm/IR/LLVMContext.h Thu May 15 21:33:15 2014
> @@ -72,6 +72,10 @@ public:
>    /// \see LLVMContext::diagnose.
>    typedef void (*DiagnosticHandlerTy)(const DiagnosticInfo &DI, void
> *Context);
>
> +  /// Defines the type of a yield callback.
> +  /// \see LLVMContext::setYieldCallback.
> +  typedef void (*YieldCallbackTy)(LLVMContext *Context, void
> *OpaqueHandle);
> +
>    /// setInlineAsmDiagnosticHandler - This method sets a handler that is
> invoked
>    /// when problems with inline asm are detected by the backend.  The
> first
>    /// argument is a function pointer and the second is a context pointer
> that
> @@ -118,6 +122,32 @@ public:
>    /// for RS_Error, "warning: " for RS_Warning, and "note: " for RS_Note.
>    void diagnose(const DiagnosticInfo &DI);
>
> +  /// \brief Registers a yield callback with the given context.
> +  ///
> +  /// The yield callback function may be called by LLVM to transfer
> control back
> +  /// to the client that invoked the LLVM compilation. This can be used
> to yield
> +  /// control of the thread, or perform periodic work needed by the
> client.
> +  /// There is no guaranteed frequency at which callbacks must occur; in
> fact,
> +  /// the client is not guaranteed to ever receive this callback. It is
> at the
> +  /// sole discretion of LLVM to do so and only if it can guarantee that
> +  /// suspending the thread won't block any forward progress in other LLVM
> +  /// contexts in the same process.
> +  ///
> +  /// At a suspend point, the state of the current LLVM context is
> intentionally
> +  /// undefined. No assumptions about it can or should be made. Only LLVM
> +  /// context API calls that explicitly state that they can be used
> during a
> +  /// yield callback are allowed to be used. Any other API calls into the
> +  /// context are not supported until the yield callback function returns
> +  /// control to LLVM. Other LLVM contexts are unaffected by this
> restriction.
> +  void setYieldCallback(YieldCallbackTy Callback, void *OpaqueHandle);
> +
> +  /// \brief Calls the yield callback (if applicable).
> +  ///
> +  /// This transfers control of the current thread back to the client,
> which may
> +  /// suspend the current thread. Only call this method when LLVM doesn't
> hold
> +  /// any global mutex or cannot block the execution in another LLVM
> context.
> +  void yield();
> +
>    /// emitError - Emit an error message to the currently installed error
> handler
>    /// with optional location information.  This function returns, so code
> should
>    /// be prepared to drop the erroneous construct on the floor and "not
> crash".
>
> Modified: llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp (original)
> +++ llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp Thu May 15 21:33:15
> 2014
> @@ -22,6 +22,7 @@
>  #include "llvm/IR/Function.h"
>  #include "llvm/IR/IntrinsicInst.h"
>  #include "llvm/IR/LegacyPassManagers.h"
> +#include "llvm/IR/LLVMContext.h"
>  #include "llvm/Support/CommandLine.h"
>  #include "llvm/Support/Debug.h"
>  #include "llvm/Support/Timer.h"
> @@ -145,8 +146,11 @@ bool CGPassManager::RunPassOnSCC(Pass *P
>         I != E; ++I) {
>      if (Function *F = (*I)->getFunction()) {
>        dumpPassInfo(P, EXECUTION_MSG, ON_FUNCTION_MSG, F->getName());
> -      TimeRegion PassTimer(getPassTimer(FPP));
> -      Changed |= FPP->runOnFunction(*F);
> +      {
> +        TimeRegion PassTimer(getPassTimer(FPP));
> +        Changed |= FPP->runOnFunction(*F);
> +      }
> +      F->getContext().yield();
>      }
>    }
>
>
> Modified: llvm/trunk/lib/Analysis/LoopPass.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopPass.cpp?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Analysis/LoopPass.cpp (original)
> +++ llvm/trunk/lib/Analysis/LoopPass.cpp Thu May 15 21:33:15 2014
> @@ -15,6 +15,7 @@
>
>  #include "llvm/Analysis/LoopPass.h"
>  #include "llvm/IR/IRPrintingPasses.h"
> +#include "llvm/IR/LLVMContext.h"
>  #include "llvm/Support/Debug.h"
>  #include "llvm/Support/Timer.h"
>  using namespace llvm;
> @@ -253,6 +254,8 @@ bool LPPassManager::runOnFunction(Functi
>
>          // Then call the regular verifyAnalysis functions.
>          verifyPreservedAnalysis(P);
> +
> +        F.getContext().yield();
>        }
>
>        removeNotPreservedAnalysis(P);
>
> Modified: llvm/trunk/lib/IR/Core.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Core.cpp?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/Core.cpp (original)
> +++ llvm/trunk/lib/IR/Core.cpp Thu May 15 21:33:15 2014
> @@ -89,6 +89,13 @@ void LLVMContextSetDiagnosticHandler(LLV
>        DiagnosticContext);
>  }
>
> +void LLVMContextSetYieldCallback(LLVMContextRef C, LLVMYieldCallback
> Callback,
> +                                 void *OpaqueHandle) {
> +  auto YieldCallback =
> +    LLVM_EXTENSION
> reinterpret_cast<LLVMContext::YieldCallbackTy>(Callback);
> +  unwrap(C)->setYieldCallback(YieldCallback, OpaqueHandle);
> +}
> +
>  void LLVMContextDispose(LLVMContextRef C) {
>    delete unwrap(C);
>  }
>
> Modified: llvm/trunk/lib/IR/LLVMContext.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LLVMContext.cpp?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/LLVMContext.cpp (original)
> +++ llvm/trunk/lib/IR/LLVMContext.cpp Thu May 15 21:33:15 2014
> @@ -115,6 +115,17 @@ void *LLVMContext::getDiagnosticContext(
>    return pImpl->DiagnosticContext;
>  }
>
> +void LLVMContext::setYieldCallback(YieldCallbackTy Callback, void
> *OpaqueHandle)
> +{
> +  pImpl->YieldCallback = Callback;
> +  pImpl->YieldOpaqueHandle = OpaqueHandle;
> +}
> +
> +void LLVMContext::yield() {
> +  if (pImpl->YieldCallback)
> +    pImpl->YieldCallback(this, pImpl->YieldOpaqueHandle);
> +}
> +
>  void LLVMContext::emitError(const Twine &ErrorStr) {
>    diagnose(DiagnosticInfoInlineAsm(ErrorStr));
>  }
>
> Modified: llvm/trunk/lib/IR/LLVMContextImpl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LLVMContextImpl.cpp?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/LLVMContextImpl.cpp (original)
> +++ llvm/trunk/lib/IR/LLVMContextImpl.cpp Thu May 15 21:33:15 2014
> @@ -41,6 +41,8 @@ LLVMContextImpl::LLVMContextImpl(LLVMCon
>    InlineAsmDiagContext = nullptr;
>    DiagnosticHandler = nullptr;
>    DiagnosticContext = nullptr;
> +  YieldCallback = nullptr;
> +  YieldOpaqueHandle = nullptr;
>    NamedStructTypesUniqueID = 0;
>  }
>
>
> Modified: llvm/trunk/lib/IR/LLVMContextImpl.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LLVMContextImpl.h?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/LLVMContextImpl.h (original)
> +++ llvm/trunk/lib/IR/LLVMContextImpl.h Thu May 15 21:33:15 2014
> @@ -242,6 +242,9 @@ public:
>    LLVMContext::DiagnosticHandlerTy DiagnosticHandler;
>    void *DiagnosticContext;
>
> +  LLVMContext::YieldCallbackTy YieldCallback;
> +  void *YieldOpaqueHandle;
> +
>    typedef DenseMap<DenseMapAPIntKeyInfo::KeyTy, ConstantInt *,
>                     DenseMapAPIntKeyInfo> IntMapTy;
>    IntMapTy IntConstants;
>
> Modified: llvm/trunk/lib/IR/LegacyPassManager.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LegacyPassManager.cpp?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/LegacyPassManager.cpp (original)
> +++ llvm/trunk/lib/IR/LegacyPassManager.cpp Thu May 15 21:33:15 2014
> @@ -12,6 +12,7 @@
>
>  //===----------------------------------------------------------------------===//
>
>
> +#include "llvm/IR/LLVMContext.h"
>  #include "llvm/IR/IRPrintingPasses.h"
>  #include "llvm/IR/LegacyPassManager.h"
>  #include "llvm/IR/LegacyPassManagers.h"
> @@ -1489,8 +1490,10 @@ bool FunctionPassManagerImpl::run(Functi
>    TimingInfo::createTheTimeInfo();
>
>    initializeAllAnalysisInfo();
> -  for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index)
> +  for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) {
>      Changed |= getContainedManager(Index)->runOnFunction(F);
> +    F.getContext().yield();
> +  }
>
>    for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index)
>      getContainedManager(Index)->cleanup();
> @@ -1723,8 +1726,10 @@ bool PassManagerImpl::run(Module &M) {
>    }
>
>    initializeAllAnalysisInfo();
> -  for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index)
> +  for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) {
>      Changed |= getContainedManager(Index)->runOnModule(M);
> +    M.getContext().yield();
> +  }
>
>    for (SmallVectorImpl<ImmutablePass *>::const_iterator I = IPV.begin(),
>         E = IPV.end(); I != E; ++I) {
>
> Modified: llvm/trunk/lib/IR/PassManager.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/PassManager.cpp?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/PassManager.cpp (original)
> +++ llvm/trunk/lib/IR/PassManager.cpp Thu May 15 21:33:15 2014
> @@ -8,6 +8,7 @@
>
>  //===----------------------------------------------------------------------===//
>
>  #include "llvm/ADT/STLExtras.h"
> +#include "llvm/IR/LLVMContext.h"
>  #include "llvm/IR/PassManager.h"
>  #include "llvm/Support/CommandLine.h"
>  #include "llvm/Support/Debug.h"
> @@ -32,6 +33,8 @@ PreservedAnalyses ModulePassManager::run
>      if (AM)
>        AM->invalidate(M, PassPA);
>      PA.intersect(std::move(PassPA));
> +
> +    M->getContext().yield();
>    }
>
>    if (DebugPM)
> @@ -92,6 +95,8 @@ PreservedAnalyses FunctionPassManager::r
>      if (AM)
>        AM->invalidate(F, PassPA);
>      PA.intersect(std::move(PassPA));
> +
> +    F->getContext().yield();
>    }
>
>    if (DebugPM)
>
> Modified: llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp?rev=208945&r1=208944&r2=208945&view=diff
>
> ==============================================================================
> --- llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp (original)
> +++ llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp Thu May
> 15 21:33:15 2014
> @@ -28,6 +28,7 @@ using namespace llvm;
>
>  static bool didCallAllocateCodeSection;
>  static bool didAllocateCompactUnwindSection;
> +static bool didCallYield;
>
>  static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
>                                               unsigned alignment,
> @@ -64,6 +65,10 @@ static void roundTripDestroy(void *objec
>    delete static_cast<SectionMemoryManager*>(object);
>  }
>
> +static void yield(LLVMContextRef, void *) {
> +  didCallYield = true;
> +}
> +
>  namespace {
>
>  // memory manager to test reserve allocation space callback
> @@ -142,6 +147,7 @@ protected:
>    virtual void SetUp() {
>      didCallAllocateCodeSection = false;
>      didAllocateCompactUnwindSection = false;
> +    didCallYield = false;
>      Module = 0;
>      Function = 0;
>      Engine = 0;
> @@ -429,3 +435,24 @@ TEST_F(MCJITCAPITest, reserve_allocation
>    EXPECT_TRUE(MM->UsedCodeSize > 0);
>    EXPECT_TRUE(MM->UsedDataSizeRW > 0);
>  }
> +
> +TEST_F(MCJITCAPITest, yield) {
> +  SKIP_UNSUPPORTED_PLATFORM;
> +
> +  buildSimpleFunction();
> +  buildMCJITOptions();
> +  buildMCJITEngine();
> +  LLVMContextRef C = LLVMGetGlobalContext();
> +  LLVMContextSetYieldCallback(C, yield, NULL);
> +  buildAndRunPasses();
> +
> +  union {
> +    void *raw;
> +    int (*usable)();
> +  } functionPointer;
> +  functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
> +
> +  EXPECT_EQ(42, functionPointer.usable());
> +  EXPECT_TRUE(didCallYield);
> +}
> +
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140515/136dd45c/attachment.html>


More information about the llvm-commits mailing list