<commit_before>//===- CorrelatedValuePropagation.cpp - Propagate CFG-derived info --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Correlated Value Propagation pass.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "correlated-value-propagation"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/Support/CFG.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;

STATISTIC(NumPhis,      "Number of phis propagated");
STATISTIC(NumSelects,   "Number of selects propagated");
STATISTIC(NumMemAccess, "Number of memory access targets propagated");
STATISTIC(NumCmps,      "Number of comparisons propagated");

namespace {
  class CorrelatedValuePropagation : public FunctionPass {
    LazyValueInfo *LVI;

    bool processSelect(SelectInst *SI);
    bool processPHI(PHINode *P);
    bool processMemAccess(Instruction *I);
    bool processCmp(CmpInst *C);

  public:
    static char ID;
    CorrelatedValuePropagation(): FunctionPass(ID) {
     initializeCorrelatedValuePropagationPass(*PassRegistry::getPassRegistry());
    }

    bool runOnFunction(Function &F);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<LazyValueInfo>();
    }
  };
}

char CorrelatedValuePropagation::ID = 0;
INITIALIZE_PASS_BEGIN(CorrelatedValuePropagation, "correlated-propagation",
                "Value Propagation", false, false)
INITIALIZE_PASS_DEPENDENCY(LazyValueInfo)
INITIALIZE_PASS_END(CorrelatedValuePropagation, "correlated-propagation",
                "Value Propagation", false, false)

// Public interface to the Value Propagation pass
Pass *llvm::createCorrelatedValuePropagationPass() {
  return new CorrelatedValuePropagation();
}

bool CorrelatedValuePropagation::processSelect(SelectInst *S) {
  if (S->getType()->isVectorTy()) return false;
  if (isa<Constant>(S->getOperand(0))) return false;

  Constant *C = LVI->getConstant(S->getOperand(0), S->getParent());
  if (!C) return false;

  ConstantInt *CI = dyn_cast<ConstantInt>(C);
  if (!CI) return false;

  S->replaceAllUsesWith(S->getOperand(CI->isOne() ? 1 : 2));
  S->eraseFromParent();

  ++NumSelects;

  return true;
}

bool CorrelatedValuePropagation::processPHI(PHINode *P) {
  bool Changed = false;

  BasicBlock *BB = P->getParent();
  for (unsigned i = 0, e = P->getNumIncomingValues(); i < e; ++i) {
    Value *Incoming = P->getIncomingValue(i);
    if (isa<Constant>(Incoming)) continue;

    Constant *C = LVI->getConstantOnEdge(P->getIncomingValue(i),
                                         P->getIncomingBlock(i),
                                         BB);
    if (!C) continue;

    P->setIncomingValue(i, C);
    Changed = true;
  }

  if (Value *ConstVal = P->hasConstantValue()) {
    P->replaceAllUsesWith(ConstVal);
    P->eraseFromParent();
    Changed = true;
  }

  ++NumPhis;

  return Changed;
}

bool CorrelatedValuePropagation::processMemAccess(Instruction *I) {
  Value *Pointer = 0;
  if (LoadInst *L = dyn_cast<LoadInst>(I))
    Pointer = L->getPointerOperand();
  else
    Pointer = cast<StoreInst>(I)->getPointerOperand();

  if (isa<Constant>(Pointer)) return false;

  Constant *C = LVI->getConstant(Pointer, I->getParent());
  if (!C) return false;

  ++NumMemAccess;
  I->replaceUsesOfWith(Pointer, C);
  return true;
}

/// processCmp - If the value of this comparison could be determined locally,
/// constant propagation would already have figured it out.  Instead, walk
/// the predecessors and statically evaluate the comparison based on information
/// available on that edge.  If a given static evaluation is true on ALL
/// incoming edges, then it's true universally and we can simplify the compare.
bool CorrelatedValuePropagation::processCmp(CmpInst *C) {
  Value *Op0 = C->getOperand(0);
  if (isa<Instruction>(Op0) &&
      cast<Instruction>(Op0)->getParent() == C->getParent())
    return false;

  Constant *Op1 = dyn_cast<Constant>(C->getOperand(1));
  if (!Op1) return false;

  pred_iterator PI = pred_begin(C->getParent()), PE = pred_end(C->getParent());
  if (PI == PE) return false;

  LazyValueInfo::Tristate Result = LVI->getPredicateOnEdge(C->getPredicate(),
                                    C->getOperand(0), Op1, *PI, C->getParent());
  if (Result == LazyValueInfo::Unknown) return false;

  ++PI;
  while (PI != PE) {
    LazyValueInfo::Tristate Res = LVI->getPredicateOnEdge(C->getPredicate(),
                                    C->getOperand(0), Op1, *PI, C->getParent());
    if (Res != Result) return false;
    ++PI;
  }

  ++NumCmps;

  if (Result == LazyValueInfo::True)
    C->replaceAllUsesWith(ConstantInt::getTrue(C->getContext()));
  else
    C->replaceAllUsesWith(ConstantInt::getFalse(C->getContext()));

  C->eraseFromParent();

  return true;
}

bool CorrelatedValuePropagation::runOnFunction(Function &F) {
  LVI = &getAnalysis<LazyValueInfo>();

  bool FnChanged = false;

  // Perform a depth-first walk of the CFG so that we don't waste time
  // optimizing unreachable blocks.
  for (df_iterator<BasicBlock*> FI = df_begin(&F.getEntryBlock()),
       FE = df_end(&F.getEntryBlock()); FI != FE; ++FI) {
    bool BBChanged = false;
    for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) {
      Instruction *II = BI++;
      switch (II->getOpcode()) {
      case Instruction::Select:
        BBChanged |= processSelect(cast<SelectInst>(II));
        break;
      case Instruction::PHI:
        BBChanged |= processPHI(cast<PHINode>(II));
        break;
      case Instruction::ICmp:
      case Instruction::FCmp:
        BBChanged |= processCmp(cast<CmpInst>(II));
        break;
      case Instruction::Load:
      case Instruction::Store:
        BBChanged |= processMemAccess(II);
        break;
      }
    }

    // Propagating correlated values might leave cruft around.
    // Try to clean it up before we continue.
    if (BBChanged)
      SimplifyInstructionsInBlock(*FI);

    FnChanged |= BBChanged;
  }

  return FnChanged;
}
<commit_msg>Give up on doing in-line instruction simplification during correlated value propagation.  Instruction simplification needs to be guaranteed never to be run on an unreachable block.  However, earlier block simplifications may have changed the CFG to make block that were reachable when we began our iteration unreachable by the time we try to simplify them. (Note that this also means that our depth-first iterators were potentially being invalidated).<commit_after>//===- CorrelatedValuePropagation.cpp - Propagate CFG-derived info --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Correlated Value Propagation pass.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "correlated-value-propagation"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/Support/CFG.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;

STATISTIC(NumPhis,      "Number of phis propagated");
STATISTIC(NumSelects,   "Number of selects propagated");
STATISTIC(NumMemAccess, "Number of memory access targets propagated");
STATISTIC(NumCmps,      "Number of comparisons propagated");

namespace {
  class CorrelatedValuePropagation : public FunctionPass {
    LazyValueInfo *LVI;

    bool processSelect(SelectInst *SI);
    bool processPHI(PHINode *P);
    bool processMemAccess(Instruction *I);
    bool processCmp(CmpInst *C);

  public:
    static char ID;
    CorrelatedValuePropagation(): FunctionPass(ID) {
     initializeCorrelatedValuePropagationPass(*PassRegistry::getPassRegistry());
    }

    bool runOnFunction(Function &F);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<LazyValueInfo>();
    }
  };
}

char CorrelatedValuePropagation::ID = 0;
INITIALIZE_PASS_BEGIN(CorrelatedValuePropagation, "correlated-propagation",
                "Value Propagation", false, false)
INITIALIZE_PASS_DEPENDENCY(LazyValueInfo)
INITIALIZE_PASS_END(CorrelatedValuePropagation, "correlated-propagation",
                "Value Propagation", false, false)

// Public interface to the Value Propagation pass
Pass *llvm::createCorrelatedValuePropagationPass() {
  return new CorrelatedValuePropagation();
}

bool CorrelatedValuePropagation::processSelect(SelectInst *S) {
  if (S->getType()->isVectorTy()) return false;
  if (isa<Constant>(S->getOperand(0))) return false;

  Constant *C = LVI->getConstant(S->getOperand(0), S->getParent());
  if (!C) return false;

  ConstantInt *CI = dyn_cast<ConstantInt>(C);
  if (!CI) return false;

  S->replaceAllUsesWith(S->getOperand(CI->isOne() ? 1 : 2));
  S->eraseFromParent();

  ++NumSelects;

  return true;
}

bool CorrelatedValuePropagation::processPHI(PHINode *P) {
  bool Changed = false;

  BasicBlock *BB = P->getParent();
  for (unsigned i = 0, e = P->getNumIncomingValues(); i < e; ++i) {
    Value *Incoming = P->getIncomingValue(i);
    if (isa<Constant>(Incoming)) continue;

    Constant *C = LVI->getConstantOnEdge(P->getIncomingValue(i),
                                         P->getIncomingBlock(i),
                                         BB);
    if (!C) continue;

    P->setIncomingValue(i, C);
    Changed = true;
  }

  if (Value *ConstVal = P->hasConstantValue()) {
    P->replaceAllUsesWith(ConstVal);
    P->eraseFromParent();
    Changed = true;
  }

  ++NumPhis;

  return Changed;
}

bool CorrelatedValuePropagation::processMemAccess(Instruction *I) {
  Value *Pointer = 0;
  if (LoadInst *L = dyn_cast<LoadInst>(I))
    Pointer = L->getPointerOperand();
  else
    Pointer = cast<StoreInst>(I)->getPointerOperand();

  if (isa<Constant>(Pointer)) return false;

  Constant *C = LVI->getConstant(Pointer, I->getParent());
  if (!C) return false;

  ++NumMemAccess;
  I->replaceUsesOfWith(Pointer, C);
  return true;
}

