<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 * $Log$
 * Revision 1.7  2003/10/02 19:21:06  peiyongz
 * Implementation of Serialization/Deserialization
 *
 * Revision 1.6  2003/05/15 18:53:26  knoaman
 * Partial implementation of the configurable memory manager.
 *
 * Revision 1.5  2002/12/18 14:17:55  gareth
 * Fix to bug #13438. When you eant a vector that calls delete[] on its members you should use RefArrayVectorOf.
 *
 * Revision 1.4  2002/11/04 14:53:27  tng
 * C++ Namespace Support.
 *
 * Revision 1.3  2002/10/18 16:52:14  peiyongz
 * Patch to Bug#13640: Getter methods not public in
 *                                    DecimalDatatypeValidator
 *
 * Revision 1.2  2002/02/14 15:17:31  peiyongz
 * getEnumString()
 *
 * Revision 1.1.1.1  2002/02/01 22:22:39  peiyongz
 * sane_include
 *
 * Revision 1.3  2001/11/22 20:23:20  peiyongz
 * _declspec(dllimport) and inline warning C4273
 *
 * Revision 1.2  2001/11/12 20:37:57  peiyongz
 * SchemaDateTimeException defined
 *
 * Revision 1.1  2001/10/01 16:13:56  peiyongz
 * DTV Reorganization:new classes: AbstractNumericFactValidator/ AbstractNumericValidator
 *
 */

#if !defined(ABSTRACT_NUMERIC_FACET_VALIDATOR_HPP)
#define ABSTRACT_NUMERIC_FACET_VALIDATOR_HPP

#include <xercesc/validators/datatype/DatatypeValidator.hpp>
#include <xercesc/util/RefArrayVectorOf.hpp>
#include <xercesc/util/XMLNumber.hpp>

XERCES_CPP_NAMESPACE_BEGIN

class VALIDATORS_EXPORT AbstractNumericFacetValidator : public DatatypeValidator
{
public:

    // -----------------------------------------------------------------------
    //  Public ctor/dtor
    // -----------------------------------------------------------------------
	/** @name Constructor. */
    //@{

    virtual ~AbstractNumericFacetValidator();

	//@}

	virtual const RefArrayVectorOf<XMLCh>* getEnumString() const;

    /***
     * Support for Serialization/De-serialization
     ***/
    DECL_XSERIALIZABLE(AbstractNumericFacetValidator)

protected:

    AbstractNumericFacetValidator
    (
        DatatypeValidator* const baseValidator
        , RefHashTableOf<KVStringPair>* const facets
        , const int finalSet
        , const ValidatorType type
        , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager
    );

    void init(RefArrayVectorOf<XMLCh>*  const enums);

    //
    // Abstract interface
    //
    virtual void assignAdditionalFacet(const XMLCh* const key
                                     , const XMLCh* const value) = 0;

    virtual void inheritAdditionalFacet() = 0;

    virtual void checkAdditionalFacetConstraints() const = 0;

    virtual void checkAdditionalFacetConstraintsBase() const = 0;

    virtual int  compareValues(const XMLNumber* const lValue
                             , const XMLNumber* const rValue) = 0;

    virtual void checkContent(const XMLCh* const content
                            , bool               asBase) = 0;

// -----------------------------------------------------------------------
// Setter methods
// -----------------------------------------------------------------------

    virtual void  setMaxInclusive(const XMLCh* const) = 0;

    virtual void  setMaxExclusive(const XMLCh* const) = 0;

    virtual void  setMinInclusive(const XMLCh* const) = 0;

    virtual void  setMinExclusive(const XMLCh* const) = 0;

    virtual void  setEnumeration() = 0;

    static const int INDETERMINATE;

public:
// -----------------------------------------------------------------------
// Getter methods
// -----------------------------------------------------------------------

    inline XMLNumber* const            getMaxInclusive() const;

    inline XMLNumber* const            getMaxExclusive() const;

    inline XMLNumber* const            getMinInclusive() const;

    inline XMLNumber* const            getMinExclusive() const;

    inline RefVectorOf<XMLNumber>*     getEnumeration() const;

protected:
    // -----------------------------------------------------------------------
    //  Protected data members
    //
    //      Allow access to derived class
    //
    // -----------------------------------------------------------------------
    bool                     fMaxInclusiveInherited;
    bool                     fMaxExclusiveInherited;
    bool                     fMinInclusiveInherited;
    bool                     fMinExclusiveInherited;
    bool                     fEnumerationInherited;

    XMLNumber*               fMaxInclusive;
    XMLNumber*               fMaxExclusive;
    XMLNumber*               fMinInclusive;
    XMLNumber*               fMinExclusive;

    RefVectorOf<XMLNumber>*  fEnumeration;    // save the actual value
    RefArrayVectorOf<XMLCh>*      fStrEnumeration;

private:

    void assignFacet();

    void inspectFacet();

    void inspectFacetBase();

    void inheritFacet();

    XMLNumber*          readNumber(XMLNumber::NumberType   numType
                                 , XSerializeEngine&       serEng);

};

// -----------------------------------------------------------------------
// Getter methods
// -----------------------------------------------------------------------

inline XMLNumber* const AbstractNumericFacetValidator::getMaxInclusive() const
{
    return fMaxInclusive;
}

inline XMLNumber* const AbstractNumericFacetValidator::getMaxExclusive() const
{
    return fMaxExclusive;
}

inline XMLNumber* const AbstractNumericFacetValidator::getMinInclusive() const
{
    return fMinInclusive;
}

inline XMLNumber* const AbstractNumericFacetValidator::getMinExclusive() const
{
    return fMinExclusive;
}

inline RefVectorOf<XMLNumber>* AbstractNumericFacetValidator::getEnumeration() const
{
    return fEnumeration;
}

XERCES_CPP_NAMESPACE_END

#endif

/**
  * End of file AbstractNumericFacetValidator.hpp
  */
<commit_msg>loadNumber() moved to XMLNumber<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 * $Log$
 * Revision 1.8  2003/10/17 21:13:24  peiyongz
 * loadNumber() moved to XMLNumber
 *
 * Revision 1.7  2003/10/02 19:21:06  peiyongz
 * Implementation of Serialization/Deserialization
 *
 * Revision 1.6  2003/05/15 18:53:26  knoaman
 * Partial implementation of the configurable memory manager.
 *
 * Revision 1.5  2002/12/18 14:17:55  gareth
 * Fix to bug #13438. When you eant a vector that calls delete[] on its members you should use RefArrayVectorOf.
 *
 * Revision 1.4  2002/11/04 14:53:27  tng
 * C++ Namespace Support.
 *
 * Revision 1.3  2002/10/18 16:52:14  peiyongz
 * Patch to Bug#13640: Getter methods not public in
 *                                    DecimalDatatypeValidator
 *
 * Revision 1.2  2002/02/14 15:17:31  peiyongz
 * getEnumString()
 *
 * Revision 1.1.1.1  2002/02/01 22:22:39  peiyongz
 * sane_include
 *
 * Revision 1.3  2001/11/22 20:23:20  peiyongz
 * _declspec(dllimport) and inline warning C4273
 *
 * Revision 1.2  2001/11/12 20:37:57  peiyongz
 * SchemaDateTimeException defined
 *
 * Revision 1.1  2001/10/01 16:13:56  peiyongz
 * DTV Reorganization:new classes: AbstractNumericFactValidator/ AbstractNumericValidator
 *
 */

#if !defined(ABSTRACT_NUMERIC_FACET_VALIDATOR_HPP)
#define ABSTRACT_NUMERIC_FACET_VALIDATOR_HPP

#include <xercesc/validators/datatype/DatatypeValidator.hpp>
#include <xercesc/util/RefArrayVectorOf.hpp>
#include <xercesc/util/XMLNumber.hpp>

XERCES_CPP_NAMESPACE_BEGIN

class VALIDATORS_EXPORT AbstractNumericFacetValidator : public DatatypeValidator
{
public:

    // -----------------------------------------------------------------------
    //  Public ctor/dtor
    // -----------------------------------------------------------------------
	/** @name Constructor. */
    //@{

    virtual ~AbstractNumericFacetValidator();

	//@}

	virtual const RefArrayVectorOf<XMLCh>* getEnumString() const;

    /***
     * Support for Serialization/De-serialization
     ***/
    DECL_XSERIALIZABLE(AbstractNumericFacetValidator)

protected:

    AbstractNumericFacetValidator
    (
        DatatypeValidator* const baseValidator
        , RefHashTableOf<KVStringPair>* const facets
        , const int finalSet
        , const ValidatorType type
        , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager
    );

    void init(RefArrayVectorOf<XMLCh>*  const enums);

    //
    // Abstract interface
    //
    virtual void assignAdditionalFacet(const XMLCh* const key
                                     , const XMLCh* const value) = 0;

    virtual void inheritAdditionalFacet() = 0;

    virtual void checkAdditionalFacetConstraints() const = 0;

    virtual void checkAdditionalFacetConstraintsBase() const = 0;

    virtual int  compareValues(const XMLNumber* const lValue
                             , const XMLNumber* const rValue) = 0;

    virtual void checkContent(const XMLCh* const content
                            , bool               asBase) = 0;

// -----------------------------------------------------------------------
// Setter methods
// -----------------------------------------------------------------------

    virtual void  setMaxInclusive(const XMLCh* const) = 0;

    virtual void  setMaxExclusive(const XMLCh* const) = 0;

    virtual void  setMinInclusive(const XMLCh* const) = 0;

    virtual void  setMinExclusive(const XMLCh* const) = 0;

    virtual void  setEnumeration() = 0;

    static const int INDETERMINATE;

public:
// -----------------------------------------------------------------------
// Getter methods
// -----------------------------------------------------------------------

    inline XMLNumber* const            getMaxInclusive() const;

    inline XMLNumber* const            getMaxExclusive() const;

    inline XMLNumber* const            getMinInclusive() const;

    inline XMLNumber* const            getMinExclusive() const;

    inline RefVectorOf<XMLNumber>*     getEnumeration() const;

protected:
    // -----------------------------------------------------------------------
    //  Protected data members
    //
    //      Allow access to derived class
    //
    // -----------------------------------------------------------------------
    bool                     fMaxInclusiveInherited;
    bool                     fMaxExclusiveInherited;
    bool                     fMinInclusiveInherited;
    bool                     fMinExclusiveInherited;
    bool                     fEnumerationInherited;

    XMLNumber*               fMaxInclusive;
    XMLNumber*               fMaxExclusive;
    XMLNumber*               fMinInclusive;
    XMLNumber*               fMinExclusive;

    RefVectorOf<XMLNumber>*  fEnumeration;    // save the actual value
    RefArrayVectorOf<XMLCh>*      fStrEnumeration;

private:

    void assignFacet();

    void inspectFacet();

    void inspectFacetBase();

    void inheritFacet();

};

// -----------------------------------------------------------------------
// Getter methods
// -----------------------------------------------------------------------

inline XMLNumber* const AbstractNumericFacetValidator::getMaxInclusive() const
{
    return fMaxInclusive;
}

inline XMLNumber* const AbstractNumericFacetValidator::getMaxExclusive() const
{
    return fMaxExclusive;
}

inline XMLNumber* const AbstractNumericFacetValidator::getMinInclusive() const
{
    return fMinInclusive;
}

inline XMLNumber* const AbstractNumericFacetValidator::getMinExclusive() const
{
    return fMinExclusive;
}

inline RefVectorOf<XMLNumber>* AbstractNumericFacetValidator::getEnumeration() const
{
    return fEnumeration;
}

XERCES_CPP_NAMESPACE_END

#endif

/**
  * End of file AbstractNumericFacetValidator.hpp
  */
<|endoftext|>


<commit_before>
#include "core.h"

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Instructions.h"

#include "llvm/Support/raw_ostream.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/RegionPass.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/Analysis/RegionPrinter.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/DomPrinter.h"
#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"

#include "llvm/Transforms/Scalar.h"

#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

#include "llvm/InitializePasses.h"
#include "llvm/LinkAllPasses.h"

#include <vector>

using namespace llvm;

namespace llvm {
    void initializeRefPrunePassPass(PassRegistry &Registry);
}
/*
struct Hello : public RegionPass {
  static char ID;
  Hello() : RegionPass(ID) {
      initializeHelloPass(*PassRegistry::getPassRegistry());
  }

  bool runOnRegion(Region *region, RGPassManager &RGM) override {
    errs() << "Hello: ";
    errs().write_escaped(region->getNameStr()) << '\n';
    return false;
  }
}; // end of struct Hello
*/

struct RefPrunePass : public FunctionPass {
  static char ID;
  RefPrunePass() : FunctionPass(ID) {
      initializeRefPrunePassPass(*PassRegistry::getPassRegistry());
  }