/// processCmp - If the value of this comparison could be determined locally,
/// constant propagation would already have figured it out.  Instead, walk
/// the predecessors and statically evaluate the comparison based on information
/// available on that edge.  If a given static evaluation is true on ALL
/// incoming edges, then it's true universally and we can simplify the compare.
bool CorrelatedValuePropagation::processCmp(CmpInst *C) {
  Value *Op0 = C->getOperand(0);
  if (isa<Instruction>(Op0) &&
      cast<Instruction>(Op0)->getParent() == C->getParent())
    return false;

  Constant *Op1 = dyn_cast<Constant>(C->getOperand(1));
  if (!Op1) return false;

  pred_iterator PI = pred_begin(C->getParent()), PE = pred_end(C->getParent());
  if (PI == PE) return false;

  LazyValueInfo::Tristate Result = LVI->getPredicateOnEdge(C->getPredicate(),
                                    C->getOperand(0), Op1, *PI, C->getParent());
  if (Result == LazyValueInfo::Unknown) return false;

  ++PI;
  while (PI != PE) {
    LazyValueInfo::Tristate Res = LVI->getPredicateOnEdge(C->getPredicate(),
                                    C->getOperand(0), Op1, *PI, C->getParent());
    if (Res != Result) return false;
    ++PI;
  }

  ++NumCmps;

  if (Result == LazyValueInfo::True)
    C->replaceAllUsesWith(ConstantInt::getTrue(C->getContext()));
  else
    C->replaceAllUsesWith(ConstantInt::getFalse(C->getContext()));

  C->eraseFromParent();

  return true;
}

bool CorrelatedValuePropagation::runOnFunction(Function &F) {
  LVI = &getAnalysis<LazyValueInfo>();

  bool FnChanged = false;

  for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
    bool BBChanged = false;
    for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) {
      Instruction *II = BI++;
      switch (II->getOpcode()) {
      case Instruction::Select:
        BBChanged |= processSelect(cast<SelectInst>(II));
        break;
      case Instruction::PHI:
        BBChanged |= processPHI(cast<PHINode>(II));
        break;
      case Instruction::ICmp:
      case Instruction::FCmp:
        BBChanged |= processCmp(cast<CmpInst>(II));
        break;
      case Instruction::Load:
      case Instruction::Store:
        BBChanged |= processMemAccess(II);
        break;
      }
    }

    FnChanged |= BBChanged;
  }

  return FnChanged;
}
<|endoftext|>


<commit_before>// Copyright 2009 Minor Gordon.
// This source comes from the XtreemFS project. It is licensed under the GPLv2 (see COPYING for terms and conditions).

#include "org/xtreemfs/client/proxy.h"
#include "policy_container.h"
#include "platform_exception_event.h"
using namespace org::xtreemfs::client;

#include "org/xtreemfs/interfaces/constants.h"

#include <algorithm>

#ifdef _WIN32
#include "yield/platform/windows.h"
#define ETIMEDOUT WSAETIMEDOUT
#else
#include <errno.h>
#endif

Proxy::Proxy( const YIELD::URI& uri, uint16_t default_oncrpc_port )
  : uri( uri )
{
  ssl_context = NULL;
  log = NULL;
  init( default_oncrpc_port );
}

Proxy::Proxy( const YIELD::URI& uri, YIELD::Log& log, uint16_t default_oncrpc_port )
  : uri( uri ), log( &log )
{
  ssl_context = NULL;
  init( default_oncrpc_port );
}

Proxy::Proxy( const YIELD::URI& uri, YIELD::SSLContext& ssl_context, uint16_t default_oncrpcs_port )
: uri( uri ), ssl_context( &ssl_context )
{
  log = NULL;
  init( default_oncrpcs_port );
}

Proxy::Proxy( const YIELD::URI& uri, YIELD::SSLContext& ssl_context, YIELD::Log& log, uint16_t default_oncrpcs_port )
: uri( uri ), ssl_context( &ssl_context ), log( &log )
{
  init( default_oncrpcs_port );
}

void Proxy::init( uint16_t default_port )
{
  peer_sockaddr = this->uri;

  if ( this->uri.get_port() == 0 )
    this->uri.set_port( default_port );

  policies = new PolicyContainer;

  flags = PROXY_DEFAULT_FLAGS;
  reconnect_tries_max = PROXY_DEFAULT_RECONNECT_TRIES_MAX;
  operation_timeout_ms = PROXY_DEFAULT_OPERATION_TIMEOUT_MS;

  conn = NULL;

  org::xtreemfs::interfaces::Exceptions().registerObjectFactories( object_factories );
}

Proxy::~Proxy()
{
  delete policies;
  delete conn;
  YIELD::Object::decRef( ssl_context );
  YIELD::Object::decRef( log );
}

void Proxy::handleEvent( YIELD::Event& ev )
{
  switch ( ev.get_type_id() )
  {
    case YIELD_OBJECT_TYPE_ID( YIELD::StageStartupEvent ):
    case YIELD_OBJECT_TYPE_ID( YIELD::StageShutdownEvent ): YIELD::Object::decRef( ev ); break;

    default:
    {
      switch ( ev.get_general_type() )
      {
        case YIELD::Object::REQUEST:
        {
          YIELD::Request& req = static_cast<YIELD::Request&>( ev );
          if ( ( flags & PROXY_FLAG_PRINT_OPERATIONS ) == PROXY_FLAG_PRINT_OPERATIONS )
          {
            YIELD::PrettyPrintOutputStream pretty_print_output_stream( std::cout );
            pretty_print_output_stream.writeObject( YIELD::PrettyPrintOutputStream::Declaration( req.get_type_name() ), req );
          }

          try
          {
            org::xtreemfs::interfaces::UserCredentials user_credentials;
            policies->getCurrentUserCredentials( user_credentials );
            YIELD::ONCRPCRequest oncrpc_req( YIELD::Object::incRef( req ), object_factories, org::xtreemfs::interfaces::ONCRPC_AUTH_FLAVOR, &user_credentials );

            uint8_t reconnect_tries_left = reconnect_tries_max;
            if ( conn == NULL )
              reconnect_tries_left = reconnect( reconnect_tries_left );

            uint64_t remaining_operation_timeout_ms = operation_timeout_ms;
            if ( operation_timeout_ms == static_cast<uint64_t>( -1 ) || ssl_context != NULL )
              conn->setBlocking();
            else
              conn->setBlocking();

            bool have_written = false;

            for ( ;; )
            {
              if ( !have_written )
              {
                if ( oncrpc_req.serialize( *conn ) )
                {
                  have_written = true;
                  continue;
                }
              }
              else
              {
                if ( oncrpc_req.deserialize( *conn ) )
                {
                  req.respond( static_cast<YIELD::Event&>( YIELD::Object::incRef( *oncrpc_req.getInBody() ) ) );
                  YIELD::Object::decRef( req );
                  return;
                }
              }

              if ( YIELD::Socket::WOULDBLOCK() )
              {
                if ( remaining_operation_timeout_ms > 0 )
                {
                  fd_event_queue.toggleSocketEvent( *conn, conn, have_written, !have_written );
                  double start_epoch_time_ms = YIELD::Time::getCurrentUnixTimeMS();
                  YIELD::FDEvent* fd_event = static_cast<YIELD::FDEvent*>( fd_event_queue.timed_dequeue( static_cast<YIELD::timeout_ns_t>( remaining_operation_timeout_ms ) * NS_IN_MS ) );
                  if ( fd_event )
                  {
                    if ( fd_event->error_code == 0 )
                      remaining_operation_timeout_ms -= std::min( static_cast<uint64_t>( YIELD::Time::getCurrentUnixTimeMS() - start_epoch_time_ms ), remaining_operation_timeout_ms );
                    else
                      reconnect_tries_left = reconnect( reconnect_tries_left );
                  }
                  else
                    throwExceptionEvent( new PlatformExceptionEvent( ETIMEDOUT ) );
                }
                else
                  throwExceptionEvent( new PlatformExceptionEvent( ETIMEDOUT ) );
              }
              else
                reconnect_tries_left = reconnect( reconnect_tries_left );
            }
          }
          catch ( YIELD::ExceptionEvent* exc_ev )
          {
            req.respond( *exc_ev );
            YIELD::Object::decRef( req );
          }
        }
        break;

        default: YIELD::DebugBreak(); break;
      }
    }
    break;
  }
}

uint8_t Proxy::reconnect( uint8_t reconnect_tries_left )
{
  if ( conn != NULL ) // This is a reconnect, not the first connect
  {
    fd_event_queue.detachSocket( *conn, conn );
    conn->close();
    delete conn;
    conn = NULL;
  }

  while( reconnect_tries_left == static_cast<uint8_t>( -1 ) ||
         --reconnect_tries_left > 0 )
  {
    // Create the conn object based on the URI type
    if ( ssl_context == NULL )
      conn = new YIELD::TCPSocket;
    else
      conn = new YIELD::SSLSocket( *ssl_context );

    // Attach the socket to the fd_event_queue even if we're doing a blocking connect, in case a later read/write is non-blocking
    fd_event_queue.attachSocket( *conn, conn, false, false ); // Attach without read or write notifications enabled

    // Now try the actual connect
    if ( operation_timeout_ms == static_cast<uint64_t>( -1 ) || ssl_context != NULL ) // Blocking
    {
      conn->setBlocking();
      if ( conn->connect( peer_sockaddr ) )
        return reconnect_tries_left;
    }
    else // Non-blocking/timed
    {
      uint64_t remaining_operation_timeout_ms = operation_timeout_ms;
      conn->setNonBlocking();

      if ( conn->connect( peer_sockaddr ) )
        break;
      else if ( YIELD::Socket::WOULDBLOCK() )
      {
        fd_event_queue.toggleSocketEvent( *conn, conn, false, true ); // Write readiness = the connect() operation is complete
        double start_epoch_time_ms = YIELD::Time::getCurrentUnixTimeMS();
        YIELD::FDEvent* fd_event = static_cast<YIELD::FDEvent*>( fd_event_queue.timed_dequeue( static_cast<YIELD::timeout_ns_t>( remaining_operation_timeout_ms ) * NS_IN_MS ) );
        if ( fd_event && fd_event->error_code == 0 && conn->connect( peer_sockaddr ) )
        {
          fd_event_queue.toggleSocketEvent( *conn, conn, false, false );
          return reconnect_tries_left;
        }
        else
        {
          remaining_operation_timeout_ms -= std::min( static_cast<uint64_t>( YIELD::Time::getCurrentUnixTimeMS() - start_epoch_time_ms ), remaining_operation_timeout_ms );
          if ( remaining_operation_timeout_ms == 0 ) { reconnect_tries_left = 0; break; }
        }
      }
    }

    // Clear the connection state for the next try
    fd_event_queue.detachSocket( *conn, conn );
    conn->close();
    delete conn;
    conn = NULL;
  }

  unsigned long error_code = YIELD::PlatformException::errno_();
  if ( error_code == 0 )
    error_code = ETIMEDOUT;
  throw new PlatformExceptionEvent( error_code );
}

void Proxy::throwExceptionEvent( YIELD::ExceptionEvent* exc_ev )
{
  if ( conn )
  {
    fd_event_queue.detachSocket( *conn, conn );
    conn->close();
    delete conn;
    conn = NULL;
  }

  throw exc_ev;
}
<commit_msg>client: Proxy: small bug fix<commit_after>// Copyright 2009 Minor Gordon.
// This source comes from the XtreemFS project. It is licensed under the GPLv2 (see COPYING for terms and conditions).

#include "org/xtreemfs/client/proxy.h"
#include "policy_container.h"
#include "platform_exception_event.h"
using namespace org::xtreemfs::client;

#include "org/xtreemfs/interfaces/constants.h"

#include <algorithm>

#ifdef _WIN32
#include "yield/platform/windows.h"
#define ETIMEDOUT WSAETIMEDOUT
#else
#include <errno.h>
#endif

Proxy::Proxy( const YIELD::URI& uri, uint16_t default_oncrpc_port )
  : uri( uri )
{
  ssl_context = NULL;
  log = NULL;
  init( default_oncrpc_port );
}

Proxy::Proxy( const YIELD::URI& uri, YIELD::Log& log, uint16_t default_oncrpc_port )
  : uri( uri ), log( &log )
{
  ssl_context = NULL;
  init( default_oncrpc_port );
}

Proxy::Proxy( const YIELD::URI& uri, YIELD::SSLContext& ssl_context, uint16_t default_oncrpcs_port )
: uri( uri ), ssl_context( &ssl_context )
{
  log = NULL;
  init( default_oncrpcs_port );
}

Proxy::Proxy( const YIELD::URI& uri, YIELD::SSLContext& ssl_context, YIELD::Log& log, uint16_t default_oncrpcs_port )
: uri( uri ), ssl_context( &ssl_context ), log( &log )
{
  init( default_oncrpcs_port );
}

void Proxy::init( uint16_t default_port )
{
  if ( this->uri.get_port() == 0 )
    this->uri.set_port( default_port );

  peer_sockaddr = this->uri;

  policies = new PolicyContainer;

  flags = PROXY_DEFAULT_FLAGS;
  reconnect_tries_max = PROXY_DEFAULT_RECONNECT_TRIES_MAX;
  operation_timeout_ms = PROXY_DEFAULT_OPERATION_TIMEOUT_MS;

  conn = NULL;

  org::xtreemfs::interfaces::Exceptions().registerObjectFactories( object_factories );
}

Proxy::~Proxy()
{
  delete policies;
  delete conn;
  YIELD::Object::decRef( ssl_context );
  YIELD::Object::decRef( log );
}

void Proxy::handleEvent( YIELD::Event& ev )
{
  switch ( ev.get_type_id() )
  {
    case YIELD_OBJECT_TYPE_ID( YIELD::StageStartupEvent ):
    case YIELD_OBJECT_TYPE_ID( YIELD::StageShutdownEvent ): YIELD::Object::decRef( ev ); break;

    default:
    {
      switch ( ev.get_general_type() )
      {
        case YIELD::Object::REQUEST:
        {
          YIELD::Request& req = static_cast<YIELD::Request&>( ev );
          if ( ( flags & PROXY_FLAG_PRINT_OPERATIONS ) == PROXY_FLAG_PRINT_OPERATIONS )
          {
            YIELD::PrettyPrintOutputStream pretty_print_output_stream( std::cout );
            pretty_print_output_stream.writeObject( YIELD::PrettyPrintOutputStream::Declaration( req.get_type_name() ), req );
          }

          try
          {
            org::xtreemfs::interfaces::UserCredentials user_credentials;
            policies->getCurrentUserCredentials( user_credentials );
            YIELD::ONCRPCRequest oncrpc_req( YIELD::Object::incRef( req ), object_factories, org::xtreemfs::interfaces::ONCRPC_AUTH_FLAVOR, &user_credentials );

            uint8_t reconnect_tries_left = reconnect_tries_max;
            if ( conn == NULL )
              reconnect_tries_left = reconnect( reconnect_tries_left );

            uint64_t remaining_operation_timeout_ms = operation_timeout_ms;
            if ( operation_timeout_ms == static_cast<uint64_t>( -1 ) || ssl_context != NULL )
              conn->setBlocking();
            else
              conn->setBlocking();

            bool have_written = false;

            for ( ;; )
            {
              if ( !have_written )
              {
                if ( oncrpc_req.serialize( *conn ) )
                {
                  have_written = true;
                  continue;
                }
              }
              else
              {
                if ( oncrpc_req.deserialize( *conn ) )
                {
                  req.respond( static_cast<YIELD::Event&>( YIELD::Object::incRef( *oncrpc_req.getInBody() ) ) );
                  YIELD::Object::decRef( req );
                  return;
                }
              }

              if ( YIELD::Socket::WOULDBLOCK() )
              {
                if ( remaining_operation_timeout_ms > 0 )
                {
                  fd_event_queue.toggleSocketEvent( *conn, conn, have_written, !have_written );
                  double start_epoch_time_ms = YIELD::Time::getCurrentUnixTimeMS();
                  YIELD::FDEvent* fd_event = static_cast<YIELD::FDEvent*>( fd_event_queue.timed_dequeue( static_cast<YIELD::timeout_ns_t>( remaining_operation_timeout_ms ) * NS_IN_MS ) );
                  if ( fd_event )
                  {
                    if ( fd_event->error_code == 0 )
                      remaining_operation_timeout_ms -= std::min( static_cast<uint64_t>( YIELD::Time::getCurrentUnixTimeMS() - start_epoch_time_ms ), remaining_operation_timeout_ms );
                    else
                      reconnect_tries_left = reconnect( reconnect_tries_left );
                  }
                  else
                    throwExceptionEvent( new PlatformExceptionEvent( ETIMEDOUT ) );
                }
                else
                  throwExceptionEvent( new PlatformExceptionEvent( ETIMEDOUT ) );
              }
              else
                reconnect_tries_left = reconnect( reconnect_tries_left );
            }
          }
          catch ( YIELD::ExceptionEvent* exc_ev )
          {
            req.respond( *exc_ev );
            YIELD::Object::decRef( req );
          }
        }
        break;

        default: YIELD::DebugBreak(); break;
      }
    }
    break;
  }
}

uint8_t Proxy::reconnect( uint8_t reconnect_tries_left )
{
  if ( conn != NULL ) // This is a reconnect, not the first connect
  {
    fd_event_queue.detachSocket( *conn, conn );
    conn->close();
    delete conn;
    conn = NULL;
  }

  while( reconnect_tries_left == static_cast<uint8_t>( -1 ) ||
         --reconnect_tries_left > 0 )
  {
    // Create the conn object based on the URI type
    if ( ssl_context == NULL )
      conn = new YIELD::TCPSocket;
    else
      conn = new YIELD::SSLSocket( *ssl_context );

    // Attach the socket to the fd_event_queue even if we're doing a blocking connect, in case a later read/write is non-blocking
    fd_event_queue.attachSocket( *conn, conn, false, false ); // Attach without read or write notifications enabled

    // Now try the actual connect
    if ( operation_timeout_ms == static_cast<uint64_t>( -1 ) || ssl_context != NULL ) // Blocking
    {
      conn->setBlocking();
      if ( conn->connect( peer_sockaddr ) )
        return reconnect_tries_left;
    }
    else // Non-blocking/timed
    {
      uint64_t remaining_operation_timeout_ms = operation_timeout_ms;
      conn->setNonBlocking();

      if ( conn->connect( peer_sockaddr ) )
        break;
      else if ( YIELD::Socket::WOULDBLOCK() )
      {
        fd_event_queue.toggleSocketEvent( *conn, conn, false, true ); // Write readiness = the connect() operation is complete
        double start_epoch_time_ms = YIELD::Time::getCurrentUnixTimeMS();
        YIELD::FDEvent* fd_event = static_cast<YIELD::FDEvent*>( fd_event_queue.timed_dequeue( static_cast<YIELD::timeout_ns_t>( remaining_operation_timeout_ms ) * NS_IN_MS ) );
        if ( fd_event && fd_event->error_code == 0 && conn->connect( peer_sockaddr ) )
        {
          fd_event_queue.toggleSocketEvent( *conn, conn, false, false );
          return reconnect_tries_left;
        }
        else
        {
          remaining_operation_timeout_ms -= std::min( static_cast<uint64_t>( YIELD::Time::getCurrentUnixTimeMS() - start_epoch_time_ms ), remaining_operation_timeout_ms );
          if ( remaining_operation_timeout_ms == 0 ) { reconnect_tries_left = 0; break; }
        }
      }
    }

    // Clear the connection state for the next try
    fd_event_queue.detachSocket( *conn, conn );
    conn->close();
    delete conn;
    conn = NULL;
  }

  unsigned long error_code = YIELD::PlatformException::errno_();
  if ( error_code == 0 )
    error_code = ETIMEDOUT;
  throw new PlatformExceptionEvent( error_code );
}

void Proxy::throwExceptionEvent( YIELD::ExceptionEvent* exc_ev )
{
  if ( conn )
  {
    fd_event_queue.detachSocket( *conn, conn );
    conn->close();
    delete conn;
    conn = NULL;
  }

  throw exc_ev;
}
<|endoftext|>


<commit_before>#pragma once

#include <iostream>
#include <cmath>

// ----------------------------------------------------------------------

namespace acmacs
{
    constexpr double sqr(double value) { return value * value; }

    class LineDefinedByEquation
    {
     public:
        LineDefinedByEquation() = default;
        LineDefinedByEquation(double slope, double intercept) : slope_{slope}, intercept_{intercept} {}

        constexpr double slope() const { return slope_; }
        constexpr double intercept() const { return intercept_; }

        template <typename V> double distance_with_direction(const V& vect) const
            {
                return (slope() * vect[0] - vect[1] + intercept()) / std::sqrt(sqr(slope()) + 1);
            }

        template <typename V> double distance_to(const V& vect) const { return std::abs(distance_with_direction(vect)); }

        template <typename V> V project_on(const V& source) const
            {
                return source;
            }

     private:
        double slope_ = 1;
        double intercept_ = 0;

    }; // class LineDefinedByEquation

    inline std::ostream& operator<<(std::ostream& out, const LineDefinedByEquation& line) { return out << "Line(slope:" << line.slope() << ", intercept:" << line.intercept() << ')'; }

} // namespace acmacs

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>acmacs::LineDefinedByEquation::project_on()<commit_after>#pragma once

#include <iostream>
#include <cmath>

// ----------------------------------------------------------------------

namespace acmacs
{
    constexpr double sqr(double value) { return value * value; }

    class LineDefinedByEquation
    {
     public:
        LineDefinedByEquation() = default;
        LineDefinedByEquation(double slope, double intercept) : slope_{slope}, intercept_{intercept} {}

        constexpr double slope() const { return slope_; }
        constexpr double intercept() const { return intercept_; }

          // https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
        template <typename V> double distance_with_direction(const V& vect) const
            {
                return (slope() * vect[0] - vect[1] + intercept()) / std::sqrt(a2b2());
            }