  bool runOnFunction(Function &F) override {
    errs() << "NRT_RefPrunePass\n";
    errs().write_escaped(F.getName()) << '\n';

    auto &domtree = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
    auto &postdomtree = getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();

    // domtree.viewGraph();   // view domtree
    // postdomtree.viewGraph();

    bool mutated = false;

    // Find all incref & decref
    std::vector<CallInst*> incref_list, decref_list;
    for (BasicBlock &bb : F) {
        for (Instruction &ii : bb) {
            if (ii.getOpcode() == Instruction::Call) {
                CallInst *call_inst = dyn_cast<CallInst>(&ii);
                // TODO: handle call_inst being NULL
                Value *callee = call_inst->getCalledOperand();
                if ( callee->getName() == "NRT_incref" ) {
                    incref_list.push_back(call_inst);
                } else if ( callee->getName() == "NRT_decref" ) {
                    decref_list.push_back(call_inst);
                }
            }
        }
    }

    errs() << "Counts " << incref_list.size() << " " << decref_list.size() << "\n";

    // Drop refops on NULL pointers
    for (CallInst*& refop: incref_list) {
        if (!keepNonNullArg(refop)) {
            refop->eraseFromParent();
            mutated |= true;
            refop = NULL;
        }
    }
    for (CallInst*& refop: decref_list) {
        if (!keepNonNullArg(refop)) {
            refop->eraseFromParent();
            mutated |= true;
            refop = NULL;
        }
    }

    // check pairs that are dominating and postdominating each other
    for (CallInst* incref: incref_list) {
        if (incref == NULL) continue;

        for (CallInst*& decref: decref_list) {
            if (decref == NULL) continue;

            if (incref->getArgOperand(0) != decref->getArgOperand(0) )
                continue;

            if ( domtree.dominates(incref, decref)
                    && postdomtree.dominates(decref, incref) ){
                errs() << "Prune these due to DOM + PDOM\n";
                incref->dump();
                decref->dump();
                errs() << "\n";
                incref->eraseFromParent();
                decref->eraseFromParent();
                decref = NULL;
                mutated |= true;
                continue;
            }
        }
    }
    return mutated;
  }

   void getAnalysisUsage(AnalysisUsage &Info) const override {
       Info.addRequired<DominatorTreeWrapperPass>();
       Info.addRequired<PostDominatorTreeWrapperPass>();
   }

   bool keepNonNullArg(CallInst *call_inst){
       auto val = call_inst->getArgOperand(0);
       auto ptr = dyn_cast<ConstantPointerNull>(val);
       return ptr == NULL;
   }
}; // end of struct RefPrunePass

char RefPrunePass::ID = 0;

INITIALIZE_PASS_BEGIN(RefPrunePass, "nrtrefprunepass",
                      "Prune NRT refops", false, false)
// INITIALIZE_PASS_DEPENDENCY(RegionInfoPass)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)

INITIALIZE_PASS_END(RefPrunePass, "refprunepass",
                    "Prune NRT refops", false, false)

extern "C" {

API_EXPORT(void)
LLVMPY_AddRefPrunePass(LLVMPassManagerRef PM)
{
    // unwrap(PM)->add(createStructurizeCFGPass());
    // unwrap(PM)->add(createUnifyFunctionExitNodesPass());
    // unwrap(PM)->add(createPromoteMemoryToRegisterPass());
    // unwrap(PM)->add(createInstSimplifyLegacyPass());
    unwrap(PM)->add(new RefPrunePass());
}

} // extern "C"<commit_msg>Handle basic fanout case in refops pruning<commit_after>
#include "core.h"

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Instructions.h"

#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SetVector.h"

#include "llvm/Support/raw_ostream.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/RegionPass.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/Analysis/RegionPrinter.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/DomPrinter.h"
#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"

#include "llvm/Transforms/Scalar.h"

#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

#include "llvm/InitializePasses.h"
#include "llvm/LinkAllPasses.h"

#include <vector>
#include <map>

using namespace llvm;

namespace llvm {
    void initializeRefPrunePassPass(PassRegistry &Registry);
}

struct RefPrunePass : public FunctionPass {
  static char ID;
  RefPrunePass() : FunctionPass(ID) {
      initializeRefPrunePassPass(*PassRegistry::getPassRegistry());
  }

  bool runOnFunction(Function &F) override {
    errs() << "NRT_RefPrunePass\n";
    errs().write_escaped(F.getName()) << '\n';

    auto &domtree = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
    auto &postdomtree = getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();

    // domtree.viewGraph();   // view domtree
    // postdomtree.viewGraph();

    bool mutated = false;

    // Find all incref & decref
    SmallVector<CallInst*, 20> incref_list, decref_list;
    for (BasicBlock &bb : F) {
        for (Instruction &ii : bb) {
            if (ii.getOpcode() == Instruction::Call) {
                CallInst *call_inst = dyn_cast<CallInst>(&ii);
                // TODO: handle call_inst being NULL
                Value *callee = call_inst->getCalledOperand();
                if ( callee->getName() == "NRT_incref" ) {
                    incref_list.push_back(call_inst);
                } else if ( callee->getName() == "NRT_decref" ) {
                    decref_list.push_back(call_inst);
                }
            }
        }
    }

    errs() << "Counts " << incref_list.size() << " " << decref_list.size() << "\n";

    // Drop refops on NULL pointers
    mutated |= eraseNullFirstArgFromList(incref_list);
    mutated |= eraseNullFirstArgFromList(decref_list);

    // Check pairs that are dominating and postdominating each other
    for (CallInst* incref: incref_list) {
        if (incref == NULL) continue;

        for (CallInst*& decref: decref_list) {
            if (decref == NULL) continue;

            if (incref->getArgOperand(0) != decref->getArgOperand(0) )
                continue;

            if ( domtree.dominates(incref, decref)
                    && postdomtree.dominates(decref, incref) ){
                errs() << "Prune these due to DOM + PDOM\n";
                incref->dump();
                decref->dump();
                errs() << "\n";
                incref->eraseFromParent();
                decref->eraseFromParent();
                decref = NULL;
                mutated |= true;
            }
        }
    }

    // Deal with fanout
    // a single incref with multiple decrefs in outgoing edges
    for (CallInst*& incref : incref_list) {
        if (incref == NULL) continue;

        SetVector<CallInst*> candidates;

        Instruction* term = incref->getParent()->getTerminator();

        bool balanced = true;
        errs() << "======= AT\n" ;
        incref->dump();
        for (unsigned int i = 0; i < term->getNumSuccessors(); ++i) {
            DomTreeNode* domchild = domtree.getNode(term->getSuccessor(i));

            errs() << "==== check " << domchild->getBlock()->getName() << "\n";
            if (!findDecrefDominatedByNode(domtree, postdomtree, domchild, incref,
                                           candidates)) {
                balanced = false;
            }
        }
        if (balanced) {
            errs() << "======balanced" << "\n";
            for (CallInst* inst : candidates)  {
                inst->dump();
            }
            errs() << "======" << "\n";
            incref->eraseFromParent();
            for (CallInst* inst : candidates)  {
                inst->eraseFromParent();
            }
            incref = NULL;
            mutated |= true;
        }

    }
    return mutated;
  }

  template <class T>
  bool eraseNullFirstArgFromList(T& refops) {
    bool mutated = false;
    for (CallInst*& refop: refops) {
        if (!isNonNullFirstArg(refop)) {
            refop->eraseFromParent();
            mutated |= true;
            refop = NULL;
        }
    }
    return mutated;
  }

  bool findDecrefDominatedByNode(DominatorTree &domtree,
                               PostDominatorTree &postdomtree,
                               DomTreeNode* dom_root,
                               CallInst* incref,
                               SetVector<CallInst*> &candidates,
                               unsigned int depth = 0) {

    bool found = false;
    BasicBlock* bb_root = dom_root->getBlock();

    errs() << "   -- findDecrefDominatedByNode: " << bb_root->getName() << "\n";

    for (CallInst *decref : findRelatedDecrefs(dom_root->getBlock(), incref) ){
        if ( domtree.dominates(incref, decref) ){
            errs() << "   found\n";
            decref->dump();

            candidates.insert(decref);
            found = true;
            // stop on first result
            break;
        }
    }

    if (found) return true;

    for (DomTreeNode* dom_child : dom_root->getChildren()) {
        if (!findDecrefDominatedByNode(domtree, postdomtree, dom_child, incref, candidates)) {
            return false;
        }
    }
    return true;
  }

  /**
   * Find related decrefs to incref inside a basicblock in order
   */
  std::vector<CallInst*> findRelatedDecrefs(BasicBlock* bb, CallInst* incref) {
      std::vector<CallInst*> res;
      for (Instruction &ii : *bb) {
        if (ii.getOpcode() == Instruction::Call) {
            CallInst *call_inst = dyn_cast<CallInst>(&ii);
            Value *callee = call_inst->getCalledOperand();
            if ( callee->getName() != "NRT_decref" ) {
                continue;
            }
            if (incref->getArgOperand(0) != call_inst->getArgOperand(0)) {
                continue;
            }
            res.push_back(call_inst);
        }
      }
      return res;
  }

   void getAnalysisUsage(AnalysisUsage &Info) const override {
       Info.addRequired<DominatorTreeWrapperPass>();
       Info.addRequired<PostDominatorTreeWrapperPass>();
   }

   bool isNonNullFirstArg(CallInst *call_inst){
       auto val = call_inst->getArgOperand(0);
       auto ptr = dyn_cast<ConstantPointerNull>(val);
       return ptr == NULL;
   }
}; // end of struct RefPrunePass

char RefPrunePass::ID = 0;

INITIALIZE_PASS_BEGIN(RefPrunePass, "nrtrefprunepass",
                      "Prune NRT refops", false, false)
// INITIALIZE_PASS_DEPENDENCY(RegionInfoPass)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)

INITIALIZE_PASS_END(RefPrunePass, "refprunepass",
                    "Prune NRT refops", false, false)

extern "C" {

API_EXPORT(void)
LLVMPY_AddRefPrunePass(LLVMPassManagerRef PM)
{
    // unwrap(PM)->add(createStructurizeCFGPass());
    // unwrap(PM)->add(createUnifyFunctionExitNodesPass());
    // unwrap(PM)->add(createPromoteMemoryToRegisterPass());
    // unwrap(PM)->add(createInstSimplifyLegacyPass());
    unwrap(PM)->add(new RefPrunePass());
}

} // extern "C"<|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_SESSION_STATUS_HPP_INCLUDED
#define TORRENT_SESSION_STATUS_HPP_INCLUDED

namespace libtorrent
{

#ifndef TORRENT_DISABLE_DHT

	struct dht_lookup
	{
		char const* type;
		int outstanding_requests;
		int timeouts;
		int responses;
		int branch_factor;
	};

#endif

	struct TORRENT_EXPORT session_status
	{
		bool has_incoming_connections;

		float upload_rate;
		float download_rate;
		size_type total_download;
		size_type total_upload;

		float payload_upload_rate;
		float payload_download_rate;
		size_type total_payload_download;
		size_type total_payload_upload;

		float ip_overhead_upload_rate;
		float ip_overhead_download_rate;
		size_type total_ip_overhead_download;
		size_type total_ip_overhead_upload;

		float dht_upload_rate;
		float dht_download_rate;
		size_type total_dht_download;
		size_type total_dht_upload;

		float tracker_upload_rate;
		float tracker_download_rate;
		size_type total_tracker_download;
		size_type total_tracker_upload;

		size_type total_redundant_bytes;
		size_type total_failed_bytes;

		int num_peers;
		int num_unchoked;
		int allowed_upload_slots;

		int up_bandwidth_queue;
		int down_bandwidth_queue;

		int optimistic_unchoke_counter;
		int unchoke_counter;

#ifndef TORRENT_DISABLE_DHT
		int dht_nodes;
		int dht_node_cache;
		int dht_torrents;
		size_type dht_global_nodes;
		std::vector<dht_lookup> active_requests;
#endif
	};

}

#endif // TORRENT_SESSION_STATUS_HPP_INCLUDED

<commit_msg>fixed missing includes in header<commit_after>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_SESSION_STATUS_HPP_INCLUDED
#define TORRENT_SESSION_STATUS_HPP_INCLUDED

#include "libtorrent/config.hpp"
#include "libtorrent/size_type.hpp"

namespace libtorrent
{

#ifndef TORRENT_DISABLE_DHT

	struct dht_lookup
	{
		char const* type;
		int outstanding_requests;
		int timeouts;
		int responses;
		int branch_factor;
	};

#endif

	struct TORRENT_EXPORT session_status
	{
		bool has_incoming_connections;

		float upload_rate;
		float download_rate;
		size_type total_download;
		size_type total_upload;

		float payload_upload_rate;
		float payload_download_rate;
		size_type total_payload_download;
		size_type total_payload_upload;

		float ip_overhead_upload_rate;
		float ip_overhead_download_rate;
		size_type total_ip_overhead_download;
		size_type total_ip_overhead_upload;

		float dht_upload_rate;
		float dht_download_rate;
		size_type total_dht_download;
		size_type total_dht_upload;

		float tracker_upload_rate;
		float tracker_download_rate;
		size_type total_tracker_download;
		size_type total_tracker_upload;

		size_type total_redundant_bytes;
		size_type total_failed_bytes;

		int num_peers;
		int num_unchoked;
		int allowed_upload_slots;

		int up_bandwidth_queue;
		int down_bandwidth_queue;