        template <typename V> double distance_to(const V& vect) const { return std::abs(distance_with_direction(vect)); }

        template <typename V> V project_on(const V& source) const
            {
                return {(source[0] + slope() * source[1] - slope() * intercept()) / a2b2(),
                        (slope() * (source[0] + slope() * source[1]) + intercept()) / a2b2()};
            }

     private:
        double slope_ = 1;
        double intercept_ = 0;

        constexpr double a2b2() const { return sqr(slope()) + 1; }

    }; // class LineDefinedByEquation

    inline std::ostream& operator<<(std::ostream& out, const LineDefinedByEquation& line) { return out << "Line(slope:" << line.slope() << ", intercept:" << line.intercept() << ')'; }

} // namespace acmacs

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <sys/time.h>

#include <boost/unordered_map.hpp>

#include "SignalRoutine.h"
#include "../Log.h"
#include "../Cache.h"

/*
 * Define log types
 * l_ means local log types, each thread has a log
 * g_ means global log types, each shared variable has a log
 * r  -> read
 * w  -> write
 * l  -> lock
 * m  -> mutex init
 * f  -> fork
 */
typedef struct {
    // <long/void *> sizeof pointer usually equals to sizeof long
    LastOnePredictorLog<long> VAL_LOG;
    // <int>, -1 is the place holder, means the read operation reads
    // the local value
    LastOnePredictorLog<int> VER_LOG;
} l_rlog_t;

typedef VLastOnePredictorLog l_wlog_t;

typedef LastOnePredictorLog<pthread_t> g_llog_t;

typedef LastOnePredictorLog<pthread_t> g_mlog_t;

typedef LastOnePredictorLog<pthread_t> g_flog_t;

typedef struct {
    void* address;
    size_t range;
} mem_t;

typedef struct {
    std::vector<mem_t *> ADDRESS_LOG;
    VLastOnePredictorLog BIRTHDAY_LOG;
} l_addmap_t;

/*
 * Define local log keys
 */
static pthread_key_t rlog_key;
static pthread_key_t wlog_key;
static pthread_key_t cache_key;
static pthread_key_t birthday_key;
static pthread_key_t address_birthday_map_key;

/*
 * Define global log variables, each shared var has one
 */
static std::vector<g_llog_t *> llogs; // <g_llog_t *> size is not fixed, and should be determined at runtime
static g_flog_t flog;
static g_mlog_t mlog;

/*
 * write versions, each shared var has a version
 */
static unsigned* write_versions;

/*
 * locks for synchronization, each shared var has one
 */
static pthread_mutex_t* locks;
static pthread_mutex_t fork_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mutex_init_lock = PTHREAD_MUTEX_INITIALIZER;

/*
 * mutex_t-> mutex_id hashmap
 * pthread_t -> thread_id hashmap
 */
static unsigned mutex_id = 0;
static boost::unordered_map<pthread_mutex_t *, unsigned> mutex_ht;
static boost::unordered_map<pthread_t, unsigned> thread_ht;
static boost::unordered_map<pthread_t, l_rlog_t*> rlogs;
static boost::unordered_map<pthread_t, l_wlog_t*> wlogs;
static boost::unordered_map<pthread_t, l_addmap_t*> addlogs;

/*
 * start to record?
 */
static bool start = false;

/*
 * number of shared variables
 */
static unsigned num_shared_vars = 0;

#ifdef NO_TIME_CMD
static struct timeval tpstart, tpend;
#endif

static inline void lock(unsigned svId) {
    pthread_mutex_lock(&locks[svId]);
}

static inline void unlock(unsigned svId) {
    pthread_mutex_unlock(&locks[svId]);
}

static inline void forkLock() {
    pthread_mutex_lock(&fork_lock);
}

static inline void forkUnlock() {
    pthread_mutex_unlock(&fork_lock);
}

static inline void mutexInitLock() {
    pthread_mutex_lock(&mutex_init_lock);
}

static inline void mutexInitUnlock() {
    pthread_mutex_unlock(&mutex_init_lock);
}

/* delete logs
 */
void close_read_log(void* log) {
    pthread_t tid = pthread_self();
    rlogs[tid] = (l_rlog_t*) log;
}

void close_write_log(void* log) {
    pthread_t tid = pthread_self();
    wlogs[tid] = (l_wlog_t*) log;
}

void close_map_log(void* log) {
    pthread_t tid = pthread_self();
    addlogs[tid] = (l_addmap_t*) log;
}

void close_cache(void* log) {
    delete (Cache*) log;
}

extern "C" {

    void OnInit(unsigned svsNum) {
        printf("OnInit-Record\n");
        num_shared_vars = svsNum;
        initializeSigRoutine();

        pthread_key_create(&rlog_key, close_read_log);
        pthread_key_create(&wlog_key, close_write_log);
        pthread_key_create(&address_birthday_map_key, close_map_log);
        pthread_key_create(&birthday_key, NULL);
        pthread_key_create(&cache_key, close_cache);

        write_versions = new unsigned[svsNum];
        memset(write_versions, 0, sizeof (unsigned) * svsNum);
        locks = new pthread_mutex_t[svsNum];

        for (unsigned i = 0; i < svsNum; i++) {
            pthread_mutex_init(&locks[i], NULL);
        }

        // main thread.
        pthread_t tid = pthread_self();
        thread_ht[tid] = thread_ht.size();

#ifdef NO_TIME_CMD
        gettimeofday(&tpstart, NULL);
#endif
    }

    void OnExit() {
        start = false;

#ifdef NO_TIME_CMD
        gettimeofday(&tpend, NULL);
        double timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec;
        timeuse /= 1000;
        printf("processor time is %lf ms\n", timeuse);
#endif
        printf("OnExit-Record\n");

        // dump, delete/free is not needed, because program will exit.
        {//flog
            flog.dumpWithValueUnsignedMap("fork.dat", "wb", thread_ht);
        }

        {
            //mlog, llogs
            mlog.dumpWithValueUnsignedMap("mutex.dat", "wb", thread_ht);
            for (unsigned i = 0; i < llogs.size(); i++) {
                g_llog_t * llog = llogs[i];
                llog->dumpWithValueUnsignedMap("mutex.dat", "ab", thread_ht);
            }
        }

        {//rlog
            bool created = false;
            boost::unordered_map<pthread_t, l_rlog_t*>::iterator rit = rlogs.begin();
            while (rit != rlogs.end()) {
                l_rlog_t* rlog = rit->second;
                unsigned _tid = thread_ht[rit->first];
                for (unsigned i = 0; i < num_shared_vars; i++) {
                    if (!created) {
                        rlog[i].VAL_LOG.dumpWithUnsigned("read.dat", "wb", _tid);
                        rlog[i].VER_LOG.dumpWithUnsigned("read.dat", "ab", _tid);

                        created = true;
                    } else {
                        rlog[i].VAL_LOG.dumpWithUnsigned("read.dat", "ab", _tid);
                        rlog[i].VER_LOG.dumpWithUnsigned("read.dat", "ab", _tid);
                    }
                }

                rit++;
            }
        }
        {//wlog
            bool created = false;
            boost::unordered_map<pthread_t, l_wlog_t*>::iterator wit = wlogs.begin();
            while (wit != wlogs.end()) {
                l_wlog_t* wlog = wit->second;
                unsigned _tid = thread_ht[wit->first];
                for (unsigned i = 0; i < num_shared_vars; i++) {
                    if (!created) {
                        wlog->dumpWithUnsigned("write.dat", "wb", _tid);

                        created = true;
                    } else {
                        wlog->dumpWithUnsigned("write.dat", "ab", _tid);
                    }
                }

                wit++;
            }
        }
        {//address birthday map
            bool created = false;
            boost::unordered_map<pthread_t, l_addmap_t*>::iterator it = addlogs.begin();
            while (it != addlogs.end()) {
                unsigned _tid = thread_ht[it->first];
                l_addmap_t * addmap = it->second;

                FILE * fout = NULL;
                if (!created) {
                    fout = fopen("addressmap.dat", "wb");
                    created = true;
                } else {
                    fout = fopen("addressmap.dat", "ab");
                }

                unsigned size = addmap->ADDRESS_LOG.size();
                fwrite(&size, sizeof (unsigned), 1, fout);
                fwrite(&_tid, sizeof (unsigned), 1, fout);
                for (unsigned i = 0; i < size; i++) {
                    mem_t * m = addmap->ADDRESS_LOG[i];
                    fwrite(&m->address, sizeof (void*), 1, fout);
                    fwrite(&m->range, sizeof (size_t), 1, fout);
                }
                fclose(fout);

                addmap->BIRTHDAY_LOG.dump("addressmap.dat", "ab");

                it++;
            }
        }
    }

    void OnAddressInit(void* value, size_t size, size_t n) {
        if (!start) {
            return;
        }

        l_addmap_t * mlog = (l_addmap_t*) pthread_getspecific(address_birthday_map_key);
        if (mlog == NULL) {
            mlog = new l_addmap_t;
            pthread_setspecific(address_birthday_map_key, mlog);
        }

        size_t * counter = (size_t *) pthread_getspecific(birthday_key);
        if (counter == NULL) {
            counter = new size_t;
            (*counter) = 0;
        }

        size_t c = *counter;
        mem_t * m = new mem_t;
        m->address = value;
        m->range = size*n;
        mlog->ADDRESS_LOG.push_back(m);
        mlog->BIRTHDAY_LOG.logValue(c++);
        (*counter) = c;
    }

    void OnLoad(int svId, long address, long value, int debug) {
        if (!start) {
            return;
        }

#ifdef DEBUG
        printf("OnLoad\n");
#endif
        // using thread_key to tell whether log has been established
        // if so, use it, otherwise, new one
        l_rlog_t * rlog = (l_rlog_t*) pthread_getspecific(rlog_key);
        if (rlog == NULL) {
            rlog = new l_rlog_t[num_shared_vars];
            pthread_setspecific(rlog_key, rlog);
        }

        Cache* cache = (Cache*) pthread_getspecific(cache_key);
        if (cache != NULL && cache->query(address, value)) {
            rlog[svId].VER_LOG.logValue(write_versions[svId]);
        } else {
            rlog[svId].VAL_LOG.logValue(value);
            rlog[svId].VER_LOG.logValue(-1);
        }
    }

    unsigned OnPreStore(int svId, int debug) {
        if (!start) {
            return 0;
        }

        lock(svId);
#ifdef DEBUG
        printf("OnPreStore: %d [%d]\n", svId, debug);
#endif
        unsigned version = write_versions[svId];
        write_versions[svId] = version + 1;

        return version;
    }

    void OnStore(int svId, unsigned version, long address, long value, int debug) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnStore\n");
#endif
        unlock(svId);

        l_wlog_t * wlog = (l_wlog_t*) pthread_getspecific(wlog_key);
        if (wlog == NULL) {
            wlog = new l_wlog_t[num_shared_vars];
            pthread_setspecific(wlog_key, wlog);
        }
        wlog[svId].logValue(version);

        Cache* cache = (Cache*) pthread_getspecific(cache_key);
        if (cache == NULL) {
            cache = new Cache;
        }

        cache->add(address, value);
    }

    void OnLock(pthread_mutex_t* mutex_ptr) {
        if (!start) {
            return;
        }

        // if map does not contain it, it must be a bug
        // because lock and init have a race.
        if (!mutex_ht.count(mutex_ptr)) {
            fprintf(stderr, "ERROR: program bug!\n");
            OnExit();
            exit(1);
        }

        // here, the same address mutex_ptr is impossible to init a new lock
        // because the lock has been locked
        // therefore mutex_ht[mutex_ptr] is safe
        g_llog_t* llog = llogs[mutex_ht[mutex_ptr]];
        llog->logValue(pthread_self()); // exchange to _tid at last

#ifdef DEBUG
        printf("OnLock --> t%d\n", thread_ht[tid]);
#endif
    }

    void OnWait(pthread_cond_t* cond_ptr, pthread_mutex_t* mutex_ptr) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnWait\n");
#endif

        if (!mutex_ht.count(mutex_ptr)) {
            fprintf(stderr, "ERROR: program bug!\n");
            OnExit();
            exit(1);
        }
        g_llog_t* llog = llogs[mutex_ht[mutex_ptr]];
        llog->logValue(pthread_self());
    }

    void OnPreMutexInit(bool race) {
        if (start && race) {
            mutexInitLock();
        }
    }

    void OnMutexInit(pthread_mutex_t* mutex_ptr, bool race) {
        // if mutex_ht contains mutex_ptr, it means that the original one may be
        // destroyed; No matther mutex_ht contains it or not, it is a new lock
        mutex_ht[mutex_ptr] = mutex_id++;
        g_llog_t * llog = new g_llog_t;
        llogs.push_back(llog);

        if (start && race) {
            pthread_t tid = pthread_self();
            mlog.logValue(tid);

            mutexInitUnlock();
        }
    }

    void OnPreFork(bool race) {
        if (!start) {
            start = true;
        }
#ifdef DEBUG
        printf("OnPreFork\n");
#endif
        if (race) forkLock();
    }

    void OnFork(pthread_t* forked_tid_ptr, bool race) {
        if (!start) {
            return;
        }

#ifdef DEBUG
        printf("OnFork\n");
#endif

        pthread_t ftid = *(forked_tid_ptr);
        if (!thread_ht.count(ftid)) {
            thread_ht[ftid] = thread_ht.size();
        }

        if (race) {
            pthread_t tid = pthread_self();
            flog.logValue(tid);

            forkUnlock();
        }
    }

}

/* ************************************************************************
 * Signal Process
 * ************************************************************************/

void sigroutine(int dunno) {
    printSigInformation(dunno);

    OnExit();
    exit(dunno);
}
<commit_msg>comments<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <sys/time.h>

#include <boost/unordered_map.hpp>

#include "SignalRoutine.h"
#include "../Log.h"
#include "../Cache.h"

/*
 * Define log types
 * l_ means local log types, each thread has a log
 * g_ means global log types, each shared variable has a log
 * r  -> read
 * w  -> write
 * l  -> lock
 * m  -> mutex init
 * f  -> fork
 */
typedef struct {
    // <long/void *> sizeof pointer usually equals to sizeof long
    LastOnePredictorLog<long> VAL_LOG;
    // <int>, -1 is the place holder, means the read operation reads
    // the local value
    LastOnePredictorLog<int> VER_LOG;
} l_rlog_t;

typedef VLastOnePredictorLog l_wlog_t;

typedef LastOnePredictorLog<pthread_t> g_llog_t;

typedef LastOnePredictorLog<pthread_t> g_mlog_t;

typedef LastOnePredictorLog<pthread_t> g_flog_t;

typedef struct {
    void* address;
    size_t range;
} mem_t;

typedef struct {
    std::vector<mem_t *> ADDRESS_LOG;
    VLastOnePredictorLog BIRTHDAY_LOG;
} l_addmap_t;

/*
 * Define local log keys
 */
static pthread_key_t rlog_key;
static pthread_key_t wlog_key;
static pthread_key_t cache_key;
static pthread_key_t birthday_key;
static pthread_key_t address_birthday_map_key;

/*
 * Define global log variables, each shared var has one
 */
static std::vector<g_llog_t *> llogs; // <g_llog_t *> size is not fixed, and should be determined at runtime
static g_flog_t flog;
static g_mlog_t mlog;

/*
 * write versions, each shared var has a version
 */
static unsigned* write_versions;

/*
 * locks for synchronization, each shared var has one
 */
static pthread_mutex_t* locks;
static pthread_mutex_t fork_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mutex_init_lock = PTHREAD_MUTEX_INITIALIZER;

/*
 * mutex_t-> mutex_id hashmap
 * pthread_t -> thread_id hashmap
 */
static unsigned mutex_id = 0;
static boost::unordered_map<pthread_mutex_t *, unsigned> mutex_ht;
static boost::unordered_map<pthread_t, unsigned> thread_ht;
static boost::unordered_map<pthread_t, l_rlog_t*> rlogs;
static boost::unordered_map<pthread_t, l_wlog_t*> wlogs;
static boost::unordered_map<pthread_t, l_addmap_t*> addlogs;

/*
 * start to record?
 */
static bool start = false;

/*
 * number of shared variables
 */
static unsigned num_shared_vars = 0;

#ifdef NO_TIME_CMD
static struct timeval tpstart, tpend;
#endif

static inline void lock(unsigned svId) {
    pthread_mutex_lock(&locks[svId]);
}

static inline void unlock(unsigned svId) {
    pthread_mutex_unlock(&locks[svId]);
}

static inline void forkLock() {
    pthread_mutex_lock(&fork_lock);
}

static inline void forkUnlock() {
    pthread_mutex_unlock(&fork_lock);
}

static inline void mutexInitLock() {
    pthread_mutex_lock(&mutex_init_lock);
}

static inline void mutexInitUnlock() {
    pthread_mutex_unlock(&mutex_init_lock);
}

/* we do not dump logs here, because it is time consuming
 * we store them in a global map, dump them at last
 *
 * in practice, we can dump them here to avoid memory leak
 */
void close_read_log(void* log) {
    pthread_t tid = pthread_self();
    rlogs[tid] = (l_rlog_t*) log;
}

void close_write_log(void* log) {
    pthread_t tid = pthread_self();
    wlogs[tid] = (l_wlog_t*) log;
}

void close_map_log(void* log) {
    pthread_t tid = pthread_self();
    addlogs[tid] = (l_addmap_t*) log;
}

void close_cache(void* log) {
    delete (Cache*) log;
}