		int optimistic_unchoke_counter;
		int unchoke_counter;

#ifndef TORRENT_DISABLE_DHT
		int dht_nodes;
		int dht_node_cache;
		int dht_torrents;
		size_type dht_global_nodes;
		std::vector<dht_lookup> active_requests;
#endif
	};

}

#endif // TORRENT_SESSION_STATUS_HPP_INCLUDED

<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

#include "tensorflow/compiler/xla/service/llvm_ir/kernel_support_library.h"

#include "tensorflow/compiler/xla/service/llvm_ir/llvm_util.h"

namespace xla {
Status KernelSupportLibrary::ForWithStatus(
    absl::string_view name, llvm::Value* start, llvm::Value* end,
    llvm::Value* step,
    const std::function<Status(llvm::Value*, bool)>& for_body_generator) {
  return IfWithStatus(b_->CreateICmpSLT(start, end), [&]() -> Status {
    TF_RETURN_IF_ERROR(for_body_generator(start, /*is_first_iteration=*/true));
    return ForWithStatus(
        name, b_->CreateAdd(start, step), end, step,
        [&](llvm::Value* iv) { return for_body_generator(iv, false); });
  });
}

Status KernelSupportLibrary::ForWithStatus(
    absl::string_view name, llvm::Value* start, llvm::Value* end,
    llvm::Value* step, bool peel_first_iteration,
    const std::function<Status(llvm::Value*, llvm::Value*)>&
        for_body_generator) {
  if (peel_first_iteration) {
    return ForWithStatus(
        name, start, end, step, true,
        [&](llvm::Value* indvar, bool is_first_iteration) -> Status {
          return for_body_generator(indvar, b_->getInt1(is_first_iteration));
        });
  } else {
    std::unique_ptr<llvm_ir::ForLoop> loop = llvm_ir::ForLoop::EmitForLoop(
        name, start, end, step, b_,
        /*unroll_mode=*/unroll_mode_,
        /*prevent_vectorization=*/prevent_vectorization_);
    b_->SetInsertPoint(&loop->GetBodyBasicBlock()->back());
    TF_RETURN_IF_ERROR(
        for_body_generator(loop->GetIndVarValue(),
                           /*is_first_iteration=*/b_->CreateICmpEQ(
                               loop->GetIndVarValue(), start)));
    llvm_ir::SetToLastInsertPoint(loop->GetExitBasicBlock(), b_);
    return Status::OK();
  }
}

Status KernelSupportLibrary::IfWithStatus(
    absl::string_view name, llvm::Value* condition,
    const std::function<Status()>& true_block_generator,
    const std::function<Status()>& false_block_generator) {
  llvm_ir::LlvmIfData if_data = llvm_ir::EmitIfThenElse(
      condition, name, b_, false_block_generator != nullptr);
  b_->SetInsertPoint(&if_data.true_block->back());
  TF_RETURN_IF_ERROR(true_block_generator());
  if (false_block_generator != nullptr) {
    b_->SetInsertPoint(&if_data.false_block->back());
    TF_RETURN_IF_ERROR(false_block_generator());
  }
  llvm_ir::SetToLastInsertPoint(if_data.after_block, b_);
  return Status::OK();
}

void KernelSupportLibrary::EmitAndCallOutlinedKernel(
    const HloModuleConfig& module_config, llvm::IRBuilder<>* b,
    absl::string_view kernel_name,
    KernelSupportLibrary::ArgumentVector arguments,
    const std::function<void(KernelSupportLibrary::ArgumentVector)>&
        kernel_body_generator) {
  llvm::Module* module = b->GetInsertBlock()->getModule();
  llvm::Function* function =
      module->getFunction(llvm_ir::AsStringRef(kernel_name));

  int64 null_arg_idx = -1;
  std::vector<llvm::Value*> sanitized_args;
  sanitized_args.reserve(arguments.size());
  for (int64 i = 0, e = arguments.size(); i < e; i++) {
    if (arguments[i]) {
      sanitized_args.push_back(arguments[i]);
    } else {
      CHECK_EQ(null_arg_idx, -1);
      null_arg_idx = i;
    }
  }

  if (!function) {
    VLOG(2) << "Generating kernel for " << kernel_name;
    std::vector<llvm::Type*> arg_types;
    std::transform(sanitized_args.begin(), sanitized_args.end(),
                   std::back_inserter(arg_types),
                   [](llvm::Value* arg) { return arg->getType(); });

    auto* function_type =
        llvm::FunctionType::get(b->getVoidTy(), arg_types, /*isVarArg=*/false);

    function = llvm_ir::CreateCpuFunction(function_type,
                                          llvm::GlobalValue::InternalLinkage,
                                          module_config, kernel_name, module);

    llvm::IRBuilder<>::InsertPointGuard guard(*b);

    auto* entry_bb =
        llvm::BasicBlock::Create(b->getContext(), "entry", function);
    auto* return_inst = llvm::ReturnInst::Create(b->getContext(),
                                                 /*retVal=*/nullptr, entry_bb);
    // Set the insert point to before return_inst.
    b->SetInsertPoint(return_inst);

    std::vector<llvm::Value*> arg_values;
    /*
     * clang on OSX doesn't like std::transform or range for loop here.
     * See https://github.com/tensorflow/tensorflow/issues/15196
     */
    for (llvm::Function::arg_iterator arg = function->arg_begin(),
                                      arg_e = function->arg_end();
         arg != arg_e; ++arg) {
      arg_values.push_back(arg);
    }
    if (null_arg_idx != -1) {
      arg_values.insert(arg_values.begin() + null_arg_idx, nullptr);
    }
    kernel_body_generator(arg_values);
  } else {
    VLOG(3) << "Re-using kernel for " << kernel_name;
  }

  b->CreateCall(function, llvm_ir::AsArrayRef(sanitized_args));
}

}  // namespace xla
<commit_msg>Add comment for parameter name.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

#include "tensorflow/compiler/xla/service/llvm_ir/kernel_support_library.h"

#include "tensorflow/compiler/xla/service/llvm_ir/llvm_util.h"

namespace xla {
Status KernelSupportLibrary::ForWithStatus(
    absl::string_view name, llvm::Value* start, llvm::Value* end,
    llvm::Value* step,
    const std::function<Status(llvm::Value*, bool)>& for_body_generator) {
  return IfWithStatus(b_->CreateICmpSLT(start, end), [&]() -> Status {
    TF_RETURN_IF_ERROR(for_body_generator(start, /*is_first_iteration=*/true));
    return ForWithStatus(
        name, b_->CreateAdd(start, step), end, step,
        [&](llvm::Value* iv) { return for_body_generator(iv, false); });
  });
}

Status KernelSupportLibrary::ForWithStatus(
    absl::string_view name, llvm::Value* start, llvm::Value* end,
    llvm::Value* step, bool peel_first_iteration,
    const std::function<Status(llvm::Value*, llvm::Value*)>&
        for_body_generator) {
  if (peel_first_iteration) {
    return ForWithStatus(
        name, start, end, step, true,
        [&](llvm::Value* indvar, bool is_first_iteration) -> Status {
          return for_body_generator(indvar, b_->getInt1(is_first_iteration));
        });
  } else {
    std::unique_ptr<llvm_ir::ForLoop> loop = llvm_ir::ForLoop::EmitForLoop(
        name, start, end, step, b_,
        /*unroll_mode=*/unroll_mode_,
        /*prevent_vectorization=*/prevent_vectorization_);
    b_->SetInsertPoint(&loop->GetBodyBasicBlock()->back());
    TF_RETURN_IF_ERROR(
        for_body_generator(loop->GetIndVarValue(),
                           /*is_first_iteration=*/b_->CreateICmpEQ(
                               loop->GetIndVarValue(), start)));
    llvm_ir::SetToLastInsertPoint(loop->GetExitBasicBlock(), b_);
    return Status::OK();
  }
}

Status KernelSupportLibrary::IfWithStatus(
    absl::string_view name, llvm::Value* condition,
    const std::function<Status()>& true_block_generator,
    const std::function<Status()>& false_block_generator) {
  llvm_ir::LlvmIfData if_data =
      llvm_ir::EmitIfThenElse(condition, name, b_,
                              /*emit_else=*/false_block_generator != nullptr);
  b_->SetInsertPoint(&if_data.true_block->back());
  TF_RETURN_IF_ERROR(true_block_generator());
  if (false_block_generator != nullptr) {
    b_->SetInsertPoint(&if_data.false_block->back());
    TF_RETURN_IF_ERROR(false_block_generator());
  }
  llvm_ir::SetToLastInsertPoint(if_data.after_block, b_);
  return Status::OK();
}

void KernelSupportLibrary::EmitAndCallOutlinedKernel(
    const HloModuleConfig& module_config, llvm::IRBuilder<>* b,
    absl::string_view kernel_name,
    KernelSupportLibrary::ArgumentVector arguments,
    const std::function<void(KernelSupportLibrary::ArgumentVector)>&
        kernel_body_generator) {
  llvm::Module* module = b->GetInsertBlock()->getModule();
  llvm::Function* function =
      module->getFunction(llvm_ir::AsStringRef(kernel_name));

  int64 null_arg_idx = -1;
  std::vector<llvm::Value*> sanitized_args;
  sanitized_args.reserve(arguments.size());
  for (int64 i = 0, e = arguments.size(); i < e; i++) {
    if (arguments[i]) {
      sanitized_args.push_back(arguments[i]);
    } else {
      CHECK_EQ(null_arg_idx, -1);
      null_arg_idx = i;
    }
  }

  if (!function) {
    VLOG(2) << "Generating kernel for " << kernel_name;
    std::vector<llvm::Type*> arg_types;
    std::transform(sanitized_args.begin(), sanitized_args.end(),
                   std::back_inserter(arg_types),
                   [](llvm::Value* arg) { return arg->getType(); });

    auto* function_type =
        llvm::FunctionType::get(b->getVoidTy(), arg_types, /*isVarArg=*/false);

    function = llvm_ir::CreateCpuFunction(function_type,
                                          llvm::GlobalValue::InternalLinkage,
                                          module_config, kernel_name, module);

    llvm::IRBuilder<>::InsertPointGuard guard(*b);

    auto* entry_bb =
        llvm::BasicBlock::Create(b->getContext(), "entry", function);
    auto* return_inst = llvm::ReturnInst::Create(b->getContext(),
                                                 /*retVal=*/nullptr, entry_bb);
    // Set the insert point to before return_inst.
    b->SetInsertPoint(return_inst);

    std::vector<llvm::Value*> arg_values;
    /*
     * clang on OSX doesn't like std::transform or range for loop here.
     * See https://github.com/tensorflow/tensorflow/issues/15196
     */
    for (llvm::Function::arg_iterator arg = function->arg_begin(),
                                      arg_e = function->arg_end();
         arg != arg_e; ++arg) {
      arg_values.push_back(arg);
    }
    if (null_arg_idx != -1) {
      arg_values.insert(arg_values.begin() + null_arg_idx, nullptr);
    }
    kernel_body_generator(arg_values);
  } else {
    VLOG(3) << "Re-using kernel for " << kernel_name;
  }

  b->CreateCall(function, llvm_ir::AsArrayRef(sanitized_args));
}

}  // namespace xla
<|endoftext|>


<commit_before>/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          http://www.mrpt.org/                          |
   |                                                                        |
   | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file     |
   | See: http://www.mrpt.org/Authors - All rights reserved.                |
   | Released under BSD License. See details in http://www.mrpt.org/License |
   +------------------------------------------------------------------------+ */

#include "system-precomp.h"  // Precompiled headers

#include <mrpt/system/datetime.h>
#include <mrpt/system/os.h>
#include <mrpt/core/exceptions.h>

#ifdef _WIN32
#include <conio.h>
#include <windows.h>
#include <process.h>
#include <tlhelp32.h>
#include <sys/utime.h>
#include <io.h>
#include <direct.h>
#else
#include <pthread.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <utime.h>
#include <cerrno>
#endif

#include <ctime>
#include <sys/types.h>
#include <sys/stat.h>
#include <cmath>  // floor()
#include <iostream>  // for the << operator

using namespace mrpt;
using namespace mrpt::system;
using namespace std;

mrpt::system::TTimeStamp mrpt::system::time_tToTimestamp(const time_t& t)
{
	return time_tToTimestamp(static_cast<double>(t));
}

double mrpt::system::timestampTotime_t(const mrpt::system::TTimeStamp t)
{
	return double(
			   t.time_since_epoch().count() -
			   UINT64_C(116444736) * UINT64_C(1000000000)) /
		   10000000.0;
}

/*---------------------------------------------------------------
					timestampToParts
  ---------------------------------------------------------------*/
void mrpt::system::timestampToParts(TTimeStamp t, TTimeParts& p, bool localTime)
{
	const double T = mrpt::system::timestampTotime_t(t);
	double sec_frac = T - floor(T);
	ASSERT_(sec_frac < 1.0);

	const time_t tt = time_t(T);

	struct tm* parts = localTime ? localtime(&tt) : gmtime(&tt);
	ASSERTMSG_(parts, "Malformed timestamp");

	p.year = parts->tm_year + 1900;
	p.month = parts->tm_mon + 1;
	p.day = parts->tm_mday;
	p.day_of_week = parts->tm_wday + 1;
	p.daylight_saving = parts->tm_isdst;
	p.hour = parts->tm_hour;
	p.minute = parts->tm_min;
	p.second = parts->tm_sec + sec_frac;
}

/*---------------------------------------------------------------
					buildTimestampFromParts
  ---------------------------------------------------------------*/
TTimeStamp mrpt::system::buildTimestampFromParts(const TTimeParts& p)
{
	struct tm parts;

	parts.tm_year = p.year - 1900;
	parts.tm_mon = p.month - 1;
	parts.tm_mday = p.day;
	parts.tm_wday = p.day_of_week - 1;
	parts.tm_isdst = p.daylight_saving;
	parts.tm_hour = p.hour;
	parts.tm_min = p.minute;
	parts.tm_sec = int(p.second);

	double sec_frac = p.second - parts.tm_sec;

	time_t tt = mrpt::system::os::timegm(&parts);  // Local time: mktime

	return mrpt::system::time_tToTimestamp(double(tt) + sec_frac);
}

/*---------------------------------------------------------------
					buildTimestampFromPartsLocalTime
  ---------------------------------------------------------------*/
TTimeStamp mrpt::system::buildTimestampFromPartsLocalTime(const TTimeParts& p)
{
	struct tm parts;

	parts.tm_year = p.year - 1900;
	parts.tm_mon = p.month - 1;
	parts.tm_mday = p.day;
	parts.tm_wday = p.day_of_week - 1;
	parts.tm_isdst = p.daylight_saving;
	parts.tm_hour = p.hour;
	parts.tm_min = p.minute;
	parts.tm_sec = int(p.second);

	double sec_frac = p.second - parts.tm_sec;

	time_t tt = mktime(&parts);

	return mrpt::system::time_tToTimestamp(double(tt) + sec_frac);
}

/*---------------------------------------------------------------
					formatTimeInterval
  ---------------------------------------------------------------*/
string mrpt::system::formatTimeInterval(const double t)
{
	double timeSeconds = (t < 0) ? (-t) : t;

	unsigned int nHours = (unsigned int)timeSeconds / 3600;
	unsigned int nMins = ((unsigned int)timeSeconds % 3600) / 60;
	unsigned int nSecs = (unsigned int)timeSeconds % 60;
	unsigned int milSecs =
		(unsigned int)(1000 * (timeSeconds - floor(timeSeconds)));

	return format("%02u:%02u:%02u.%03u", nHours, nMins, nSecs, milSecs);
}

/*---------------------------------------------------------------
  Convert a timestamp into this textual form: YEAR/MONTH/DAY,HH:MM:SS.MMM
  ---------------------------------------------------------------*/
string mrpt::system::dateTimeToString(const mrpt::system::TTimeStamp t)
{
	if (t == INVALID_TIMESTAMP) return string("INVALID_TIMESTAMP");

	uint64_t tmp =
		(t.time_since_epoch().count() - ((uint64_t)116444736 * 1000000000));
	time_t auxTime = tmp / (uint64_t)10000000;
	unsigned int secFractions =
		(unsigned int)(1000000 * (tmp % 10000000) / 10000000.0);
	tm* ptm = gmtime(&auxTime);

	if (!ptm) return std::string("(Malformed timestamp)");

	return format(
		"%u/%02u/%02u,%02u:%02u:%02u.%06u", 1900 + ptm->tm_year,
		ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min,
		(unsigned int)ptm->tm_sec, secFractions);
}

/*---------------------------------------------------------------
  Convert a timestamp into this textual form (in local time):
	  YEAR/MONTH/DAY,HH:MM:SS.MMM
  ---------------------------------------------------------------*/
string mrpt::system::dateTimeLocalToString(const mrpt::system::TTimeStamp t)
{
	if (t == INVALID_TIMESTAMP) return string("INVALID_TIMESTAMP");

	uint64_t tmp =
		(t.time_since_epoch().count() - ((uint64_t)116444736 * 1000000000));
	time_t auxTime = tmp / (uint64_t)10000000;
	unsigned int secFractions =
		(unsigned int)(1000000 * (tmp % 10000000) / 10000000.0);
	tm* ptm = localtime(&auxTime);

	if (!ptm) return "(Malformed timestamp)";

	return format(
		"%u/%02u/%02u,%02u:%02u:%02u.%06u", 1900 + ptm->tm_year,
		ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min,
		(unsigned int)ptm->tm_sec, secFractions);
}

/*---------------------------------------------------------------
						extractDayTimeFromTimestamp
  ---------------------------------------------------------------*/
double mrpt::system::extractDayTimeFromTimestamp(
	const mrpt::system::TTimeStamp tt)
{
	MRPT_START
	ASSERT_(tt != INVALID_TIMESTAMP);

	auto t = tt.time_since_epoch().count();
#ifdef _WIN32
	SYSTEMTIME sysT;
	FileTimeToSystemTime((FILETIME*)&t, &sysT);
	return sysT.wHour * 3600.0 + sysT.wMinute * 60.0 + sysT.wSecond +
		   sysT.wMilliseconds * 0.001;
#else
	time_t auxTime =
		(t - ((uint64_t)116444736 * 1000000000)) / (uint64_t)10000000;
	tm* ptm = gmtime(&auxTime);
	ASSERTMSG_(ptm, "Malformed timestamp");
	return ptm->tm_hour * 3600.0 + ptm->tm_min * 60.0 + ptm->tm_sec;
#endif
	MRPT_END
}

/*---------------------------------------------------------------
  Convert a timestamp into this textual form: HH:MM:SS.MMM
  ---------------------------------------------------------------*/
string mrpt::system::timeLocalToString(
	const mrpt::system::TTimeStamp tt, unsigned int secondFractionDigits)
{
	if (tt == INVALID_TIMESTAMP) return string("INVALID_TIMESTAMP");
	auto t = tt.time_since_epoch().count();

	uint64_t tmp = (t - ((uint64_t)116444736 * 1000000000));
	const time_t auxTime = tmp / (uint64_t)10000000;
	const tm* ptm = localtime(&auxTime);

	unsigned int secFractions =
		(unsigned int)(1000000 * (tmp % 10000000) / 10000000.0);
	// We start with 10^{-6} second units: reduce if requested by user:
	const unsigned int user_secondFractionDigits = secondFractionDigits;
	while (secondFractionDigits++ < 6) secFractions = secFractions / 10;

	return format(
		"%02u:%02u:%02u.%0*u", ptm->tm_hour, ptm->tm_min,
		(unsigned int)ptm->tm_sec, user_secondFractionDigits, secFractions);
}

/*---------------------------------------------------------------
  Convert a timestamp into this textual form: HH:MM:SS.MMM
  ---------------------------------------------------------------*/
string mrpt::system::timeToString(const mrpt::system::TTimeStamp tt)
{
	if (tt == INVALID_TIMESTAMP) return string("INVALID_TIMESTAMP");
	auto t = tt.time_since_epoch().count();

	uint64_t tmp = (t - ((uint64_t)116444736 * 1000000000));
	time_t auxTime = tmp / (uint64_t)10000000;
	unsigned int secFractions =
		(unsigned int)(1000000 * (tmp % 10000000) / 10000000.0);
	tm* ptm = gmtime(&auxTime);
	if (!ptm) return string("(Malformed timestamp)");

	return format(
		"%02u:%02u:%02u.%06u", ptm->tm_hour, ptm->tm_min,
		(unsigned int)ptm->tm_sec, secFractions);
}

/*---------------------------------------------------------------
  Convert a timestamp into this textual form: YEAR/MONTH/DAY
  ---------------------------------------------------------------*/
string mrpt::system::dateToString(const mrpt::system::TTimeStamp tt)
{
	if (tt == INVALID_TIMESTAMP) return string("INVALID_TIMESTAMP");
	auto t = tt.time_since_epoch().count();

	uint64_t tmp = (t - ((uint64_t)116444736 * 1000000000));
	time_t auxTime = tmp / (uint64_t)10000000;
	tm* ptm = gmtime(&auxTime);
	if (!ptm) return string("(Malformed timestamp)");

	return format(
		"%u/%02u/%02u", 1900 + ptm->tm_year, ptm->tm_mon + 1, ptm->tm_mday);
}

/** This function implements time interval formatting: Given a time in seconds,
 * it will return a string describing the interval with the most appropriate
 * unit.
 * E.g.: 1.23 year, 3.50 days, 9.3 hours, 5.3 minutes, 3.34 sec, 178.1 ms,  87.1
 * us.
 */
std::string mrpt::system::intervalFormat(const double seconds)
{
	if (seconds >= 365 * 24 * 3600)
		return format("%.2f years", seconds / (365 * 24 * 3600));
	else if (seconds >= 24 * 3600)
		return format("%.2f days", seconds / (24 * 3600));
	else if (seconds >= 3600)
		return format("%.2f hours", seconds / 3600);
	else if (seconds >= 60)
		return format("%.2f minutes", seconds / 60);
	else if (seconds >= 1)
		return format("%.2f sec", seconds);
	else if (seconds >= 1e-3)
		return format("%.2f ms", seconds * 1e3);
	else if (seconds >= 1e-6)
		return format("%.2f us", seconds * 1e6);
	else
		return format("%.2f ns", seconds * 1e9);
}

std::ostream& mrpt::system::operator<<(std::ostream& o, const TTimeStamp& t)
{
	const uint64_t v = t.time_since_epoch().count();
	o << v;
	return o;
}
<commit_msg>formatTimeInterval() prints "days" too<commit_after>/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          http://www.mrpt.org/                          |
   |                                                                        |
   | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file     |
   | See: http://www.mrpt.org/Authors - All rights reserved.                |
   | Released under BSD License. See details in http://www.mrpt.org/License |
   +------------------------------------------------------------------------+ */

#include "system-precomp.h"  // Precompiled headers

#include <mrpt/system/datetime.h>
#include <mrpt/system/os.h>
#include <mrpt/core/exceptions.h>

#ifdef _WIN32
#include <conio.h>
#include <windows.h>
#include <process.h>
#include <tlhelp32.h>
#include <sys/utime.h>
#include <io.h>
#include <direct.h>
#else
#include <pthread.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <utime.h>
#include <cerrno>
#endif

#include <ctime>
#include <sys/types.h>
#include <sys/stat.h>
#include <cmath>  // floor()
#include <iostream>  // for the << operator

using namespace mrpt;
using namespace mrpt::system;
using namespace std;

mrpt::system::TTimeStamp mrpt::system::time_tToTimestamp(const time_t& t)
{
	return time_tToTimestamp(static_cast<double>(t));
}

double mrpt::system::timestampTotime_t(const mrpt::system::TTimeStamp t)
{
	return double(
			   t.time_since_epoch().count() -
			   UINT64_C(116444736) * UINT64_C(1000000000)) /
		   10000000.0;
}

/*---------------------------------------------------------------
					timestampToParts
  ---------------------------------------------------------------*/
void mrpt::system::timestampToParts(TTimeStamp t, TTimeParts& p, bool localTime)
{
	const double T = mrpt::system::timestampTotime_t(t);
	double sec_frac = T - floor(T);
	ASSERT_(sec_frac < 1.0);

	const time_t tt = time_t(T);

	struct tm* parts = localTime ? localtime(&tt) : gmtime(&tt);
	ASSERTMSG_(parts, "Malformed timestamp");

	p.year = parts->tm_year + 1900;
	p.month = parts->tm_mon + 1;
	p.day = parts->tm_mday;
	p.day_of_week = parts->tm_wday + 1;
	p.daylight_saving = parts->tm_isdst;
	p.hour = parts->tm_hour;
	p.minute = parts->tm_min;
	p.second = parts->tm_sec + sec_frac;
}

/*---------------------------------------------------------------
					buildTimestampFromParts
  ---------------------------------------------------------------*/
TTimeStamp mrpt::system::buildTimestampFromParts(const TTimeParts& p)
{
	struct tm parts;

	parts.tm_year = p.year - 1900;
	parts.tm_mon = p.month - 1;
	parts.tm_mday = p.day;
	parts.tm_wday = p.day_of_week - 1;
	parts.tm_isdst = p.daylight_saving;
	parts.tm_hour = p.hour;
	parts.tm_min = p.minute;
	parts.tm_sec = int(p.second);

	double sec_frac = p.second - parts.tm_sec;

	time_t tt = mrpt::system::os::timegm(&parts);  // Local time: mktime

	return mrpt::system::time_tToTimestamp(double(tt) + sec_frac);
}

/*---------------------------------------------------------------
					buildTimestampFromPartsLocalTime
  ---------------------------------------------------------------*/
TTimeStamp mrpt::system::buildTimestampFromPartsLocalTime(const TTimeParts& p)
{
	struct tm parts;

	parts.tm_year = p.year - 1900;
	parts.tm_mon = p.month - 1;
	parts.tm_mday = p.day;
	parts.tm_wday = p.day_of_week - 1;
	parts.tm_isdst = p.daylight_saving;
	parts.tm_hour = p.hour;
	parts.tm_min = p.minute;
	parts.tm_sec = int(p.second);

	double sec_frac = p.second - parts.tm_sec;

	time_t tt = mktime(&parts);

	return mrpt::system::time_tToTimestamp(double(tt) + sec_frac);
}