extern "C" {

    void OnInit(unsigned svsNum) {
        printf("OnInit-Record\n");
        num_shared_vars = svsNum;
        initializeSigRoutine();

        pthread_key_create(&rlog_key, close_read_log);
        pthread_key_create(&wlog_key, close_write_log);
        pthread_key_create(&address_birthday_map_key, close_map_log);
        pthread_key_create(&birthday_key, NULL);
        pthread_key_create(&cache_key, close_cache);

        write_versions = new unsigned[svsNum];
        memset(write_versions, 0, sizeof (unsigned) * svsNum);
        locks = new pthread_mutex_t[svsNum];

        for (unsigned i = 0; i < svsNum; i++) {
            pthread_mutex_init(&locks[i], NULL);
        }

        // main thread.
        pthread_t tid = pthread_self();
        thread_ht[tid] = thread_ht.size();

#ifdef NO_TIME_CMD
        gettimeofday(&tpstart, NULL);
#endif
    }

    void OnExit() {
        start = false;

#ifdef NO_TIME_CMD
        gettimeofday(&tpend, NULL);
        double timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec;
        timeuse /= 1000;
        printf("processor time is %lf ms\n", timeuse);
#endif
        printf("OnExit-Record\n");

        // dump, delete/free is not needed, because program will exit.
        {//flog
            flog.dumpWithValueUnsignedMap("fork.dat", "wb", thread_ht);
        }

        {
            //mlog, llogs
            mlog.dumpWithValueUnsignedMap("mutex.dat", "wb", thread_ht);
            for (unsigned i = 0; i < llogs.size(); i++) {
                g_llog_t * llog = llogs[i];
                llog->dumpWithValueUnsignedMap("mutex.dat", "ab", thread_ht);
            }
        }

        {//rlog
            bool created = false;
            boost::unordered_map<pthread_t, l_rlog_t*>::iterator rit = rlogs.begin();
            while (rit != rlogs.end()) {
                l_rlog_t* rlog = rit->second;
                unsigned _tid = thread_ht[rit->first];
                for (unsigned i = 0; i < num_shared_vars; i++) {
                    if (!created) {
                        rlog[i].VAL_LOG.dumpWithUnsigned("read.dat", "wb", _tid);
                        rlog[i].VER_LOG.dumpWithUnsigned("read.dat", "ab", _tid);

                        created = true;
                    } else {
                        rlog[i].VAL_LOG.dumpWithUnsigned("read.dat", "ab", _tid);
                        rlog[i].VER_LOG.dumpWithUnsigned("read.dat", "ab", _tid);
                    }
                }

                rit++;
            }
        }
        {//wlog
            bool created = false;
            boost::unordered_map<pthread_t, l_wlog_t*>::iterator wit = wlogs.begin();
            while (wit != wlogs.end()) {
                l_wlog_t* wlog = wit->second;
                unsigned _tid = thread_ht[wit->first];
                for (unsigned i = 0; i < num_shared_vars; i++) {
                    if (!created) {
                        wlog->dumpWithUnsigned("write.dat", "wb", _tid);

                        created = true;
                    } else {
                        wlog->dumpWithUnsigned("write.dat", "ab", _tid);
                    }
                }

                wit++;
            }
        }
        {//address birthday map
            bool created = false;
            boost::unordered_map<pthread_t, l_addmap_t*>::iterator it = addlogs.begin();
            while (it != addlogs.end()) {
                unsigned _tid = thread_ht[it->first];
                l_addmap_t * addmap = it->second;

                FILE * fout = NULL;
                if (!created) {
                    fout = fopen("addressmap.dat", "wb");
                    created = true;
                } else {
                    fout = fopen("addressmap.dat", "ab");
                }

                unsigned size = addmap->ADDRESS_LOG.size();
                fwrite(&size, sizeof (unsigned), 1, fout);
                fwrite(&_tid, sizeof (unsigned), 1, fout);
                for (unsigned i = 0; i < size; i++) {
                    mem_t * m = addmap->ADDRESS_LOG[i];
                    fwrite(&m->address, sizeof (void*), 1, fout);
                    fwrite(&m->range, sizeof (size_t), 1, fout);
                }
                fclose(fout);

                addmap->BIRTHDAY_LOG.dump("addressmap.dat", "ab");

                it++;
            }
        }
    }

    void OnAddressInit(void* value, size_t size, size_t n) {
        if (!start) {
            return;
        }

        l_addmap_t * mlog = (l_addmap_t*) pthread_getspecific(address_birthday_map_key);
        if (mlog == NULL) {
            mlog = new l_addmap_t;
            pthread_setspecific(address_birthday_map_key, mlog);
        }

        size_t * counter = (size_t *) pthread_getspecific(birthday_key);
        if (counter == NULL) {
            counter = new size_t;
            (*counter) = 0;
        }

        size_t c = *counter;
        mem_t * m = new mem_t;
        m->address = value;
        m->range = size*n;
        mlog->ADDRESS_LOG.push_back(m);
        mlog->BIRTHDAY_LOG.logValue(c++);
        (*counter) = c;
    }

    void OnLoad(int svId, long address, long value, int debug) {
        if (!start) {
            return;
        }

#ifdef DEBUG
        printf("OnLoad\n");
#endif
        // using thread_key to tell whether log has been established
        // if so, use it, otherwise, new one
        l_rlog_t * rlog = (l_rlog_t*) pthread_getspecific(rlog_key);
        if (rlog == NULL) {
            rlog = new l_rlog_t[num_shared_vars];
            pthread_setspecific(rlog_key, rlog);
        }

        Cache* cache = (Cache*) pthread_getspecific(cache_key);
        if (cache != NULL && cache->query(address, value)) {
            rlog[svId].VER_LOG.logValue(write_versions[svId]);
        } else {
            rlog[svId].VAL_LOG.logValue(value);
            rlog[svId].VER_LOG.logValue(-1);
        }
    }

    unsigned OnPreStore(int svId, int debug) {
        if (!start) {
            return 0;
        }

        lock(svId);
#ifdef DEBUG
        printf("OnPreStore: %d [%d]\n", svId, debug);
#endif
        unsigned version = write_versions[svId];
        write_versions[svId] = version + 1;

        return version;
    }

    void OnStore(int svId, unsigned version, long address, long value, int debug) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnStore\n");
#endif
        unlock(svId);

        l_wlog_t * wlog = (l_wlog_t*) pthread_getspecific(wlog_key);
        if (wlog == NULL) {
            wlog = new l_wlog_t[num_shared_vars];
            pthread_setspecific(wlog_key, wlog);
        }
        wlog[svId].logValue(version);

        Cache* cache = (Cache*) pthread_getspecific(cache_key);
        if (cache == NULL) {
            cache = new Cache;
        }

        cache->add(address, value);
    }

    void OnLock(pthread_mutex_t* mutex_ptr) {
        if (!start) {
            return;
        }

        // if map does not contain it, it must be a bug
        // because lock and init have a race.
        if (!mutex_ht.count(mutex_ptr)) {
            fprintf(stderr, "ERROR: program bug!\n");
            OnExit();
            exit(1);
        }

        // here, the same address mutex_ptr is impossible to init a new lock
        // because the lock has been locked
        // therefore mutex_ht[mutex_ptr] is safe
        g_llog_t* llog = llogs[mutex_ht[mutex_ptr]];
        llog->logValue(pthread_self()); // exchange to _tid at last

#ifdef DEBUG
        printf("OnLock --> t%d\n", thread_ht[tid]);
#endif
    }

    void OnWait(pthread_cond_t* cond_ptr, pthread_mutex_t* mutex_ptr) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnWait\n");
#endif

        if (!mutex_ht.count(mutex_ptr)) {
            fprintf(stderr, "ERROR: program bug!\n");
            OnExit();
            exit(1);
        }
        g_llog_t* llog = llogs[mutex_ht[mutex_ptr]];
        llog->logValue(pthread_self());
    }

    void OnPreMutexInit(bool race) {
        if (start && race) {
            mutexInitLock();
        }
    }

    void OnMutexInit(pthread_mutex_t* mutex_ptr, bool race) {
        // if mutex_ht contains mutex_ptr, it means that the original one may be
        // destroyed; No matther mutex_ht contains it or not, it is a new lock
        mutex_ht[mutex_ptr] = mutex_id++;
        g_llog_t * llog = new g_llog_t;
        llogs.push_back(llog);

        if (start && race) {
            pthread_t tid = pthread_self();
            mlog.logValue(tid);

            mutexInitUnlock();
        }
    }

    void OnPreFork(bool race) {
        if (!start) {
            start = true;
        }
#ifdef DEBUG
        printf("OnPreFork\n");
#endif
        if (race) forkLock();
    }

    void OnFork(pthread_t* forked_tid_ptr, bool race) {
        if (!start) {
            return;
        }

#ifdef DEBUG
        printf("OnFork\n");
#endif

        pthread_t ftid = *(forked_tid_ptr);
        if (!thread_ht.count(ftid)) {
            thread_ht[ftid] = thread_ht.size();
        }

        if (race) {
            pthread_t tid = pthread_self();
            flog.logValue(tid);

            forkUnlock();
        }
    }

}

/* ************************************************************************
 * Signal Process
 * ************************************************************************/

void sigroutine(int dunno) {
    printSigInformation(dunno);

    OnExit();
    exit(dunno);
}
<|endoftext|>


<commit_before>#include <thread>
#include <renderer.hpp>
#include <fensterchen.hpp>

int main(int argc, char* argv[])
{
  unsigned const width = 600;
  unsigned const height = 600;
  std::string const filename = "./checkerboard.ppm";

  Renderer app(width, height, filename);

  std::thread thr([&app]() { app.render(); });

  Window win(glm::ivec2(width,height));

  while (!win.shouldClose()) {
    if (win.isKeyPressed(GLFW_KEY_ESCAPE)) {
      win.stop();
    }

    glDrawPixels( width, height, GL_RGB, GL_FLOAT
                , app.colorbuffer().data());

    win.update();
  }

  thr.join();

  return 0;
}
<commit_msg>raytracer.cpp fixed<commit_after>#include <thread>
#include <renderer.hpp>
#include <fensterchen.hpp>

int main(int argc, char* argv[])
{
  Scene scene;
  unsigned const width = 600;
  unsigned const height = 600;
  std::string const filename = "./checkerboard.ppm";

  Renderer app(scene, width, height, filename);

  std::thread thr([&app]() { app.render(); });

  Window win(glm::ivec2(width,height));

  while (!win.shouldClose()) {
    if (win.isKeyPressed(GLFW_KEY_ESCAPE)) {
      win.stop();
    }

    glDrawPixels( width, height, GL_RGB, GL_FLOAT
                , app.colorbuffer().data());

    win.update();
  }

  thr.join();

  return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: XMLEmbeddedObjectImportContext.hxx,v $
 *
 *  $Revision: 1.1 $
 *
 *  last change: $Author: mib $ $Date: 2001-05-09 12:06:23 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_XMLEMBEDDEDOBJECTIMPORTCONTEXT_HXX
#define _XMLOFF_XMLEMBEDDEDOBJECTIMPORTCONTEXT_HXX

#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HPP_
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#endif

#ifndef _XMLOFF_XMLICTXT_HXX
#include "xmlictxt.hxx"
#endif

namespace com { namespace sun { namespace star { namespace lang {
    class XComponent; } } } }

class XMLEmbeddedObjectImportContext : public SvXMLImportContext
{
    ::com::sun::star::uno::Reference<
        ::com::sun::star::xml::sax::XDocumentHandler > xHandler;

    ::rtl::OUString sFilterService;

public:
    TYPEINFO();

    const ::rtl::OUString& GetFilterServiceName() const { return sFilterService; }

    XMLEmbeddedObjectImportContext( SvXMLImport& rImport, USHORT nPrfx,
                                    const ::rtl::OUString& rLName,
        const ::com::sun::star::uno::Reference<
            ::com::sun::star::xml::sax::XAttributeList >& xAttrList );

    virtual ~XMLEmbeddedObjectImportContext();

    virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix,
                                   const ::rtl::OUString& rLocalName,
                                   const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList );

    virtual void StartElement( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList );

    virtual void EndElement();

    virtual void Characters( const ::rtl::OUString& rChars );

    sal_Bool SetComponent(
        ::com::sun::star::uno::Reference<
            ::com::sun::star::lang::XComponent >& rComp );

};

#endif  //  _XMLOFF_XMLEMBEDDEDOBJECTIMPORTCONTEXT_HXX

<commit_msg>#100592# added OUString sCLSID and interfaces<commit_after>/*************************************************************************
 *
 *  $RCSfile: XMLEmbeddedObjectImportContext.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: aw $ $Date: 2002-06-27 11:04:33 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_XMLEMBEDDEDOBJECTIMPORTCONTEXT_HXX
#define _XMLOFF_XMLEMBEDDEDOBJECTIMPORTCONTEXT_HXX

#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HPP_
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#endif

#ifndef _XMLOFF_XMLICTXT_HXX
#include "xmlictxt.hxx"
#endif

namespace com { namespace sun { namespace star { namespace lang {
    class XComponent; } } } }

class XMLEmbeddedObjectImportContext : public SvXMLImportContext
{
    ::com::sun::star::uno::Reference<
        ::com::sun::star::xml::sax::XDocumentHandler > xHandler;

    ::rtl::OUString sFilterService;
    // #100592#
    ::rtl::OUString sCLSID;

public:
    TYPEINFO();

    const ::rtl::OUString& GetFilterServiceName() const { return sFilterService; }
    // #100592#
    const ::rtl::OUString& GetFilterCLSID() const { return sCLSID; }

    XMLEmbeddedObjectImportContext( SvXMLImport& rImport, USHORT nPrfx,
                                    const ::rtl::OUString& rLName,
        const ::com::sun::star::uno::Reference<
            ::com::sun::star::xml::sax::XAttributeList >& xAttrList );

    virtual ~XMLEmbeddedObjectImportContext();

    virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix,
                                   const ::rtl::OUString& rLocalName,
                                   const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList );

    virtual void StartElement( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList );

    virtual void EndElement();

    virtual void Characters( const ::rtl::OUString& rChars );

    sal_Bool SetComponent(
        ::com::sun::star::uno::Reference<
            ::com::sun::star::lang::XComponent >& rComp );

};

#endif  //  _XMLOFF_XMLEMBEDDEDOBJECTIMPORTCONTEXT_HXX