/*---------------------------------------------------------------
					formatTimeInterval
  ---------------------------------------------------------------*/
string mrpt::system::formatTimeInterval(const double t)
{
	double timeSeconds = (t < 0) ? (-t) : t;
	std::string s;

	const auto nDays = static_cast<unsigned int>(timeSeconds / (3600 * 24));
	timeSeconds -= nDays * 3600 * 24;
	const auto nHours = static_cast<unsigned int>(timeSeconds / 3600);
	timeSeconds -= nHours * 3600;
	const auto nMins = static_cast<unsigned int>(timeSeconds / 60);
	const auto nSecs = static_cast<unsigned int>(timeSeconds) % 60;
	const auto milSecs =
		static_cast<unsigned int>(1000 * timeSeconds - floor(timeSeconds));

	if (nDays > 0) s += mrpt::format("%udays ", nDays);
	if (nHours > 0) s += mrpt::format("%uh ", nHours);
	if (nMins > 0) s += mrpt::format("%02umin ", nMins);
	s += mrpt::format("%02u.%03us", nSecs, milSecs);
	return s;
}

/*---------------------------------------------------------------
  Convert a timestamp into this textual form: YEAR/MONTH/DAY,HH:MM:SS.MMM
  ---------------------------------------------------------------*/
string mrpt::system::dateTimeToString(const mrpt::system::TTimeStamp t)
{
	if (t == INVALID_TIMESTAMP) return string("INVALID_TIMESTAMP");

	uint64_t tmp =
		(t.time_since_epoch().count() - ((uint64_t)116444736 * 1000000000));
	time_t auxTime = tmp / (uint64_t)10000000;
	unsigned int secFractions =
		(unsigned int)(1000000 * (tmp % 10000000) / 10000000.0);
	tm* ptm = gmtime(&auxTime);

	if (!ptm) return std::string("(Malformed timestamp)");

	return format(
		"%u/%02u/%02u,%02u:%02u:%02u.%06u", 1900 + ptm->tm_year,
		ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min,
		(unsigned int)ptm->tm_sec, secFractions);
}

/*---------------------------------------------------------------
  Convert a timestamp into this textual form (in local time):
	  YEAR/MONTH/DAY,HH:MM:SS.MMM
  ---------------------------------------------------------------*/
string mrpt::system::dateTimeLocalToString(const mrpt::system::TTimeStamp t)
{
	if (t == INVALID_TIMESTAMP) return string("INVALID_TIMESTAMP");

	uint64_t tmp =
		(t.time_since_epoch().count() - ((uint64_t)116444736 * 1000000000));
	time_t auxTime = tmp / (uint64_t)10000000;
	unsigned int secFractions =
		(unsigned int)(1000000 * (tmp % 10000000) / 10000000.0);
	tm* ptm = localtime(&auxTime);

	if (!ptm) return "(Malformed timestamp)";

	return format(
		"%u/%02u/%02u,%02u:%02u:%02u.%06u", 1900 + ptm->tm_year,
		ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min,
		(unsigned int)ptm->tm_sec, secFractions);
}

/*---------------------------------------------------------------
						extractDayTimeFromTimestamp
  ---------------------------------------------------------------*/
double mrpt::system::extractDayTimeFromTimestamp(
	const mrpt::system::TTimeStamp tt)
{
	MRPT_START
	ASSERT_(tt != INVALID_TIMESTAMP);

	auto t = tt.time_since_epoch().count();
#ifdef _WIN32
	SYSTEMTIME sysT;
	FileTimeToSystemTime((FILETIME*)&t, &sysT);
	return sysT.wHour * 3600.0 + sysT.wMinute * 60.0 + sysT.wSecond +
		   sysT.wMilliseconds * 0.001;
#else
	time_t auxTime =
		(t - ((uint64_t)116444736 * 1000000000)) / (uint64_t)10000000;
	tm* ptm = gmtime(&auxTime);
	ASSERTMSG_(ptm, "Malformed timestamp");
	return ptm->tm_hour * 3600.0 + ptm->tm_min * 60.0 + ptm->tm_sec;
#endif
	MRPT_END
}

/*---------------------------------------------------------------
  Convert a timestamp into this textual form: HH:MM:SS.MMM
  ---------------------------------------------------------------*/
string mrpt::system::timeLocalToString(
	const mrpt::system::TTimeStamp tt, unsigned int secondFractionDigits)
{
	if (tt == INVALID_TIMESTAMP) return string("INVALID_TIMESTAMP");
	auto t = tt.time_since_epoch().count();

	uint64_t tmp = (t - ((uint64_t)116444736 * 1000000000));
	const time_t auxTime = tmp / (uint64_t)10000000;
	const tm* ptm = localtime(&auxTime);

	unsigned int secFractions =
		(unsigned int)(1000000 * (tmp % 10000000) / 10000000.0);
	// We start with 10^{-6} second units: reduce if requested by user:
	const unsigned int user_secondFractionDigits = secondFractionDigits;
	while (secondFractionDigits++ < 6) secFractions = secFractions / 10;

	return format(
		"%02u:%02u:%02u.%0*u", ptm->tm_hour, ptm->tm_min,
		(unsigned int)ptm->tm_sec, user_secondFractionDigits, secFractions);
}

/*---------------------------------------------------------------
  Convert a timestamp into this textual form: HH:MM:SS.MMM
  ---------------------------------------------------------------*/
string mrpt::system::timeToString(const mrpt::system::TTimeStamp tt)
{
	if (tt == INVALID_TIMESTAMP) return string("INVALID_TIMESTAMP");
	auto t = tt.time_since_epoch().count();

	uint64_t tmp = (t - ((uint64_t)116444736 * 1000000000));
	time_t auxTime = tmp / (uint64_t)10000000;
	unsigned int secFractions =
		(unsigned int)(1000000 * (tmp % 10000000) / 10000000.0);
	tm* ptm = gmtime(&auxTime);
	if (!ptm) return string("(Malformed timestamp)");

	return format(
		"%02u:%02u:%02u.%06u", ptm->tm_hour, ptm->tm_min,
		(unsigned int)ptm->tm_sec, secFractions);
}

/*---------------------------------------------------------------
  Convert a timestamp into this textual form: YEAR/MONTH/DAY
  ---------------------------------------------------------------*/
string mrpt::system::dateToString(const mrpt::system::TTimeStamp tt)
{
	if (tt == INVALID_TIMESTAMP) return string("INVALID_TIMESTAMP");
	auto t = tt.time_since_epoch().count();

	uint64_t tmp = (t - ((uint64_t)116444736 * 1000000000));
	time_t auxTime = tmp / (uint64_t)10000000;
	tm* ptm = gmtime(&auxTime);
	if (!ptm) return string("(Malformed timestamp)");

	return format(
		"%u/%02u/%02u", 1900 + ptm->tm_year, ptm->tm_mon + 1, ptm->tm_mday);
}

/** This function implements time interval formatting: Given a time in seconds,
 * it will return a string describing the interval with the most appropriate
 * unit.
 * E.g.: 1.23 year, 3.50 days, 9.3 hours, 5.3 minutes, 3.34 sec, 178.1 ms,  87.1
 * us.
 */
std::string mrpt::system::intervalFormat(const double seconds)
{
	if (seconds >= 365 * 24 * 3600)
		return format("%.2f years", seconds / (365 * 24 * 3600));
	else if (seconds >= 24 * 3600)
		return format("%.2f days", seconds / (24 * 3600));
	else if (seconds >= 3600)
		return format("%.2f hours", seconds / 3600);
	else if (seconds >= 60)
		return format("%.2f minutes", seconds / 60);
	else if (seconds >= 1)
		return format("%.2f sec", seconds);
	else if (seconds >= 1e-3)
		return format("%.2f ms", seconds * 1e3);
	else if (seconds >= 1e-6)
		return format("%.2f us", seconds * 1e6);
	else
		return format("%.2f ns", seconds * 1e9);
}

std::ostream& mrpt::system::operator<<(std::ostream& o, const TTimeStamp& t)
{
	const uint64_t v = t.time_since_epoch().count();
	o << v;
	return o;
}
<|endoftext|>


<commit_before>/*
PlainFFT Library
No warranty, no claims, just fun
Didier Longueville invenit et fecit October 2010
Modified by Ted Hayes 2011 to use only Hamming windowing to optimize compiled object size.
*/

#include "PlainFFT.h"

#define twoPi 6.28318531
#define fourPi 12.56637061

PlainFFT::PlainFFT(void) {
// Constructor
}

PlainFFT::~PlainFFT(void){
// Destructor
}

uint8_t PlainFFT::revision(void){
	return(FFT_LIB_REV);
}

void PlainFFT::compute(double *vReal, double *vImag, uint16_t samples, uint8_t dir) {
// Computes in-place complex-to-complex FFT
	// Reverse bits
	uint16_t j = 0;
	for (uint16_t i = 0; i < (samples - 1); i++) {
		if (i < j) {
			 swap(&vReal[i], &vReal[j]);
			 swap(&vImag[i], &vImag[j]);
		}
		uint16_t k = (samples >> 1);
		while (k <= j) {
			 j -= k;
			 k >>= 1;
		}
		j += k;
	}
	// Compute the FFT
	double c1 = -1.0;
	double c2 = 0.0;
	uint8_t l2 = 1;
	for (uint8_t l = 0; l < exponent(samples); l++) {
		uint8_t l1 = l2;
		l2 <<= 1;
		double u1 = 1.0;
		double u2 = 0.0;
		for (j = 0; j < l1; j++) {
			 for (uint16_t i = j; i < samples; i += l2) {
					uint16_t i1 = i + l1;
					double t1 = u1 * vReal[i1] - u2 * vImag[i1];
					double t2 = u1 * vImag[i1] + u2 * vReal[i1];
					vReal[i1] = vReal[i] - t1;
					vImag[i1] = vImag[i] - t2;
					vReal[i] += t1;
					vImag[i] += t2;
			 }
			 double z = (u1 * c1) - (u2 * c2);
			 u2 = (u1 * c2) + (u2 * c1);
			 u1 = z;
		}
		c2 = sqrt((1.0 - c1) / 2.0);
		if (dir == FFT_FORWARD) c2 = -c2;
		c1 = sqrt((1.0 + c1) / 2.0);
	}
	// Scaling for forward transform
	if (dir == FFT_FORWARD) {
		for (uint16_t i = 0; i < samples; i++) {
			 vReal[i] /= samples;
			 vImag[i] /= samples;
		}
	}
}

void PlainFFT::complexToMagnitude(double *vReal, double *vImag, uint16_t samples) {
// vM is half the size of vReal and vImag
	for (uint8_t i = 0; i < samples; i++) vReal[i] = sqrt((vReal[i]*vReal[i]) + (vImag[i]*vImag[i]));
}

void PlainFFT::windowing(double *vData, uint16_t samples) {
// Weighing factors are computed once before multiple use of FFT
// The weighing function is symetric; half the weighs are recorded
	double samplesMinusOne = (double(samples) - 1.0);
	for (uint16_t i = 0; i < (samples >> 1); i++) {
		double indexMinusOne = double(i);
		double ratio = (indexMinusOne / samplesMinusOne);
		double weighingFactor = 1.0;
		// compute and record weighting factor
		weighingFactor = 0.54 - (0.46 * cos(twoPi * ratio));
		vData[i] *= weighingFactor;
		vData[samples - (i + 1)] *= weighingFactor;
	}
}

String PlainFFT::majorPeakFrequency(double *vD, uint16_t samples, double samplingFrequency) {
	double amp;
	int ind;
	String result = "";
	double maxY = 2;
	double maxY2 = 1;//dikom
	double maxY3 = 0;//dik
	int IndexOfMaxY = 0;
	int IndexOfMaxY2 = 0;//dikom
	int IndexOfMaxY3 = 0;//dikom
	for (uint16_t i = 1; i < ((samples >> 1) - 1); i++) {
		if ((vD[i-1] < vD[i]) && (vD[i] > vD[i+1])) {
			if(vD[i] >= maxY3){
			        maxY3 = vD[i];
				IndexOfMaxY3 = i;
			}
			if(vD[i] >= maxY2){
				amp = maxY3;
				ind = IndexOfMaxY3;
				maxY3 = maxY2;
			        IndexOfMaxY3 = IndexOfMaxY2;
				maxY2 = vD[i];
				IndexOfMaxY2 = i;

				if (vD[i] >= maxY) {
					maxY3 = amp;
					IndexOfMaxY3 = ind;
					maxY2 = maxY;
				        IndexOfMaxY2 = IndexOfMaxY;
					maxY = vD[i];
					IndexOfMaxY = i;
				}
			}
		}
	}
	double delta1 = 0.5 * ((vD[IndexOfMaxY-1] - vD[IndexOfMaxY+1]) / (vD[IndexOfMaxY-1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY+1]));
	double interpolatedX = ((IndexOfMaxY + delta1)  * samplingFrequency) / (samples-1);
	// retuned value: interpolated frequency peak apex
	double delta2 = 0.5 * ((vD[IndexOfMaxY2-1] - vD[IndexOfMaxY2+1]) / (vD[IndexOfMaxY2-1] - (2.0 * vD[IndexOfMaxY2]) + vD[IndexOfMaxY2+1]));
	double interpolatedX2 = ((IndexOfMaxY2 + delta2)  * samplingFrequency) / (samples-1);
	////////////////////////////////////////
	double delta3 = 0.5 * ((vD[IndexOfMaxY3-1] - vD[IndexOfMaxY3+1]) / (vD[IndexOfMaxY3-1] - (2.0 * vD[IndexOfMaxY3]) + vD[IndexOfMaxY3+1]));
	double interpolatedX3 = ((IndexOfMaxY3 + delta3)  * samplingFrequency) / (samples-1);
	result = String(int(interpolatedX)) + "," + String(int((10*log(maxY)))) + "," + String(int(interpolatedX2)) + "," + String(int((10*log(maxY2)))) + "," + String(int(interpolatedX3)) + "," + String(int((10*log(maxY3))));
	return(result);  //to allaksa  ki evala allo return

}

double PlainFFT::majorPeakIndex(double *vD, uint16_t samples, double samplingFrequency) {
	double maxY = 0;
	int IndexOfMaxY = 0;
	for (uint16_t i = 1; i < ((samples >> 1) - 1); i++) {
		if ((vD[i-1] < vD[i]) && (vD[i] > vD[i+1])) {
			if (vD[i] > maxY) {
				maxY = vD[i];
				IndexOfMaxY = i;
			}
		}
	}
	double delta = 0.5 * ((vD[IndexOfMaxY-1] - vD[IndexOfMaxY+1]) / (vD[IndexOfMaxY-1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY+1]));
	double interpolatedX = ((IndexOfMaxY + delta)  * samplingFrequency) / (samples-1);
	// retuned value: interpolated frequency peak apex
	//return(interpolatedX);  //to allaksa  ki evala allo return
	return (IndexOfMaxY);
}

void PlainFFT::printMagnitudes(double *vM, uint16_t samples){
	for (uint16_t i = 1; i < ((samples >> 1) - 1); i++) {
		Serial.print(vM[i]);
		Serial.print("\t");
	}
}

/* Private */

void PlainFFT::swap(double *x, double *y) {
	double temp = *x;
	*x = *y;
	*y = temp;
}

uint8_t PlainFFT::exponent(uint16_t value) {
	// computes the exponent of a powered 2 value
	uint8_t result = 0;
	while (((value >> result) & 1) != 1) result++;
	return(result);
}
<commit_msg>saasas<commit_after>/*
PlainFFT Library
No warranty, no claims, just fun
Didier Longueville invenit et fecit October 2010
Modified by Ted Hayes 2011 to use only Hamming windowing to optimize compiled object size.
*/

#include "PlainFFT.h"

#define twoPi 6.28318531
#define fourPi 12.56637061

PlainFFT::PlainFFT(void) {
// Constructor
}

PlainFFT::~PlainFFT(void){
// Destructor
}

uint8_t PlainFFT::revision(void){
	return(FFT_LIB_REV);
}

void PlainFFT::compute(double *vReal, double *vImag, uint16_t samples, uint8_t dir) {
// Computes in-place complex-to-complex FFT
	// Reverse bits
	uint16_t j = 0;
	for (uint16_t i = 0; i < (samples - 1); i++) {
		if (i < j) {
			 swap(&vReal[i], &vReal[j]);
			 swap(&vImag[i], &vImag[j]);
		}
		uint16_t k = (samples >> 1);
		while (k <= j) {
			 j -= k;
			 k >>= 1;
		}
		j += k;
	}
	// Compute the FFT
	double c1 = -1.0;
	double c2 = 0.0;
	uint8_t l2 = 1;
	for (uint8_t l = 0; l < exponent(samples); l++) {
		uint8_t l1 = l2;
		l2 <<= 1;
		double u1 = 1.0;
		double u2 = 0.0;
		for (j = 0; j < l1; j++) {
			 for (uint16_t i = j; i < samples; i += l2) {
					uint16_t i1 = i + l1;
					double t1 = u1 * vReal[i1] - u2 * vImag[i1];
					double t2 = u1 * vImag[i1] + u2 * vReal[i1];
					vReal[i1] = vReal[i] - t1;
					vImag[i1] = vImag[i] - t2;
					vReal[i] += t1;
					vImag[i] += t2;
			 }
			 double z = (u1 * c1) - (u2 * c2);
			 u2 = (u1 * c2) + (u2 * c1);
			 u1 = z;
		}
		c2 = sqrt((1.0 - c1) / 2.0);
		if (dir == FFT_FORWARD) c2 = -c2;
		c1 = sqrt((1.0 + c1) / 2.0);
	}
	// Scaling for forward transform
	if (dir == FFT_FORWARD) {
		for (uint16_t i = 0; i < samples; i++) {
			 vReal[i] /= samples;
			 vImag[i] /= samples;
		}
	}
}

void PlainFFT::complexToMagnitude(double *vReal, double *vImag, uint16_t samples) {
// vM is half the size of vReal and vImag
	for (uint8_t i = 0; i < samples; i++) vReal[i] = sqrt((vReal[i]*vReal[i]) + (vImag[i]*vImag[i]));
}

void PlainFFT::windowing(double *vData, uint16_t samples) {
// Weighing factors are computed once before multiple use of FFT
// The weighing function is symetric; half the weighs are recorded
	double samplesMinusOne = (double(samples) - 1.0);
	for (uint16_t i = 0; i < (samples >> 1); i++) {
		double indexMinusOne = double(i);
		double ratio = (indexMinusOne / samplesMinusOne);
		double weighingFactor = 1.0;
		// compute and record weighting factor
		weighingFactor = 0.54 - (0.46 * cos(twoPi * ratio));
		vData[i] *= weighingFactor;
		vData[samples - (i + 1)] *= weighingFactor;
	}
}

String PlainFFT::majorPeakFrequency(double *vD, uint16_t samples, double samplingFrequency) {
	double amp;
	int ind;
	String result = "";
	double maxY = 2;
	double maxY2 = 1;//dikom
	double maxY3 = 0;//dik
	int IndexOfMaxY = 0;
	int IndexOfMaxY2 = 0;//dikom
	int IndexOfMaxY3 = 0;//dikom
	for (uint16_t i = 1; i < ((samples >> 1) - 1); i++) {
		if ((vD[i-1] < vD[i]) && (vD[i] > vD[i+1])) {
			if(vD[i] >= maxY3){
			        maxY3 = vD[i];
				IndexOfMaxY3 = i;
			}
			if(vD[i] >= maxY2){
				amp = maxY3;
				ind = IndexOfMaxY3;
				maxY3 = maxY2;
			        IndexOfMaxY3 = IndexOfMaxY2;
				maxY2 = vD[i];
				IndexOfMaxY2 = i;

				if (vD[i] >= maxY) {
					maxY3 = amp;
					IndexOfMaxY3 = ind;
					maxY2 = maxY;
				        IndexOfMaxY2 = IndexOfMaxY;
					maxY = vD[i];
					IndexOfMaxY = i;
				}
			}
		}
	}
	double delta1 = 0.5 * ((vD[IndexOfMaxY-1] - vD[IndexOfMaxY+1]) / (vD[IndexOfMaxY-1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY+1]));
	double interpolatedX = ((IndexOfMaxY + delta1)  * samplingFrequency) / (samples-1);
	// retuned value: interpolated frequency peak apex
	double delta2 = 0.5 * ((vD[IndexOfMaxY2-1] - vD[IndexOfMaxY2+1]) / (vD[IndexOfMaxY2-1] - (2.0 * vD[IndexOfMaxY2]) + vD[IndexOfMaxY2+1]));
	double interpolatedX2 = ((IndexOfMaxY2 + delta2)  * samplingFrequency) / (samples-1);
	////////////////////////////////////////
	double delta3 = 0.5 * ((vD[IndexOfMaxY3-1] - vD[IndexOfMaxY3+1]) / (vD[IndexOfMaxY3-1] - (2.0 * vD[IndexOfMaxY3]) + vD[IndexOfMaxY3+1]));
	double interpolatedX3 = ((IndexOfMaxY3 + delta3)  * samplingFrequency) / (samples-1);
	result = String(int(interpolatedX)) + "," + String(int((log(maxY)))) + "," + String(int(interpolatedX2)) + "," + String(int((log(maxY2)))) + "," + String(int(interpolatedX3)) + "," + String(int((log(maxY3))));
	return(result);  //to allaksa  ki evala allo return

}

double PlainFFT::majorPeakIndex(double *vD, uint16_t samples, double samplingFrequency) {
	double maxY = 0;
	int IndexOfMaxY = 0;
	for (uint16_t i = 1; i < ((samples >> 1) - 1); i++) {
		if ((vD[i-1] < vD[i]) && (vD[i] > vD[i+1])) {
			if (vD[i] > maxY) {
				maxY = vD[i];
				IndexOfMaxY = i;
			}
		}
	}
	double delta = 0.5 * ((vD[IndexOfMaxY-1] - vD[IndexOfMaxY+1]) / (vD[IndexOfMaxY-1] - (2.0 * vD[IndexOfMaxY]) + vD[IndexOfMaxY+1]));
	double interpolatedX = ((IndexOfMaxY + delta)  * samplingFrequency) / (samples-1);
	// retuned value: interpolated frequency peak apex
	//return(interpolatedX);  //to allaksa  ki evala allo return
	return (IndexOfMaxY);
}

void PlainFFT::printMagnitudes(double *vM, uint16_t samples){
	for (uint16_t i = 1; i < ((samples >> 1) - 1); i++) {
		Serial.print(vM[i]);
		Serial.print("\t");
	}
}

/* Private */

void PlainFFT::swap(double *x, double *y) {
	double temp = *x;
	*x = *y;
	*y = temp;
}

uint8_t PlainFFT::exponent(uint16_t value) {
	// computes the exponent of a powered 2 value
	uint8_t result = 0;
	while (((value >> result) & 1) != 1) result++;
	return(result);
}
<|endoftext|>


<commit_before>// $Id$

// Author: Constantin Loizides <mailto:loizides@ikf.physik.uni-frankfurt.de>
//*-- Copyright & copy CL

#include "AliL3StandardIncludes.h"

#include "AliL3VHDLClusterFinder.h"

#if GCCVERSION == 3
using namespace std;
#endif

/** \class AliL3VHDLClusterFinder
//

//____________________________________________________
// AliL3VHDLClusterFinder
//
// The current VHDL cluster finder for HLT
// Based on STAR L3
//
// Most important parameters:
// fThreshold - threshold for noise clusters
// fMatch - length in time for overlapping sequences
//

*/

ClassImp(AliL3VHDLClusterFinder)

AliL3VHDLClusterFinder::AliL3VHDLClusterFinder()
{
  fMatch = 4;
  fThreshold = 10;
  fMinMerge = 1;
  fNClusters=0;

  fXYErr = 0.2;
  fZErr = 0.3;
  fDeconvPad = kTRUE;
  fDeconvTime = kTRUE;
  fstdout = kFALSE;
  fcalcerr = kTRUE;

  Clear();
#ifdef DEBUG
  fdeb=fopen("vhdlclusterfinder.debug","w");
  //fdeb=stderr;
#endif
}

AliL3VHDLClusterFinder::~AliL3VHDLClusterFinder()
{
#ifdef DEBUG
  fclose(fdeb);
#endif
}

void AliL3VHDLClusterFinder::ProcessDigits()
{
  //Loop over data like the analyzer of the VHDL code
  const UChar_t n=255;
  UShort_t rrow=0,rtime=0;
  UChar_t rpad=0,i=n;
  UShort_t *charges=new UShort_t[n];
  Int_t tc=0,mp=0,mt=0,sp=0,st=0;

  fNClusters=0;
  fRow=0;
  fPad=0;
  Clear();

  //loop over input data
  while(fAltromem.ReadSequence(rrow,rpad,rtime,i,&charges)){
    tc=0;mp=0;mt=0;sp=0;st=0;
#if 0
    cout << "Padrow " << (int)rrow << " pad " << (int)rpad << " time " <<(int)rtime << " charges ";
    for(UChar_t ii=0;ii<i;ii++) cout << (int)charges[ii] << " ";
    cout << endl;
#endif
#ifdef DEBUG
    fprintf(fdeb,"ProcessDigits: Input Data: %d %d %d charges:",(int)rrow,(int)rpad,(int)rtime);
    for(UChar_t ii=0;ii<i;ii++) fprintf(fdeb," %d",(int)charges[ii]);
    fprintf(fdeb,"\n");
#endif

    fNRow=rrow;
    fNPad=rpad;

    //calculate sequence values
    //no deconvulution so far
    for(UChar_t ii=0;ii<i;ii++){
      tc+=charges[ii];
      mt+=(rtime-ii)*charges[ii];
      st+=(rtime-ii)*(rtime-ii)*charges[ii];
    }
    mp=rpad*tc;
    sp=rpad*rpad*tc;

    fSeq.fTotalCharge=tc;
    fSeq.fPad=mp;
    fSeq.fTime=mt;
    fSeq.fPad2=sp;
    fSeq.fTime2=st;
    fSeq.fMean=0;
    //if(tc!=0) fSeq.fMean=mt/tc;
    if(tc!=0) fSeq.fMean=rtime-i/2;
    fSeq.fMerge=0;
    fSeq.fRow=rrow;
    fSeq.fLastPad=rpad;

    //work on this sequence
    ProcessSequence();
    //output one cluster
    OutputMemory();

#ifdef DEBUG
    fflush(fdeb);
#endif
    i=n; //store size of charges array
  } //loop over data

  //flush everything left
  FlushMemory();
  while(fOP!=fFP) OutputMemory();
}