<|endoftext|>


<commit_before>// Copyright 2018 The clvk authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <cstring>

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <deque>
#include <list>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>

#include <vulkan/vulkan.h>

#include "cl_headers.hpp"
#include "device.hpp"
#include "utils.hpp"

struct refcounted {

    refcounted() : m_refcount(1) { }

    virtual ~refcounted() = default;

    void retain() {
        unsigned int refcount = m_refcount.fetch_add(1);
        cvk_debug_fn("obj = %p, refcount now %u", this, refcount + 1);
    }

    void release() {
        unsigned int refcount = m_refcount.fetch_sub(1);
        cvk_debug_fn("obj = %p, refcount now %u", this, refcount - 1);

        if (refcount == 1) {
            delete this;
        }
    }

    unsigned int refcount() const {
        return m_refcount.load();
    }

private:
    std::atomic<unsigned int> m_refcount;
};

template<typename T>
struct refcounted_holder {

    refcounted_holder() : m_refcounted(nullptr) {}

    refcounted_holder(T *refcounted) : m_refcounted(refcounted) {
        if (m_refcounted != nullptr) {
            m_refcounted->retain();
        }
    }

    refcounted_holder(const refcounted_holder &other) :
        m_refcounted(other.m_refcounted) {
        if (m_refcounted != nullptr) {
            m_refcounted->retain();
        }
    }

    refcounted_holder(const refcounted_holder &&other) = delete;

    ~refcounted_holder() {
        if (m_refcounted != nullptr) {
            m_refcounted->release();
        }
    }

    T* operator->() const {
        return m_refcounted;
    }

    operator T*() const {
        return m_refcounted;
    }

    refcounted_holder& operator=(const refcounted_holder& ) = delete;
    refcounted_holder& operator=(const refcounted_holder&&) = delete;

    void reset(T* refc) {
        if (m_refcounted != nullptr) {
            m_refcounted->release();
        }
        m_refcounted = refc;
        if (m_refcounted != nullptr) {
            m_refcounted->retain();
        }
    }

private:
    T *m_refcounted;
};

typedef struct _cl_context : public refcounted {

    _cl_context(cvk_device *device, const cl_context_properties* props)
        : m_device(device) {

        if (props) {
            while (*props) {
                // Save name
                m_properties.push_back(*props);
                // Save value
                m_properties.push_back(*(props+1));
                props += 2;
            }
            m_properties.push_back(*props);
        }
    }

    virtual ~_cl_context() {}

    const std::vector<cl_context_properties>& properties() const {
        return m_properties;
    }

    cvk_device* device() const { return m_device; }
    unsigned num_devices() const { return 1u; }

private:
    cvk_device *m_device;
    std::vector<cl_context_properties> m_properties;

} cvk_context;

struct api_object : public refcounted {

    api_object(cvk_context *context) : m_context(context) {
        m_context->retain();
    }
    ~api_object() {
        m_context->release();
    }

    cvk_context* context() const { return m_context; }

protected:
    cvk_context *m_context;
};

<commit_msg>Use refcounted_holder to manage context refcounting in api_object<commit_after>// Copyright 2018 The clvk authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <cstring>

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <deque>
#include <list>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>

#include <vulkan/vulkan.h>

#include "cl_headers.hpp"
#include "device.hpp"
#include "utils.hpp"

struct refcounted {

    refcounted() : m_refcount(1) { }

    virtual ~refcounted() = default;

    void retain() {
        unsigned int refcount = m_refcount.fetch_add(1);
        cvk_debug_fn("obj = %p, refcount now %u", this, refcount + 1);
    }

    void release() {
        unsigned int refcount = m_refcount.fetch_sub(1);
        cvk_debug_fn("obj = %p, refcount now %u", this, refcount - 1);

        if (refcount == 1) {
            delete this;
        }
    }

    unsigned int refcount() const {
        return m_refcount.load();
    }

private:
    std::atomic<unsigned int> m_refcount;
};

template<typename T>
struct refcounted_holder {

    refcounted_holder() : m_refcounted(nullptr) {}

    refcounted_holder(T *refcounted) : m_refcounted(refcounted) {
        if (m_refcounted != nullptr) {
            m_refcounted->retain();
        }
    }

    refcounted_holder(const refcounted_holder &other) :
        m_refcounted(other.m_refcounted) {
        if (m_refcounted != nullptr) {
            m_refcounted->retain();
        }
    }

    refcounted_holder(const refcounted_holder &&other) = delete;

    ~refcounted_holder() {
        if (m_refcounted != nullptr) {
            m_refcounted->release();
        }
    }

    T* operator->() const {
        return m_refcounted;
    }

    operator T*() const {
        return m_refcounted;
    }

    refcounted_holder& operator=(const refcounted_holder& ) = delete;
    refcounted_holder& operator=(const refcounted_holder&&) = delete;

    void reset(T* refc) {
        if (m_refcounted != nullptr) {
            m_refcounted->release();
        }
        m_refcounted = refc;
        if (m_refcounted != nullptr) {
            m_refcounted->retain();
        }
    }

private:
    T *m_refcounted;
};

typedef struct _cl_context : public refcounted {

    _cl_context(cvk_device *device, const cl_context_properties* props)
        : m_device(device) {

        if (props) {
            while (*props) {
                // Save name
                m_properties.push_back(*props);
                // Save value
                m_properties.push_back(*(props+1));
                props += 2;
            }
            m_properties.push_back(*props);
        }
    }

    virtual ~_cl_context() {}

    const std::vector<cl_context_properties>& properties() const {
        return m_properties;
    }

    cvk_device* device() const { return m_device; }
    unsigned num_devices() const { return 1u; }

private:
    cvk_device *m_device;
    std::vector<cl_context_properties> m_properties;

} cvk_context;

using cvk_context_holder = refcounted_holder<cvk_context>;

struct api_object : public refcounted {

    api_object(cvk_context *context) : m_context(context) {}
    cvk_context* context() const { return m_context; }

protected:
    cvk_context_holder m_context;
};

<|endoftext|>


<commit_before>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

// $Id$

#include "AliMUONClusterFinderSimpleFit.h"

#include "AliLog.h"
#include "AliMpDEManager.h"
#include "AliMpStationType.h"
#include "AliMUONCluster.h"
#include "AliMUONConstants.h"
#include "AliMUONDigit.h"
#include "AliMUONMathieson.h"
#include "AliMUONPad.h"
#include "AliMUONClusterFinderCOG.h"
#include "AliMpArea.h"
#include "TClonesArray.h"
#include "TObjArray.h"
#include "TVector2.h"
#include "TVirtualFitter.h"
#include "TF1.h"

/// \class AliMUONClusterFinderSimpleFit
///
/// Basic cluster finder
///
/// We simply use AliMUONPreClusterFinder to get basic cluster,
/// and then we try to fit the charge repartition using a Mathieson
/// distribution, varying the position.
///
/// FIXME: this one is still at the developping stage...
///
/// \author Laurent Aphecetche

/// \nocond CLASSIMP
ClassImp(AliMUONClusterFinderSimpleFit)
/// \endcond

namespace
{
  //___________________________________________________________________________
  void
  FitFunction(Int_t& /*notused*/, Double_t* /*notused*/,
              Double_t& f, Double_t* par,
              Int_t /*notused*/)
  {
    /// Chi2 Function to minimize: Mathieson charge distribution in 2 dimensions

    TObjArray* userObjects = static_cast<TObjArray*>(TVirtualFitter::GetFitter()->GetObjectFit());

    AliMUONCluster* cluster = static_cast<AliMUONCluster*>(userObjects->At(0));
    AliMUONMathieson* mathieson = static_cast<AliMUONMathieson*>(userObjects->At(1));

    f = 0.0;
    Float_t qTot = cluster->Charge();
    Float_t chargeCorrel[] = { cluster->Charge(0)/qTot, cluster->Charge(1)/qTot };

    for ( Int_t i = 0 ; i < cluster->Multiplicity(); ++i )
    {
      AliMUONPad* pad = cluster->Pad(i);
      // skip pads w/ saturation or other problem(s)
      if ( pad->Status() ) continue;
      TVector2 lowerLeft = TVector2(par[0],par[1]) - pad->Position() - pad->Dimensions();
      TVector2 upperRight(lowerLeft + pad->Dimensions()*2.0);
      Float_t estimatedCharge =
        qTot*mathieson->IntXY(lowerLeft.X(),lowerLeft.Y(),
                              upperRight.X(),upperRight.Y());
      estimatedCharge *= chargeCorrel[pad->Cathode()];
      Float_t actualCharge = pad->Charge();

      Float_t delta = (estimatedCharge - actualCharge);

      f += delta*delta/qTot;
    }
  }
}

//_____________________________________________________________________________
AliMUONClusterFinderSimpleFit::AliMUONClusterFinderSimpleFit()
: AliMUONVClusterFinder(),
fClusterFinder(0x0),
fMathieson(0x0)
{
  /// ctor
}

//_____________________________________________________________________________
AliMUONClusterFinderSimpleFit::~AliMUONClusterFinderSimpleFit()
{
  /// dtor
  delete fClusterFinder;
  delete fMathieson;
}

//_____________________________________________________________________________
Bool_t
AliMUONClusterFinderSimpleFit::Prepare(const AliMpVSegmentation* segmentations[2],
                                       TClonesArray* digits[2])
{
  /// Prepare for clustering

  // FIXME: should we get the Mathieson from elsewhere ?

  // Find out the DetElemId
  Int_t detElemId(-1);

  for ( Int_t i = 0; i < 2; ++i )
  {
    AliMUONDigit* d = static_cast<AliMUONDigit*>(digits[i]->First());
    if (d)
    {
      detElemId = d->DetElemId();
      break;
    }
  }

  if ( detElemId < 0 )
  {
    AliWarning("Could not find DE. Probably no digits at all ?");
    return kFALSE;
  }

  AliMp::StationType stationType = AliMpDEManager::GetStationType(detElemId);

  Float_t kx3 = AliMUONConstants::SqrtKx3();
  Float_t ky3 = AliMUONConstants::SqrtKy3();
  Float_t pitch = AliMUONConstants::Pitch();

  if ( stationType == AliMp::kStation1 )
  {
    kx3 = AliMUONConstants::SqrtKx3St1();
    ky3 = AliMUONConstants::SqrtKy3St1();
    pitch = AliMUONConstants::PitchSt1();
  }

  delete fMathieson;
  fMathieson = new AliMUONMathieson;

  fMathieson->SetPitch(pitch);
  fMathieson->SetSqrtKx3AndDeriveKx2Kx4(kx3);
  fMathieson->SetSqrtKy3AndDeriveKy2Ky4(ky3);

  delete fClusterFinder;
  fClusterFinder = new AliMUONClusterFinderCOG;
  return fClusterFinder->Prepare(segmentations,digits);
}

//_____________________________________________________________________________
AliMUONCluster*
AliMUONClusterFinderSimpleFit::NextCluster()
{
  /// Returns next cluster

  if ( !fClusterFinder ) return 0x0;
  AliMUONCluster* cluster = fClusterFinder->NextCluster();
  if ( cluster )
  {
    ComputePosition(*cluster);

    if ( cluster->Charge() < 7 )
    {
      // skip that one
      return NextCluster();
    }
  }
  return cluster;
}

//_____________________________________________________________________________
void
AliMUONClusterFinderSimpleFit::ComputePosition(AliMUONCluster& cluster)
{
  /// Compute the position of the given cluster, by fitting a Mathieson
  /// charge distribution to it

  TVirtualFitter* fitter = TVirtualFitter::Fitter(0,2);
  fitter->SetFCN(FitFunction);

  if ( cluster.Multiplicity() < 3 ) return;

  // We try a Mathieson fit, starting
  // with the center-of-gravity estimate as a first guess
  // for the cluster center.

  Double_t xCOG = cluster.Position().X();
  Double_t yCOG = cluster.Position().Y();

  Float_t stepX = 0.01; // cm
  Float_t stepY = 0.01; // cm

  Double_t arg(1);//0);

  fitter->ExecuteCommand("SET PRINT",&arg,1); // disable printout

  fitter->SetParameter(0,"cluster X position",xCOG,stepX,0,0);
  fitter->SetParameter(1,"cluster Y position",yCOG,stepY,0,0);
//  fitter->SetParameter(2,"charge ratio",1.0,0.01,0.1,10);

  TObjArray userObjects;

  userObjects.Add(&cluster);
  userObjects.Add(fMathieson);

//  fitter->SetUserFunc(&userObjects);
  fitter->SetObjectFit(&userObjects);

  fitter->ExecuteCommand("MIGRAD",0,0);

  Double_t results[] = { fitter->GetParameter(0),
    fitter->GetParameter(1) };

  Double_t errors[] = { fitter->GetParError(0),
    fitter->GetParError(1) };

  cluster.SetPosition(TVector2(results[0],results[1]),
                      TVector2(errors[0],errors[1]));

  TF1* func = static_cast<TF1*>(fitter->GetUserFunc());
  Double_t chi2 = 0;
  if ( func ) chi2 = func->GetChisquare();

  AliDebug(1,Form("Cluster fitted to (x,y)=(%e,%e) (xerr,yerr)=(%e,%e) chi2=%e",
                  results[0],results[1],
                  errors[0],errors[1],chi2));
//  cluster.SetChi2(chi2/fitter->GetNumberFreeParameters());
}

<commit_msg>Should now work almost correctly...(Laurent)<commit_after>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

// $Id$

#include "AliMUONClusterFinderSimpleFit.h"

#include "AliLog.h"
#include "AliMpDEManager.h"
#include "AliMpStationType.h"
#include "AliMUONCluster.h"
#include "AliMUONConstants.h"
#include "AliMUONDigit.h"
#include "AliMUONMathieson.h"
#include "AliMUONPad.h"
#include "AliMUONClusterFinderCOG.h"
#include "AliMpArea.h"
#include "TClonesArray.h"
#include "TObjArray.h"
#include "TVector2.h"
#include "TVirtualFitter.h"
#include "TF1.h"

/// \class AliMUONClusterFinderSimpleFit
///
/// Basic cluster finder
///
/// We simply use AliMUONPreClusterFinder to get basic cluster,
/// and then we try to fit the charge repartition using a Mathieson
/// distribution, varying the position.
///
/// FIXME: this one is still at the developping stage...
///
/// \author Laurent Aphecetche

/// \nocond CLASSIMP
ClassImp(AliMUONClusterFinderSimpleFit)
/// \endcond

namespace
{
  //___________________________________________________________________________
  void
  FitFunction(Int_t& /*notused*/, Double_t* /*notused*/,
              Double_t& f, Double_t* par,
              Int_t /*notused*/)
  {
    /// Chi2 Function to minimize: Mathieson charge distribution in 2 dimensions

    TObjArray* userObjects = static_cast<TObjArray*>(TVirtualFitter::GetFitter()->GetObjectFit());

    AliMUONCluster* cluster = static_cast<AliMUONCluster*>(userObjects->At(0));
    AliMUONMathieson* mathieson = static_cast<AliMUONMathieson*>(userObjects->At(1));

    f = 0.0;
    Float_t qTot = cluster->Charge();
//    Float_t chargeCorrel[] = { cluster->Charge(0)/qTot, cluster->Charge(1)/qTot };
//    Float_t qRatio[] = { 1.0/par[2], par[2] };

    for ( Int_t i = 0 ; i < cluster->Multiplicity(); ++i )
    {
      AliMUONPad* pad = cluster->Pad(i);
      // skip pads w/ saturation or other problem(s)
      if ( pad->Status() ) continue;
      TVector2 lowerLeft = TVector2(par[0],par[1]) - pad->Position() - pad->Dimensions();
      TVector2 upperRight(lowerLeft + pad->Dimensions()*2.0);
      Float_t estimatedCharge = mathieson->IntXY(lowerLeft.X(),lowerLeft.Y(),
                                                 upperRight.X(),upperRight.Y());
//      estimatedCharge *= 2/(1+qRatio[pad->Cathode()]);
      Float_t actualCharge = pad->Charge()/qTot;

      Float_t delta = (estimatedCharge - actualCharge);

      f += delta*delta;
    }
  }
}

//_____________________________________________________________________________
AliMUONClusterFinderSimpleFit::AliMUONClusterFinderSimpleFit()
: AliMUONVClusterFinder(),
fClusterFinder(0x0),
fMathieson(0x0)
{
  /// ctor
}

//_____________________________________________________________________________
AliMUONClusterFinderSimpleFit::~AliMUONClusterFinderSimpleFit()
{
  /// dtor
  delete fClusterFinder;
  delete fMathieson;
}

//_____________________________________________________________________________
Bool_t
AliMUONClusterFinderSimpleFit::Prepare(const AliMpVSegmentation* segmentations[2],
                                       TClonesArray* digits[2])
{
  /// Prepare for clustering

  // FIXME: should we get the Mathieson from elsewhere ?

  // Find out the DetElemId
  Int_t detElemId(-1);

  for ( Int_t i = 0; i < 2; ++i )
  {
    AliMUONDigit* d = static_cast<AliMUONDigit*>(digits[i]->First());
    if (d)
    {
      detElemId = d->DetElemId();
      break;
    }
  }

  if ( detElemId < 0 )
  {
    AliWarning("Could not find DE. Probably no digits at all ?");
    return kFALSE;
  }

  AliMp::StationType stationType = AliMpDEManager::GetStationType(detElemId);

  Float_t kx3 = AliMUONConstants::SqrtKx3();
  Float_t ky3 = AliMUONConstants::SqrtKy3();
  Float_t pitch = AliMUONConstants::Pitch();

  if ( stationType == AliMp::kStation1 )
  {
    kx3 = AliMUONConstants::SqrtKx3St1();
    ky3 = AliMUONConstants::SqrtKy3St1();
    pitch = AliMUONConstants::PitchSt1();
  }

  delete fMathieson;
  fMathieson = new AliMUONMathieson;

  fMathieson->SetPitch(pitch);
  fMathieson->SetSqrtKx3AndDeriveKx2Kx4(kx3);
  fMathieson->SetSqrtKy3AndDeriveKy2Ky4(ky3);

  delete fClusterFinder;
  fClusterFinder = new AliMUONClusterFinderCOG;
  return fClusterFinder->Prepare(segmentations,digits);
}

//_____________________________________________________________________________
AliMUONCluster*
AliMUONClusterFinderSimpleFit::NextCluster()
{
  /// Returns next cluster

  if ( !fClusterFinder ) return 0x0;
  AliMUONCluster* cluster = fClusterFinder->NextCluster();
  if ( cluster )
  {
    ComputePosition(*cluster);

    if ( cluster->Charge() < 7 )
    {
      // skip that one
      return NextCluster();
    }
  }
  return cluster;
}

//_____________________________________________________________________________
void
AliMUONClusterFinderSimpleFit::ComputePosition(AliMUONCluster& cluster)
{
  /// Compute the position of the given cluster, by fitting a Mathieson
  /// charge distribution to it

  TVirtualFitter* fitter = TVirtualFitter::Fitter(0,2);
  fitter->SetFCN(FitFunction);

  if ( cluster.Multiplicity() < 3 ) return;

  // We try a Mathieson fit, starting
  // with the center-of-gravity estimate as a first guess
  // for the cluster center.

  Double_t xCOG = cluster.Position().X();
  Double_t yCOG = cluster.Position().Y();

  Float_t stepX = 0.01; // cm
  Float_t stepY = 0.01; // cm

  Double_t arg(-1); // disable printout

  fitter->ExecuteCommand("SET PRINT",&arg,1);

  fitter->SetParameter(0,"cluster X position",xCOG,stepX,0,0);
  fitter->SetParameter(1,"cluster Y position",yCOG,stepY,0,0);

  TObjArray userObjects;

  userObjects.Add(&cluster);
  userObjects.Add(fMathieson);

  fitter->SetObjectFit(&userObjects);

  Int_t val = fitter->ExecuteCommand("MIGRAD",0,0);
  AliDebug(1,Form("ExecuteCommand returned value=%d",val));
  if ( val )
  {
    // fit failed. Using COG results, with big errors
    AliWarning("Fit failed. Using COG results for cluster=");
    StdoutToAliWarning(cluster.Print());
    cluster.SetPosition(TVector2(xCOG,yCOG),TVector2(TMath::Abs(xCOG),TMath::Abs(yCOG)));
    cluster.SetChi2(1E3);
  }

  Double_t results[] = { fitter->GetParameter(0),
    fitter->GetParameter(1) };

  Double_t errors[] = { fitter->GetParError(0),
    fitter->GetParError(1) };

  cluster.SetPosition(TVector2(results[0],results[1]),
                      TVector2(errors[0],errors[1]));

  Double_t amin, edm, errdef;
  Int_t nvpar, nparx;

  fitter->GetStats(amin, edm, errdef, nvpar, nparx);

  Double_t chi2 = amin;

  AliDebug(1,Form("Cluster fitted to (x,y)=(%e,%e) (xerr,yerr)=(%e,%e) \n chi2=%e ndf=%d",
                  results[0],results[1],
                  errors[0],errors[1],chi2,fitter->GetNumberFreeParameters()));
  cluster.SetChi2(chi2);
}

<|endoftext|>