void AliL3VHDLClusterFinder::ProcessSequence()
{
  if(fNRow!=fRow) FlushMemory();
  else if(fNPad==fPad+1) PrepareMemory();
  else if(fNPad!=fPad) FlushMemory();

  //store new row and pad values
  fRow=fNRow;
  fPad=fNPad;

#ifdef DEBUG
  fprintf(fdeb,"ProcessSequence: Mean=%d TC=%d ",fSeq.fMean,fSeq.fTotalCharge);
#endif

  CompareSeq(); //merge or insert
}

void AliL3VHDLClusterFinder::PrepareMemory()
{
#ifdef DEBUG
  fprintf(fdeb,"PrepareMemory %d %d %d\n",fRP,fEP,fWP);
#endif
  fRP=fEP;
  fEP=fWP;
}

void AliL3VHDLClusterFinder::FlushMemory()
{
#ifdef DEBUG
  fprintf(fdeb,"FlushMemory %d %d %d %d\n",fFP,fRP,fEP,fWP);
#endif
  fFP=fWP;
  fRP=fWP;
  fEP=fWP;
}

void AliL3VHDLClusterFinder::CompareSeq()
{

  while(fRP!=fEP){
    Int_t diff=fSeqs[fPList[fRP]].fMean-fSeq.fMean;

    if(diff>fMatch){ //no match
      IncRPointer(); //cluster finished
      continue;
    } else if(diff<-fMatch){ //no match
      break;                 //insert new cluster
    }
    else { //match found, merge it
      MergeSeq();
      return;
    }
  }

  InsertSeq(); //start new cluster
}

void AliL3VHDLClusterFinder::MergeSeq()
{
#ifdef DEBUG
  fprintf(fdeb,"merged with Mean=%d TC=%d (new Merge=%d) %d %d\n",fSeqs[fPList[fRP]].fMean,fSeqs[fPList[fRP]].fTotalCharge,fSeqs[fPList[fRP]].fMerge+1,fRow,fPad);
#endif
  if(fSeqs[fPList[fRP]].fRow==fSeq.fRow){
    LOG(AliL3Log::kWarning,"AliL3VHDLClusterFinder::","Memory Check")
      <<"Sequences can be merged on the same rows only."<<ENDLOG;
  }
  if(fSeqs[fPList[fRP]].fLastPad+1!=fSeq.fLastPad){
    LOG(AliL3Log::kWarning,"AliL3VHDLClusterFinder::","Memory Check")
      <<"Sequences can be merged on consecutive pads only."<<ENDLOG;
  }

  fSeqs[fPList[fRP]].fMean=fSeq.fMean; //take the new mean
  fSeqs[fPList[fRP]].fLastPad=fSeq.fLastPad;
  fSeqs[fPList[fRP]].fTotalCharge+=fSeq.fTotalCharge;
  fSeqs[fPList[fRP]].fPad+=fSeq.fPad;
  fSeqs[fPList[fRP]].fTime+=fSeq.fTime;
  fSeqs[fPList[fRP]].fPad2+=fSeq.fPad2;
  fSeqs[fPList[fRP]].fTime2+=fSeq.fTime2;
  fSeqs[fPList[fRP]].fMerge+=1;

  fPList[fWP]=fPList[fRP];
  fPList[fRP]=N_clmem; //mark it to be free

  IncRPointer();
  IncWPointer();
}

void AliL3VHDLClusterFinder::InsertSeq()
{
#ifdef DEBUG
  fprintf(fdeb,"inserted %d %d\n",fRow,fPad);
#endif
  NextFreeIndex();    //get next index
  fSeqs[fFirst]=fSeq; //store data
  fPList[fWP]=fFirst; //store index
  IncWPointer();
}

void AliL3VHDLClusterFinder::OutputMemory()
{
  Float_t mtime=0,mpad=0;
  Float_t mtime2=0,mpad2=0;
  UInt_t tc,row,mno;

  if(fOP!=fFP){
  //while(fOP!=fFP){

    UInt_t index=fPList[fOP];
    fPList[fOP]=N_clmem;
    //cout << fOP << " - " << fFP << " - " << index << endl;
    IncPointer(fOP);
    if(index>=N_clmem) return; //nothing to do
    //if(index>=N_clmem) continue; //nothing to do

    tc=fSeqs[index].fTotalCharge;
    mno=fSeqs[index].fMerge;
    row=fSeqs[index].fRow;
    if(tc!=0){
      mtime=(Float_t)(fSeqs[index].fTime)/tc;
      mtime2=sqrt((Float_t)(fSeqs[index].fTime2)/tc-mtime*mtime);
    }
    if(tc!=0){
      mpad=(Float_t)(fSeqs[index].fPad)/tc;
      mpad2=sqrt((Float_t)(fSeqs[index].fPad2)/tc-mpad*mpad);
    }

    if(mno<fMinMerge){ //noise cluster
#ifdef DEBUG
    fprintf(fdeb,"OutputMemory %d %d: noise cluster (merge): Row %d Pad %.3f Time %.3f TC %d Merge %d\n",fOP,fFP,row,mpad,mtime,tc,mno);
#endif
      FreeSeq(index);
      return;
      //continue;
    }

    if(tc<fThreshold){ //total charge below threshold
#ifdef DEBUG
    fprintf(fdeb,"OutputMemory %d %d: noise cluster (threshold): Row %d Pad %.3f Time %.3f TC %d Merge %d\n",fOP,fFP,row,mpad,mtime,tc,mno);
#endif
      FreeSeq(index);
      return;
      //continue;
    }

#ifdef DEBUG
    fprintf(fdeb,"OutputMemory %d: Row %d Pad %.3f Time %.3f TC %d Merge %d\n",fNClusters,row,mpad,mtime,tc,mno);
#endif

    if(stdout)
      cout<<"WriteCluster: padrow "<<row<<" pad "<<mpad<< " +- "<<mpad2<<" time "<<mtime<<" +- "<<mtime2<<" charge "<<tc<<endl;

    fNClusters++;
    FreeSeq(index);
  }
}

inline void AliL3VHDLClusterFinder::FreeSeq(UShort_t i)
{
  ClearSeq(i);
  IncPointer(fLast,1,N_clmem);
}

void AliL3VHDLClusterFinder::Clear()
{
  fFirst=0; //first list pointer
  fLast=0;  //last  list pointer

  fWP=0; //write pointer
  fRP=0; //read pointer
  fEP=0; //end read pointer
  fFP=0; //end flush pointer
  fOP=0; //output pointer

  fSeq.fRow=0;
  fSeq.fLastPad=0;
  fSeq.fTotalCharge=0;
  fSeq.fPad=0;
  fSeq.fTime=0;
  fSeq.fPad2=0;
  fSeq.fTime2=0;
  fSeq.fMean=0;
  fSeq.fMerge=0;

  for(UInt_t i=0;i<N_mem;i++) fPList[i]=N_clmem;
  for(UInt_t i=0;i<N_clmem;i++) ClearSeq(i);
}

void AliL3VHDLClusterFinder::ClearSeq(UShort_t i){
  fSeqs[i].fRow=0;
  fSeqs[i].fLastPad=0;
  fSeqs[i].fTotalCharge=0;
  fSeqs[i].fPad=0;
  fSeqs[i].fTime=0;
  fSeqs[i].fPad2=0;
  fSeqs[i].fTime2=0;
  fSeqs[i].fMean=0;
  fSeqs[i].fMerge=0;
}

void AliL3VHDLClusterFinder::IncPointer(UShort_t &p, Short_t add, UShort_t N){
  Short_t pp=p;
  pp+=add;
  if(pp>=N) p=UShort_t(pp-N);
  else if(pp<0) p=UShort_t(pp+N);
  else p=UShort_t(pp);
}

inline void AliL3VHDLClusterFinder::IncRPointer(){
  IncPointer(fRP);
}

inline void AliL3VHDLClusterFinder::IncWPointer(){
  IncPointer(fWP);

  if(fWP==fOP){
    LOG(AliL3Log::kWarning,"AliL3VHDLClusterFinder::IncWPointer","Memory Check")
      <<"Write pointer overwrites output pointer."<<ENDLOG;
  }
}

inline void AliL3VHDLClusterFinder::NextFreeIndex(){
  IncPointer(fFirst,1,N_clmem);
  if(fFirst==fLast) {
    LOG(AliL3Log::kFatal,"AliL3VHDLClusterFinder::GetFreeIndex","Memory Check")
      <<"No space left in sequence list: "<<fFirst<<"=="<<fLast<<ENDLOG;
  }
}

#if 0
void AliL3ClustFinderNew::WriteClusters(Int_t n_clusters,ClusterData *list)
{
  Int_t thisrow,thissector;
  UInt_t counter = fNClusters;

  for(int j=0; j<n_clusters; j++)
    {
      if(!list[j].fFlags) continue; //discard 1 pad clusters
      if(list[j].fTotalCharge < fThreshold) continue; //noise cluster

      Float_t xyz[3];
      Float_t fpad =(Float_t)list[j].fPad /(Float_t)list[j].fTotalCharge;
      Float_t fpad2=fXYErr;
      Float_t ftime =(Float_t)list[j].fTime /(Float_t)list[j].fTotalCharge;
      Float_t ftime2=fZErr;

      if(fcalcerr) {
	fpad2=(Float_t)list[j].fPad2/(Float_t)list[j].fTotalCharge - fpad*fpad;
	fpad2 = sqrt(fpad2);
	ftime2=(Float_t)list[j].fTime2/(Float_t)list[j].fTotalCharge - ftime*ftime;
	ftime2 = sqrt(ftime2);
      }

      if(fstdout==kTRUE)
	cout<<"WriteCluster: padrow "<<fCurrentRow<<" pad "<<fpad << "+-"<<fpad2<<" time "<<ftime<<"+-"<<ftime2<<" charge "<<list[j].fTotalCharge<<endl;

      AliL3Transform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
      AliL3Transform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
      if(xyz[0]==0) LOG(AliL3Log::kError,"AliL3ClustFinder","Cluster Finder")
	<<AliL3Log::kDec<<"Zero cluster"<<ENDLOG;
      if(fNClusters >= fMaxNClusters)
	{
	  LOG(AliL3Log::kError,"AliL3ClustFinder::WriteClusters","Cluster Finder")
	    <<AliL3Log::kDec<<"Too many clusters"<<ENDLOG;
	  return;
	}
      fSpacePointData[counter].fCharge = list[j].fTotalCharge;
      fSpacePointData[counter].fX = xyz[0];
      fSpacePointData[counter].fY = xyz[1];
      fSpacePointData[counter].fZ = xyz[2];
      fSpacePointData[counter].fPadRow = fCurrentRow;
      fSpacePointData[counter].fXYErr = fpad2;
      fSpacePointData[counter].fZErr  = ftime2;
      fSpacePointData[counter].fID = counter
	+((fCurrentSlice&0x7f)<<25)+((fCurrentPatch&0x7)<<22);//Uli

      fNClusters++;
      counter++;
    }
}
#endif

<commit_msg>Little bug when reporting row merge error.<commit_after>// $Id$

// Author: Constantin Loizides <mailto:loizides@ikf.physik.uni-frankfurt.de>
//*-- Copyright & copy CL

#include "AliL3StandardIncludes.h"

#include "AliL3VHDLClusterFinder.h"

#if GCCVERSION == 3
using namespace std;
#endif

/** \class AliL3VHDLClusterFinder
//

//____________________________________________________
// AliL3VHDLClusterFinder
//
// The current VHDL cluster finder for HLT
// Based on STAR L3
//
// Most important parameters:
// fThreshold - threshold for noise clusters
// fMatch - length in time for overlapping sequences
//

*/

ClassImp(AliL3VHDLClusterFinder)

AliL3VHDLClusterFinder::AliL3VHDLClusterFinder()
{
  fMatch = 4;
  fThreshold = 10;
  fMinMerge = 1;
  fNClusters=0;

  fXYErr = 0.2;
  fZErr = 0.3;
  fDeconvPad = kTRUE;
  fDeconvTime = kTRUE;
  fstdout = kFALSE;
  fcalcerr = kTRUE;

  Clear();
#ifdef DEBUG
  fdeb=fopen("vhdlclusterfinder.debug","w");
  //fdeb=stderr;
#endif
}

AliL3VHDLClusterFinder::~AliL3VHDLClusterFinder()
{
#ifdef DEBUG
  fclose(fdeb);
#endif
}

void AliL3VHDLClusterFinder::ProcessDigits()
{
  //Loop over data like the analyzer of the VHDL code
  const UChar_t n=255;
  UShort_t rrow=0,rtime=0;
  UChar_t rpad=0,i=n;
  UShort_t *charges=new UShort_t[n];
  Int_t tc=0,mp=0,mt=0,sp=0,st=0;

  fNClusters=0;
  fRow=0;
  fPad=0;
  Clear();

  //loop over input data
  while(fAltromem.ReadSequence(rrow,rpad,rtime,i,&charges)){
    tc=0;mp=0;mt=0;sp=0;st=0;
#if 0
    cout << "Padrow " << (int)rrow << " pad " << (int)rpad << " time " <<(int)rtime << " charges ";
    for(UChar_t ii=0;ii<i;ii++) cout << (int)charges[ii] << " ";
    cout << endl;
#endif
#ifdef DEBUG
    fprintf(fdeb,"ProcessDigits: Input Data: %d %d %d charges:",(int)rrow,(int)rpad,(int)rtime);
    for(UChar_t ii=0;ii<i;ii++) fprintf(fdeb," %d",(int)charges[ii]);
    fprintf(fdeb,"\n");
#endif

    fNRow=rrow;
    fNPad=rpad;

    //calculate sequence values
    //no deconvulution so far
    for(UChar_t ii=0;ii<i;ii++){
      tc+=charges[ii];
      mt+=(rtime-ii)*charges[ii];
      st+=(rtime-ii)*(rtime-ii)*charges[ii];
    }
    mp=rpad*tc;
    sp=rpad*rpad*tc;

    fSeq.fTotalCharge=tc;
    fSeq.fPad=mp;
    fSeq.fTime=mt;
    fSeq.fPad2=sp;
    fSeq.fTime2=st;
    fSeq.fMean=0;
    //if(tc!=0) fSeq.fMean=mt/tc;
    if(tc!=0) fSeq.fMean=rtime-i/2;
    fSeq.fMerge=0;
    fSeq.fRow=rrow;
    fSeq.fLastPad=rpad;

    //work on this sequence
    ProcessSequence();
    //output one cluster
    OutputMemory();

#ifdef DEBUG
    fflush(fdeb);
#endif
    i=n; //store size of charges array
  } //loop over data

  //flush everything left
  FlushMemory();
  while(fOP!=fFP) OutputMemory();
}

void AliL3VHDLClusterFinder::ProcessSequence()
{
  if(fNRow!=fRow) FlushMemory();
  else if(fNPad==fPad+1) PrepareMemory();
  else if(fNPad!=fPad) FlushMemory();

  //store new row and pad values
  fRow=fNRow;
  fPad=fNPad;

#ifdef DEBUG
  fprintf(fdeb,"ProcessSequence: Mean=%d TC=%d ",fSeq.fMean,fSeq.fTotalCharge);
#endif

  CompareSeq(); //merge or insert
}

void AliL3VHDLClusterFinder::PrepareMemory()
{
#ifdef DEBUG
  fprintf(fdeb,"PrepareMemory %d %d %d\n",fRP,fEP,fWP);
#endif
  fRP=fEP;
  fEP=fWP;
}

void AliL3VHDLClusterFinder::FlushMemory()
{
#ifdef DEBUG
  fprintf(fdeb,"FlushMemory %d %d %d %d\n",fFP,fRP,fEP,fWP);
#endif
  fFP=fWP;
  fRP=fWP;
  fEP=fWP;
}

void AliL3VHDLClusterFinder::CompareSeq()
{

  while(fRP!=fEP){
    Int_t diff=fSeqs[fPList[fRP]].fMean-fSeq.fMean;

    if(diff>fMatch){ //no match
      IncRPointer(); //cluster finished
      continue;
    } else if(diff<-fMatch){ //no match
      break;                 //insert new cluster
    }
    else { //match found, merge it
      MergeSeq();
      return;
    }
  }

  InsertSeq(); //start new cluster
}

void AliL3VHDLClusterFinder::MergeSeq()
{
#ifdef DEBUG
  fprintf(fdeb,"merged with Mean=%d TC=%d (new Merge=%d) %d %d\n",fSeqs[fPList[fRP]].fMean,fSeqs[fPList[fRP]].fTotalCharge,fSeqs[fPList[fRP]].fMerge+1,fRow,fPad);
#endif
  if(fSeqs[fPList[fRP]].fRow!=fSeq.fRow){
    LOG(AliL3Log::kWarning,"AliL3VHDLClusterFinder::","Memory Check")
      <<"Sequences can be merged on the same rows only."<<ENDLOG;
  }
  if(fSeqs[fPList[fRP]].fLastPad+1!=fSeq.fLastPad){
    LOG(AliL3Log::kWarning,"AliL3VHDLClusterFinder::","Memory Check")
      <<"Sequences can be merged on consecutive pads only."<<ENDLOG;
  }

  fSeqs[fPList[fRP]].fMean=fSeq.fMean; //take the new mean
  fSeqs[fPList[fRP]].fLastPad=fSeq.fLastPad;
  fSeqs[fPList[fRP]].fTotalCharge+=fSeq.fTotalCharge;
  fSeqs[fPList[fRP]].fPad+=fSeq.fPad;
  fSeqs[fPList[fRP]].fTime+=fSeq.fTime;
  fSeqs[fPList[fRP]].fPad2+=fSeq.fPad2;
  fSeqs[fPList[fRP]].fTime2+=fSeq.fTime2;
  fSeqs[fPList[fRP]].fMerge+=1;

  fPList[fWP]=fPList[fRP];
  fPList[fRP]=N_clmem; //mark it to be free

  IncRPointer();
  IncWPointer();
}

void AliL3VHDLClusterFinder::InsertSeq()
{
#ifdef DEBUG
  fprintf(fdeb,"inserted %d %d\n",fRow,fPad);
#endif
  NextFreeIndex();    //get next index
  fSeqs[fFirst]=fSeq; //store data
  fPList[fWP]=fFirst; //store index
  IncWPointer();
}

void AliL3VHDLClusterFinder::OutputMemory()
{
  Float_t mtime=0,mpad=0;
  Float_t mtime2=0,mpad2=0;
  UInt_t tc,row,mno;

  if(fOP!=fFP){
  //while(fOP!=fFP){

    UInt_t index=fPList[fOP];
    fPList[fOP]=N_clmem;
    //cout << fOP << " - " << fFP << " - " << index << endl;
    IncPointer(fOP);
    if(index>=N_clmem) return; //nothing to do
    //if(index>=N_clmem) continue; //nothing to do

    tc=fSeqs[index].fTotalCharge;
    mno=fSeqs[index].fMerge;
    row=fSeqs[index].fRow;
    if(tc!=0){
      mtime=(Float_t)(fSeqs[index].fTime)/tc;
      mtime2=sqrt((Float_t)(fSeqs[index].fTime2)/tc-mtime*mtime);
    }
    if(tc!=0){
      mpad=(Float_t)(fSeqs[index].fPad)/tc;
      mpad2=sqrt((Float_t)(fSeqs[index].fPad2)/tc-mpad*mpad);
    }

    if(mno<fMinMerge){ //noise cluster
#ifdef DEBUG
    fprintf(fdeb,"OutputMemory %d %d: noise cluster (merge): Row %d Pad %.3f Time %.3f TC %d Merge %d\n",fOP,fFP,row,mpad,mtime,tc,mno);
#endif
      FreeSeq(index);
      return;
      //continue;
    }

    if(tc<fThreshold){ //total charge below threshold
#ifdef DEBUG
    fprintf(fdeb,"OutputMemory %d %d: noise cluster (threshold): Row %d Pad %.3f Time %.3f TC %d Merge %d\n",fOP,fFP,row,mpad,mtime,tc,mno);
#endif
      FreeSeq(index);
      return;
      //continue;
    }

#ifdef DEBUG
    fprintf(fdeb,"OutputMemory %d: Row %d Pad %.3f Time %.3f TC %d Merge %d\n",fNClusters,row,mpad,mtime,tc,mno);
#endif

    if(stdout)
      cout<<"WriteCluster: padrow "<<row<<" pad "<<mpad<< " +- "<<mpad2<<" time "<<mtime<<" +- "<<mtime2<<" charge "<<tc<<endl;

    fNClusters++;
    FreeSeq(index);
  }
}

inline void AliL3VHDLClusterFinder::FreeSeq(UShort_t i)
{
  ClearSeq(i);
  IncPointer(fLast,1,N_clmem);
}

void AliL3VHDLClusterFinder::Clear()
{
  fFirst=0; //first list pointer
  fLast=0;  //last  list pointer

  fWP=0; //write pointer
  fRP=0; //read pointer
  fEP=0; //end read pointer
  fFP=0; //end flush pointer
  fOP=0; //output pointer

  fSeq.fRow=0;
  fSeq.fLastPad=0;
  fSeq.fTotalCharge=0;
  fSeq.fPad=0;
  fSeq.fTime=0;
  fSeq.fPad2=0;
  fSeq.fTime2=0;
  fSeq.fMean=0;
  fSeq.fMerge=0;

  for(UInt_t i=0;i<N_mem;i++) fPList[i]=N_clmem;
  for(UInt_t i=0;i<N_clmem;i++) ClearSeq(i);
}

void AliL3VHDLClusterFinder::ClearSeq(UShort_t i){
  fSeqs[i].fRow=0;
  fSeqs[i].fLastPad=0;
  fSeqs[i].fTotalCharge=0;
  fSeqs[i].fPad=0;
  fSeqs[i].fTime=0;
  fSeqs[i].fPad2=0;
  fSeqs[i].fTime2=0;
  fSeqs[i].fMean=0;
  fSeqs[i].fMerge=0;
}

void AliL3VHDLClusterFinder::IncPointer(UShort_t &p, Short_t add, UShort_t N){
  Short_t pp=p;
  pp+=add;
  if(pp>=N) p=UShort_t(pp-N);
  else if(pp<0) p=UShort_t(pp+N);
  else p=UShort_t(pp);
}

inline void AliL3VHDLClusterFinder::IncRPointer(){
  IncPointer(fRP);
}

inline void AliL3VHDLClusterFinder::IncWPointer(){
  IncPointer(fWP);

  if(fWP==fOP){
    LOG(AliL3Log::kWarning,"AliL3VHDLClusterFinder::IncWPointer","Memory Check")
      <<"Write pointer overwrites output pointer."<<ENDLOG;
  }
}

inline void AliL3VHDLClusterFinder::NextFreeIndex(){
  IncPointer(fFirst,1,N_clmem);
  if(fFirst==fLast) {
    LOG(AliL3Log::kFatal,"AliL3VHDLClusterFinder::GetFreeIndex","Memory Check")
      <<"No space left in sequence list: "<<fFirst<<"=="<<fLast<<ENDLOG;
  }
}

#if 0
void AliL3ClustFinderNew::WriteClusters(Int_t n_clusters,ClusterData *list)
{
  Int_t thisrow,thissector;
  UInt_t counter = fNClusters;

  for(int j=0; j<n_clusters; j++)
    {
      if(!list[j].fFlags) continue; //discard 1 pad clusters
      if(list[j].fTotalCharge < fThreshold) continue; //noise cluster

      Float_t xyz[3];
      Float_t fpad =(Float_t)list[j].fPad /(Float_t)list[j].fTotalCharge;
      Float_t fpad2=fXYErr;
      Float_t ftime =(Float_t)list[j].fTime /(Float_t)list[j].fTotalCharge;
      Float_t ftime2=fZErr;

      if(fcalcerr) {
	fpad2=(Float_t)list[j].fPad2/(Float_t)list[j].fTotalCharge - fpad*fpad;
	fpad2 = sqrt(fpad2);
	ftime2=(Float_t)list[j].fTime2/(Float_t)list[j].fTotalCharge - ftime*ftime;
	ftime2 = sqrt(ftime2);
      }

      if(fstdout==kTRUE)
	cout<<"WriteCluster: padrow "<<fCurrentRow<<" pad "<<fpad << "+-"<<fpad2<<" time "<<ftime<<"+-"<<ftime2<<" charge "<<list[j].fTotalCharge<<endl;

      AliL3Transform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
      AliL3Transform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
      if(xyz[0]==0) LOG(AliL3Log::kError,"AliL3ClustFinder","Cluster Finder")
	<<AliL3Log::kDec<<"Zero cluster"<<ENDLOG;
      if(fNClusters >= fMaxNClusters)
	{
	  LOG(AliL3Log::kError,"AliL3ClustFinder::WriteClusters","Cluster Finder")
	    <<AliL3Log::kDec<<"Too many clusters"<<ENDLOG;
	  return;
	}
      fSpacePointData[counter].fCharge = list[j].fTotalCharge;
      fSpacePointData[counter].fX = xyz[0];
      fSpacePointData[counter].fY = xyz[1];
      fSpacePointData[counter].fZ = xyz[2];
      fSpacePointData[counter].fPadRow = fCurrentRow;
      fSpacePointData[counter].fXYErr = fpad2;
      fSpacePointData[counter].fZErr  = ftime2;
      fSpacePointData[counter].fID = counter
	+((fCurrentSlice&0x7f)<<25)+((fCurrentPatch&0x7)<<22);//Uli

      fNClusters++;
      counter++;
    }
}
#endif

<|endoftext|>