<commit_before>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * 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 copyright holders 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.
 *
 * Authors: Ron Dreslinski
 *          Steve Reinhardt
 *          Ali Saidi
 */

/**
 * @file
 * Declaration of a request, the overall memory request consisting of
 the parts of the request that are persistent throughout the transaction.
 */

#ifndef __MEM_REQUEST_HH__
#define __MEM_REQUEST_HH__

#include <cassert>

#include "base/fast_alloc.hh"
#include "base/flags.hh"
#include "base/misc.hh"
#include "base/types.hh"
#include "sim/core.hh"

class Request;

typedef Request* RequestPtr;

class Request : public FastAlloc
{
  public:
    typedef uint32_t FlagsType;
    typedef ::Flags<FlagsType> Flags;

    /** ASI information for this request if it exists. */
    static const FlagsType ASI_BITS                    = 0x000000FF;
    /** The request was an instruction fetch. */
    static const FlagsType INST_FETCH                  = 0x00000100;
    /** The virtual address is also the physical address. */
    static const FlagsType PHYSICAL                    = 0x00000200;
    /** The request is an ALPHA VPTE pal access (hw_ld). */
    static const FlagsType VPTE                        = 0x00000400;
    /** Use the alternate mode bits in ALPHA. */
    static const FlagsType ALTMODE                     = 0x00000800;
    /** The request is to an uncacheable address. */
    static const FlagsType UNCACHEABLE                 = 0x00001000;
    /** This request is to a memory mapped register. */
    static const FlagsType MMAPPED_IPR                  = 0x00002000;
    /** This request is a clear exclusive. */
    static const FlagsType CLEAR_LL                    = 0x00004000;

    /** The request should not cause a memory access. */
    static const FlagsType NO_ACCESS                   = 0x00080000;
    /** This request will lock or unlock the accessed memory. When used with
     * a load, the access locks the particular chunk of memory. When used
     * with a store, it unlocks. The rule is that locked accesses have to be
     * made up of a locked load, some operation on the data, and then a locked
     * store.
     */
    static const FlagsType LOCKED                      = 0x00100000;
    /** The request is a Load locked/store conditional. */
    static const FlagsType LLSC                        = 0x00200000;
    /** This request is for a memory swap. */
    static const FlagsType MEM_SWAP                    = 0x00400000;
    static const FlagsType MEM_SWAP_COND               = 0x00800000;

    /** The request is a prefetch. */
    static const FlagsType PREFETCH                    = 0x01000000;
    /** The request should be prefetched into the exclusive state. */
    static const FlagsType PF_EXCLUSIVE                = 0x02000000;
    /** The request should be marked as LRU. */
    static const FlagsType EVICT_NEXT                  = 0x04000000;

    /** These flags are *not* cleared when a Request object is reused
       (assigned a new address). */
    static const FlagsType STICKY_FLAGS = INST_FETCH;

  private:
    typedef uint8_t PrivateFlagsType;
    typedef ::Flags<PrivateFlagsType> PrivateFlags;

    /** Whether or not the size is valid. */
    static const PrivateFlagsType VALID_SIZE           = 0x00000001;
    /** Whether or not paddr is valid (has been written yet). */
    static const PrivateFlagsType VALID_PADDR          = 0x00000002;
    /** Whether or not the vaddr & asid are valid. */
    static const PrivateFlagsType VALID_VADDR          = 0x00000004;
    /** Whether or not the pc is valid. */
    static const PrivateFlagsType VALID_PC             = 0x00000010;
    /** Whether or not the context ID is valid. */
    static const PrivateFlagsType VALID_CONTEXT_ID     = 0x00000020;
    static const PrivateFlagsType VALID_THREAD_ID      = 0x00000040;
    /** Whether or not the sc result is valid. */
    static const PrivateFlagsType VALID_EXTRA_DATA     = 0x00000080;

    /** These flags are *not* cleared when a Request object is reused
       (assigned a new address). */
    static const PrivateFlagsType STICKY_PRIVATE_FLAGS =
        VALID_CONTEXT_ID | VALID_THREAD_ID;

  private:
    /**
     * The physical address of the request. Valid only if validPaddr
     * is set.
     */
    Addr _paddr;

    /**
     * The size of the request. This field must be set when vaddr or
     * paddr is written via setVirt() or setPhys(), so it is always
     * valid as long as one of the address fields is valid.
     */
    int _size;

    /** Flag structure for the request. */
    Flags _flags;

    /** Private flags for field validity checking. */
    PrivateFlags privateFlags;

    /**
     * The time this request was started. Used to calculate
     * latencies. This field is set to curTick() any time paddr or vaddr
     * is written.
     */
    Tick _time;

    /** The address space ID. */
    int _asid;

    /** The virtual address of the request. */
    Addr _vaddr;

    /**
     * Extra data for the request, such as the return value of
     * store conditional or the compare value for a CAS. */
    uint64_t _extraData;

    /** The context ID (for statistics, typically). */
    int _contextId;
    /** The thread ID (id within this CPU) */
    int _threadId;

    /** program counter of initiating access; for tracing/debugging */
    Addr _pc;

  public:
    /** Minimal constructor.  No fields are initialized.
     *  (Note that _flags and privateFlags are cleared by Flags
     *  default constructor.)
     */
    Request()
    {}

    /**
     * Constructor for physical (e.g. device) requests.  Initializes
     * just physical address, size, flags, and timestamp (to curTick()).
     * These fields are adequate to perform a request.
     */
    Request(Addr paddr, int size, Flags flags)
    {
        setPhys(paddr, size, flags);
    }

    Request(Addr paddr, int size, Flags flags, Tick time)
    {
        setPhys(paddr, size, flags, time);
    }

    Request(Addr paddr, int size, Flags flags, Tick time, Addr pc)
    {
        setPhys(paddr, size, flags, time);
        privateFlags.set(VALID_PC);
        _pc = pc;
    }

    Request(int asid, Addr vaddr, int size, Flags flags, Addr pc,
            int cid, ThreadID tid)
    {
        setVirt(asid, vaddr, size, flags, pc);
        setThreadContext(cid, tid);
    }

    ~Request() {}  // for FastAlloc

    /**
     * Set up CPU and thread numbers.
     */
    void
    setThreadContext(int context_id, ThreadID tid)
    {
        _contextId = context_id;
        _threadId = tid;
        privateFlags.set(VALID_CONTEXT_ID|VALID_THREAD_ID);
    }

    /**
     * Set up a physical (e.g. device) request in a previously
     * allocated Request object.
     */
    void
    setPhys(Addr paddr, int size, Flags flags, Tick time)
    {
        assert(size >= 0);
        _paddr = paddr;
        _size = size;
        _time = time;

        _flags.clear(~STICKY_FLAGS);
        _flags.set(flags);
        privateFlags.clear(~STICKY_PRIVATE_FLAGS);
        privateFlags.set(VALID_PADDR|VALID_SIZE);
    }

    void
    setPhys(Addr paddr, int size, Flags flags)
    {
        setPhys(paddr, size, flags, curTick());
    }

    /**
     * Set up a virtual (e.g., CPU) request in a previously
     * allocated Request object.
     */
    void
    setVirt(int asid, Addr vaddr, int size, Flags flags, Addr pc)
    {
        assert(size >= 0);
        _asid = asid;
        _vaddr = vaddr;
        _size = size;
        _pc = pc;
        _time = curTick();

        _flags.clear(~STICKY_FLAGS);
        _flags.set(flags);
        privateFlags.clear(~STICKY_PRIVATE_FLAGS);
        privateFlags.set(VALID_VADDR|VALID_SIZE|VALID_PC);
    }

    /**
     * Set just the physical address.  This should only be used to
     * record the result of a translation, and thus the vaddr must be
     * valid before this method is called.  Otherwise, use setPhys()
     * to guarantee that the size and flags are also set.
     */
    void
    setPaddr(Addr paddr)
    {
        assert(privateFlags.isSet(VALID_VADDR));
        _paddr = paddr;
        privateFlags.set(VALID_PADDR);
    }

    /**
     * Generate two requests as if this request had been split into two
     * pieces. The original request can't have been translated already.
     */
    void splitOnVaddr(Addr split_addr, RequestPtr &req1, RequestPtr &req2)
    {
        assert(privateFlags.isSet(VALID_VADDR));
        assert(privateFlags.noneSet(VALID_PADDR));
        assert(split_addr > _vaddr && split_addr < _vaddr + _size);
        req1 = new Request;
        *req1 = *this;
        req2 = new Request;
        *req2 = *this;
        req1->_size = split_addr - _vaddr;
        req2->_vaddr = split_addr;
        req2->_size = _size - req1->_size;
    }

    /**
     * Accessor for paddr.
     */
    bool
    hasPaddr()
    {
        return privateFlags.isSet(VALID_PADDR);
    }

    Addr
    getPaddr()
    {
        assert(privateFlags.isSet(VALID_PADDR));
        return _paddr;
    }

    /**
     *  Accessor for size.
     */
    bool
    hasSize()
    {
        return privateFlags.isSet(VALID_SIZE);
    }

    int
    getSize()
    {
        assert(privateFlags.isSet(VALID_SIZE));
        return _size;
    }

    /** Accessor for time. */
    Tick
    time() const
    {
        assert(privateFlags.isSet(VALID_PADDR|VALID_VADDR));
        return _time;
    }

    void
    time(Tick time)
    {
        assert(privateFlags.isSet(VALID_PADDR|VALID_VADDR));
        _time = time;
    }

    /** Accessor for flags. */
    Flags
    getFlags()
    {
        assert(privateFlags.isSet(VALID_PADDR|VALID_VADDR));
        return _flags;
    }

    /** Note that unlike other accessors, this function sets *specific
       flags* (ORs them in); it does not assign its argument to the
       _flags field.  Thus this method should rightly be called
       setFlags() and not just flags(). */
    void
    setFlags(Flags flags)
    {
        assert(privateFlags.isSet(VALID_PADDR|VALID_VADDR));
        _flags.set(flags);
    }

    /** Accessor function for vaddr.*/
    Addr
    getVaddr()
    {
        assert(privateFlags.isSet(VALID_VADDR));
        return _vaddr;
    }

    /** Accessor function for asid.*/
    int
    getAsid()
    {
        assert(privateFlags.isSet(VALID_VADDR));
        return _asid;
    }

    /** Accessor function for asi.*/
    uint8_t
    getAsi()
    {
        assert(privateFlags.isSet(VALID_VADDR));
        return _flags & ASI_BITS;
    }

    /** Accessor function to check if sc result is valid. */
    bool
    extraDataValid()
    {
        return privateFlags.isSet(VALID_EXTRA_DATA);
    }

    /** Accessor function for store conditional return value.*/
    uint64_t
    getExtraData() const
    {
        assert(privateFlags.isSet(VALID_EXTRA_DATA));
        return _extraData;
    }

    /** Accessor function for store conditional return value.*/
    void
    setExtraData(uint64_t extraData)
    {
        _extraData = extraData;
        privateFlags.set(VALID_EXTRA_DATA);
    }

    bool
    hasContextId() const
    {
        return privateFlags.isSet(VALID_CONTEXT_ID);
    }

    /** Accessor function for context ID.*/
    int
    contextId() const
    {
        assert(privateFlags.isSet(VALID_CONTEXT_ID));
        return _contextId;
    }

    /** Accessor function for thread ID. */
    int
    threadId() const
    {
        assert(privateFlags.isSet(VALID_THREAD_ID));
        return _threadId;
    }

    bool
    hasPC() const
    {
        return privateFlags.isSet(VALID_PC);
    }

    /** Accessor function for pc.*/
    Addr
    getPC() const
    {
        assert(privateFlags.isSet(VALID_PC));
        return _pc;
    }

    /** Accessor functions for flags.  Note that these are for testing
       only; setting flags should be done via setFlags(). */
    bool isUncacheable() const { return _flags.isSet(UNCACHEABLE); }
    bool isInstFetch() const { return _flags.isSet(INST_FETCH); }
    bool isPrefetch() const { return _flags.isSet(PREFETCH); }
    bool isLLSC() const { return _flags.isSet(LLSC); }
    bool isLocked() const { return _flags.isSet(LOCKED); }
    bool isSwap() const { return _flags.isSet(MEM_SWAP|MEM_SWAP_COND); }
    bool isCondSwap() const { return _flags.isSet(MEM_SWAP_COND); }
    bool isMmappedIpr() const { return _flags.isSet(MMAPPED_IPR); }
    bool isClearLL() const { return _flags.isSet(CLEAR_LL); }
};

#endif // __MEM_REQUEST_HH__
<commit_msg>Mem: Allow ASID to be set after request is created.<commit_after>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * 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 copyright holders 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.
 *
 * Authors: Ron Dreslinski
 *          Steve Reinhardt
 *          Ali Saidi
 */

/**
 * @file
 * Declaration of a request, the overall memory request consisting of
 the parts of the request that are persistent throughout the transaction.
 */

#ifndef __MEM_REQUEST_HH__
#define __MEM_REQUEST_HH__

#include <cassert>

#include "base/fast_alloc.hh"
#include "base/flags.hh"
#include "base/misc.hh"
#include "base/types.hh"
#include "sim/core.hh"

class Request;

typedef Request* RequestPtr;

class Request : public FastAlloc
{
  public:
    typedef uint32_t FlagsType;
    typedef ::Flags<FlagsType> Flags;

    /** ASI information for this request if it exists. */
    static const FlagsType ASI_BITS                    = 0x000000FF;
    /** The request was an instruction fetch. */
    static const FlagsType INST_FETCH                  = 0x00000100;
    /** The virtual address is also the physical address. */
    static const FlagsType PHYSICAL                    = 0x00000200;
    /** The request is an ALPHA VPTE pal access (hw_ld). */
    static const FlagsType VPTE                        = 0x00000400;
    /** Use the alternate mode bits in ALPHA. */
    static const FlagsType ALTMODE                     = 0x00000800;
    /** The request is to an uncacheable address. */
    static const FlagsType UNCACHEABLE                 = 0x00001000;
    /** This request is to a memory mapped register. */
    static const FlagsType MMAPPED_IPR                  = 0x00002000;
    /** This request is a clear exclusive. */
    static const FlagsType CLEAR_LL                    = 0x00004000;

    /** The request should not cause a memory access. */
    static const FlagsType NO_ACCESS                   = 0x00080000;
    /** This request will lock or unlock the accessed memory. When used with
     * a load, the access locks the particular chunk of memory. When used
     * with a store, it unlocks. The rule is that locked accesses have to be
     * made up of a locked load, some operation on the data, and then a locked
     * store.
     */
    static const FlagsType LOCKED                      = 0x00100000;
    /** The request is a Load locked/store conditional. */
    static const FlagsType LLSC                        = 0x00200000;
    /** This request is for a memory swap. */
    static const FlagsType MEM_SWAP                    = 0x00400000;
    static const FlagsType MEM_SWAP_COND               = 0x00800000;

    /** The request is a prefetch. */
    static const FlagsType PREFETCH                    = 0x01000000;
    /** The request should be prefetched into the exclusive state. */
    static const FlagsType PF_EXCLUSIVE                = 0x02000000;
    /** The request should be marked as LRU. */
    static const FlagsType EVICT_NEXT                  = 0x04000000;

    /** These flags are *not* cleared when a Request object is reused
       (assigned a new address). */
    static const FlagsType STICKY_FLAGS = INST_FETCH;

  private:
    typedef uint8_t PrivateFlagsType;
    typedef ::Flags<PrivateFlagsType> PrivateFlags;

    /** Whether or not the size is valid. */
    static const PrivateFlagsType VALID_SIZE           = 0x00000001;
    /** Whether or not paddr is valid (has been written yet). */
    static const PrivateFlagsType VALID_PADDR          = 0x00000002;
    /** Whether or not the vaddr & asid are valid. */
    static const PrivateFlagsType VALID_VADDR          = 0x00000004;
    /** Whether or not the pc is valid. */
    static const PrivateFlagsType VALID_PC             = 0x00000010;
    /** Whether or not the context ID is valid. */
    static const PrivateFlagsType VALID_CONTEXT_ID     = 0x00000020;
    static const PrivateFlagsType VALID_THREAD_ID      = 0x00000040;
    /** Whether or not the sc result is valid. */
    static const PrivateFlagsType VALID_EXTRA_DATA     = 0x00000080;

    /** These flags are *not* cleared when a Request object is reused
       (assigned a new address). */
    static const PrivateFlagsType STICKY_PRIVATE_FLAGS =
        VALID_CONTEXT_ID | VALID_THREAD_ID;

  private:
    /**
     * The physical address of the request. Valid only if validPaddr
     * is set.
     */
    Addr _paddr;

    /**
     * The size of the request. This field must be set when vaddr or
     * paddr is written via setVirt() or setPhys(), so it is always
     * valid as long as one of the address fields is valid.
     */
    int _size;

    /** Flag structure for the request. */
    Flags _flags;

    /** Private flags for field validity checking. */
    PrivateFlags privateFlags;

    /**
     * The time this request was started. Used to calculate
     * latencies. This field is set to curTick() any time paddr or vaddr
     * is written.
     */
    Tick _time;

    /** The address space ID. */
    int _asid;

    /** The virtual address of the request. */
    Addr _vaddr;

    /**
     * Extra data for the request, such as the return value of
     * store conditional or the compare value for a CAS. */
    uint64_t _extraData;

    /** The context ID (for statistics, typically). */
    int _contextId;
    /** The thread ID (id within this CPU) */
    int _threadId;

    /** program counter of initiating access; for tracing/debugging */
    Addr _pc;

  public:
    /** Minimal constructor.  No fields are initialized.
     *  (Note that _flags and privateFlags are cleared by Flags
     *  default constructor.)
     */
    Request()
    {}

    /**
     * Constructor for physical (e.g. device) requests.  Initializes
     * just physical address, size, flags, and timestamp (to curTick()).
     * These fields are adequate to perform a request.
     */
    Request(Addr paddr, int size, Flags flags)
    {
        setPhys(paddr, size, flags);
    }

    Request(Addr paddr, int size, Flags flags, Tick time)
    {
        setPhys(paddr, size, flags, time);
    }

    Request(Addr paddr, int size, Flags flags, Tick time, Addr pc)
    {
        setPhys(paddr, size, flags, time);
        privateFlags.set(VALID_PC);
        _pc = pc;
    }

    Request(int asid, Addr vaddr, int size, Flags flags, Addr pc,
            int cid, ThreadID tid)
    {
        setVirt(asid, vaddr, size, flags, pc);
        setThreadContext(cid, tid);
    }

    ~Request() {}  // for FastAlloc

    /**
     * Set up CPU and thread numbers.
     */
    void
    setThreadContext(int context_id, ThreadID tid)
    {
        _contextId = context_id;
        _threadId = tid;
        privateFlags.set(VALID_CONTEXT_ID|VALID_THREAD_ID);
    }

    /**
     * Set up a physical (e.g. device) request in a previously
     * allocated Request object.
     */
    void
    setPhys(Addr paddr, int size, Flags flags, Tick time)
    {
        assert(size >= 0);
        _paddr = paddr;
        _size = size;
        _time = time;

        _flags.clear(~STICKY_FLAGS);
        _flags.set(flags);
        privateFlags.clear(~STICKY_PRIVATE_FLAGS);
        privateFlags.set(VALID_PADDR|VALID_SIZE);
    }

    void
    setPhys(Addr paddr, int size, Flags flags)
    {
        setPhys(paddr, size, flags, curTick());
    }

    /**
     * Set up a virtual (e.g., CPU) request in a previously
     * allocated Request object.
     */
    void
    setVirt(int asid, Addr vaddr, int size, Flags flags, Addr pc)
    {
        assert(size >= 0);
        _asid = asid;
        _vaddr = vaddr;
        _size = size;
        _pc = pc;
        _time = curTick();

        _flags.clear(~STICKY_FLAGS);
        _flags.set(flags);
        privateFlags.clear(~STICKY_PRIVATE_FLAGS);
        privateFlags.set(VALID_VADDR|VALID_SIZE|VALID_PC);
    }

    /**
     * Set just the physical address.  This should only be used to
     * record the result of a translation, and thus the vaddr must be
     * valid before this method is called.  Otherwise, use setPhys()
     * to guarantee that the size and flags are also set.
     */
    void
    setPaddr(Addr paddr)
    {
        assert(privateFlags.isSet(VALID_VADDR));
        _paddr = paddr;
        privateFlags.set(VALID_PADDR);
    }

    /**
     * Generate two requests as if this request had been split into two
     * pieces. The original request can't have been translated already.
     */
    void splitOnVaddr(Addr split_addr, RequestPtr &req1, RequestPtr &req2)
    {
        assert(privateFlags.isSet(VALID_VADDR));
        assert(privateFlags.noneSet(VALID_PADDR));
        assert(split_addr > _vaddr && split_addr < _vaddr + _size);
        req1 = new Request;
        *req1 = *this;
        req2 = new Request;
        *req2 = *this;
        req1->_size = split_addr - _vaddr;
        req2->_vaddr = split_addr;
        req2->_size = _size - req1->_size;
    }

    /**
     * Accessor for paddr.
     */
    bool
    hasPaddr()
    {
        return privateFlags.isSet(VALID_PADDR);
    }

    Addr
    getPaddr()
    {
        assert(privateFlags.isSet(VALID_PADDR));
        return _paddr;
    }

    /**
     *  Accessor for size.
     */
    bool
    hasSize()
    {
        return privateFlags.isSet(VALID_SIZE);
    }

    int
    getSize()
    {
        assert(privateFlags.isSet(VALID_SIZE));
        return _size;
    }

    /** Accessor for time. */
    Tick
    time() const
    {
        assert(privateFlags.isSet(VALID_PADDR|VALID_VADDR));
        return _time;
    }

    void
    time(Tick time)
    {
        assert(privateFlags.isSet(VALID_PADDR|VALID_VADDR));
        _time = time;
    }

    /** Accessor for flags. */
    Flags
    getFlags()
    {
        assert(privateFlags.isSet(VALID_PADDR|VALID_VADDR));
        return _flags;
    }

    /** Note that unlike other accessors, this function sets *specific
       flags* (ORs them in); it does not assign its argument to the
       _flags field.  Thus this method should rightly be called
       setFlags() and not just flags(). */
    void
    setFlags(Flags flags)
    {
        assert(privateFlags.isSet(VALID_PADDR|VALID_VADDR));
        _flags.set(flags);
    }

    /** Accessor function for vaddr.*/
    Addr
    getVaddr()
    {
        assert(privateFlags.isSet(VALID_VADDR));
        return _vaddr;
    }

    /** Accessor function for asid.*/
    int
    getAsid()
    {
        assert(privateFlags.isSet(VALID_VADDR));
        return _asid;
    }

    /** Accessor function for asid.*/
    void
    setAsid(int asid)
    {
        _asid = asid;
    }

    /** Accessor function for asi.*/
    uint8_t
    getAsi()
    {
        assert(privateFlags.isSet(VALID_VADDR));
        return _flags & ASI_BITS;
    }

    /** Accessor function to check if sc result is valid. */
    bool
    extraDataValid()
    {
        return privateFlags.isSet(VALID_EXTRA_DATA);
    }

    /** Accessor function for store conditional return value.*/
    uint64_t
    getExtraData() const
    {
        assert(privateFlags.isSet(VALID_EXTRA_DATA));
        return _extraData;
    }

    /** Accessor function for store conditional return value.*/
    void
    setExtraData(uint64_t extraData)
    {
        _extraData = extraData;
        privateFlags.set(VALID_EXTRA_DATA);
    }

    bool
    hasContextId() const
    {
        return privateFlags.isSet(VALID_CONTEXT_ID);
    }

    /** Accessor function for context ID.*/
    int
    contextId() const
    {
        assert(privateFlags.isSet(VALID_CONTEXT_ID));
        return _contextId;
    }

    /** Accessor function for thread ID. */
    int
    threadId() const
    {
        assert(privateFlags.isSet(VALID_THREAD_ID));
        return _threadId;
    }

    bool
    hasPC() const
    {
        return privateFlags.isSet(VALID_PC);
    }

    /** Accessor function for pc.*/
    Addr
    getPC() const
    {
        assert(privateFlags.isSet(VALID_PC));
        return _pc;
    }

    /** Accessor functions for flags.  Note that these are for testing
       only; setting flags should be done via setFlags(). */
    bool isUncacheable() const { return _flags.isSet(UNCACHEABLE); }
    bool isInstFetch() const { return _flags.isSet(INST_FETCH); }
    bool isPrefetch() const { return _flags.isSet(PREFETCH); }
    bool isLLSC() const { return _flags.isSet(LLSC); }
    bool isLocked() const { return _flags.isSet(LOCKED); }
    bool isSwap() const { return _flags.isSet(MEM_SWAP|MEM_SWAP_COND); }
    bool isCondSwap() const { return _flags.isSet(MEM_SWAP_COND); }
    bool isMmappedIpr() const { return _flags.isSet(MMAPPED_IPR); }
    bool isClearLL() const { return _flags.isSet(CLEAR_LL); }
};

#endif // __MEM_REQUEST_HH__
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <iostream>
#include <vector>

#include <thrift/processor/TMultiplexedProcessor.h>

#include "xbt.h"
#include "simgrid/s4u.hpp"

#include "rsg/services.hpp"
#include "rsg/Server.hpp"
#include "common.hpp"

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;

using boost::shared_ptr;
using namespace ::simgrid;

std::vector<std::thread*> threads;

XBT_LOG_NEW_CATEGORY(RSG_THRIFT, "Remote SimGrid");
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(RSG_THRIFT_SERVER, RSG_THRIFT , "RSG server (Remote SimGrid)");

/* Fork a remote process, and serve it until it CMD_QUITs */
static int rsg_representative(int argc, char **argv) {
    debug_server_print("START");
    if (! fork()) {
        int newargc = argc-1+2+1;
        char **newargv = (char**)calloc(newargc, sizeof(char*));
        newargv[0] = (char*)"/usr/bin/env";
        newargv[1] = (char*)"--";
        for(int i=1; i < argc; i++) {
            newargv[1+i] = argv[i];
        }
        newargv[newargc-1] = NULL;
        debug_server_print("fork+exec: %s", newargv[2]);
        execv(newargv[0], newargv);
    }
    debug_server_print("RUN server");
    SocketServer &socketServer = SocketServer::getSocketServer();
    RsgThriftServerFramework *server = socketServer.acceptClient();
    server->serve();
    delete server;
    debug_server_print("END");
    return 0;
}

int main(int argc, char **argv) {

    SocketServer &socketServer = SocketServer::createSocketServer(std::string("127.0.0.1"), 9090);
    socketServer.connect();

    s4u::Engine *e = new s4u::Engine(&argc,argv);

    if (argc < 3) {
        fprintf(stderr,"Usage: rsg platform.xml deploy.xml port\n");
        exit(1);
    }

    /* Initialize the SimGrid world */
    e->loadPlatform(argv[1]);
    e->registerDefault(rsg_representative);
    e->loadDeployment(argv[2]);
    e->run();

    socketServer.closeServer();
    return 0;
}
<commit_msg>Actor from deployement file can connects with an env variable<commit_after>#include <stdlib.h>
#include <iostream>
#include <vector>

#include <thrift/processor/TMultiplexedProcessor.h>

#include "xbt.h"
#include "simgrid/s4u.hpp"

#include "rsg/Socket.hpp"
#include "rsg/services.hpp"
#include "rsg/Server.hpp"
#include "common.hpp"

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;

using boost::shared_ptr;
using namespace ::simgrid;

std::vector<std::thread*> threads;

XBT_LOG_NEW_CATEGORY(RSG_THRIFT, "Remote SimGrid");
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(RSG_THRIFT_SERVER, RSG_THRIFT , "RSG server (Remote SimGrid)");

/*!
 *  Fork a remote process, creates an RPC server to handle all the actor communication
 *  The function first creates an RPC server with an unused TCP port. When the server is succefully setted in listen mode
 *  the function forks and set the Rpc port to the environment with execve.
*/
static int rsg_representative(int argc, char **argv) {
    debug_server_print("START");

    //First we create an RPC server designed to communicate with the futur child
    int rpcPort = getFreePort(1024);
    bool connected = false;

    RsgThriftServerFramework* server = NULL;
    do {
        server = SocketServer::getSocketServer().createRpcServer(rpcPort);
        try {
            server->listen();
            connected = true;
        } catch(apache::thrift::transport::TTransportException &ex) {
            rpcPort = getFreePort(1024);
            delete server;
        }
    } while( ! connected);

    // We fork the actor process
    if (! fork()) {
        //We create the string formated to environment variables (key=value)
        std::string envKeyValueStr, envKeyName = "RsgRpcPort";
        std::string envValue = std::to_string(rpcPort);
        envKeyValueStr = envKeyName + "=" + envValue;

        // Initialization of the array desgnied to host the new environment variables
        int envp_size = 2;
        char **newenviron = (char**) malloc(sizeof(char*) * envp_size);
        newenviron[0] = (char*) malloc(sizeof(char) * (envKeyValueStr.size() + 1));

        // Copying the new key value string
        strcpy(newenviron[0], envKeyValueStr.c_str());
        // Null terminating of the array
        newenviron[1] = NULL;

        int newargc = argc-1+2+1;
        char **newargv = (char**)calloc(newargc, sizeof(char*));
        newargv[0] = (char*)"/usr/bin/env";
        newargv[1] = (char*)"--";
        for(int i=1; i < argc; i++) {
            newargv[1+i] = argv[i];
        }
        newargv[newargc-1] = NULL;
        debug_server_print("fork+exec: %s", newargv[2]);
        execve(newargv[0], newargv, newenviron);
    }

    server->serve();
    delete server;
    debug_server_print("END");
    return 0;
}

int main(int argc, char **argv) {

    SocketServer &socketServer = SocketServer::createSocketServer(std::string("127.0.0.1"), 9090);
    socketServer.connect();

    s4u::Engine *e = new s4u::Engine(&argc,argv);

    if (argc < 3) {
        fprintf(stderr,"Usage: rsg platform.xml deploy.xml port\n");
        exit(1);
    }

    /* Initialize the SimGrid world */
    e->loadPlatform(argv[1]);
    e->registerDefault(rsg_representative);
    e->loadDeployment(argv[2]);
    e->run();

    socketServer.closeServer();
    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <sstream>
#include <string>
#include <zmq.hpp>
#include "read_line.hpp"
#include <bitcoin/client.hpp>

static void on_unknown(const std::string& command)
{
    std::cout << "unknown message:" << command << std::endl;
}

static void on_update(const bc::payment_address& address,
    size_t height, const bc::hash_digest& blk_hash,
    const bc::transaction_type&)
{
    std::cout << "update:" << address.encoded() << std::endl;
}

/**
 * A dynamically-allocated structure holding the resources needed for a
 * connection to a bitcoin server.
 */
class connection
{
public:
    connection(zmq::context_t& context, const std::string& server)
      : socket(context, server), codec(socket, on_update, on_unknown)
    {
    }

    libbitcoin::client::zmq_socket socket;
    libbitcoin::client::obelisk_codec codec;
};

/**
 * Command-line interface for talking to the oblelisk server.
 */
class cli
{
public:
    ~cli();
    cli();

    int run();

private:
    void command();
    void cmd_exit();
    void cmd_help();
    void cmd_connect(std::stringstream& args);
    void cmd_disconnect(std::stringstream& args);
    void cmd_height(std::stringstream& args);

    bool check_connection();
    bool read_string(std::stringstream& args, std::string& out,
        const std::string& error_message);

    bool done_;

    zmq::context_t context_;
    read_line terminal_;
    connection *connection_;
};

cli::~cli()
{
    delete connection_;
}

cli::cli()
  : done_(false), terminal_(context_), connection_(nullptr)
{
}

/**
 * The main loop for the example application. This loop can be woken up
 * by either events from the network or by input from the terminal.
 */
int cli::run()
{
    std::cout << "type \"help\" for instructions" << std::endl;
    terminal_.show_prompt();

    while (!done_)
    {
        std::vector<zmq_pollitem_t> items;
        items.reserve(2);
        items.push_back(terminal_.pollitem());
        if (connection_)
            items.push_back(connection_->socket.pollitem());
        zmq::poll(items.data(), items.size(), -1);

        if (items[0].revents)
            command();
        if (connection_ && items[1].revents)
            connection_->socket.forward(connection_->codec);
    }
    return 0;
}

/**
 * Reads a command from the terminal thread, and processes it appropriately.
 */
void cli::command()
{
    std::stringstream reader(terminal_.get_line());
    std::string command;
    reader >> command;

    if (command == "exit")              cmd_exit();
    else if (command == "help")         cmd_help();
    else if (command == "connect")      cmd_connect(reader);
    else if (command == "disconnect")   cmd_disconnect(reader);
    else if (command == "height")       cmd_height(reader);
    else
        std::cout << "unknown command " << command << std::endl;

    // Display another prompt, if needed:
    if (!done_)
        terminal_.show_prompt();
}

void cli::cmd_exit()
{
    done_ = true;
}

void cli::cmd_help()
{
    std::cout << "commands:" << std::endl;
    std::cout << "  exit              - leave the program" << std::endl;
    std::cout << "  help              - this menu" << std::endl;
    std::cout << "  connect <server>  - connect to a server" << std::endl;
    std::cout << "  disconnect        - disconnect from the server" << std::endl;
    std::cout << "  height            - get last block height" << std::endl;
}

void cli::cmd_connect(std::stringstream& args)
{
    std::string server;
    if (!read_string(args, server, "error: no server given"))
        return;
    std::cout << "connecting to " << server << std::endl;

    delete connection_;
    connection_ = nullptr;
    try
    {
        connection_ = new connection(context_, server);
    }
    catch (zmq::error_t)
    {
        std::cout << "error: failed to connect" << std::endl;
    }
}

void cli::cmd_disconnect(std::stringstream& args)
{
    if (!check_connection())
        return;
    delete connection_;
    connection_ = nullptr;
}

static void on_error(const std::error_code& ec)
{
    std::cout << "error: " << ec.message() << std::endl;
}

void cli::cmd_height(std::stringstream& args)
{
    if (!check_connection())
        return;

    auto handler = [](size_t height)
    {
        std::cout << "height: " << height << std::endl;
    };
    connection_->codec.fetch_last_height(on_error, handler);
}

/**
 * Verifies that a connection exists, and prints an error message otherwise.
 */
bool cli::check_connection()
{
    if (!connection_)
    {
        std::cout << "error: no connection" << std::endl;
        return false;
    }
    return true;
}

/**
 * Parses a string argument out of the command line,
 * or prints an error message if there is none.
 */
bool cli::read_string(std::stringstream& args, std::string& out,
    const std::string& error_message)
{
    args >> out;
    if (!out.size())
    {
        std::cout << error_message << std::endl;
        return false;
    }
    return true;
}

int main()
{
    cli c;
    return c.run();
}
<commit_msg>examples: Add history command<commit_after>#include <iostream>
#include <sstream>
#include <string>
#include <zmq.hpp>
#include "read_line.hpp"
#include <bitcoin/client.hpp>

static void on_unknown(const std::string& command)
{
    std::cout << "unknown message:" << command << std::endl;
}

static void on_update(const bc::payment_address& address,
    size_t height, const bc::hash_digest& blk_hash,
    const bc::transaction_type&)
{
    std::cout << "update:" << address.encoded() << std::endl;
}

/**
 * A dynamically-allocated structure holding the resources needed for a
 * connection to a bitcoin server.
 */
class connection
{
public:
    connection(zmq::context_t& context, const std::string& server)
      : socket(context, server), codec(socket, on_update, on_unknown)
    {
    }

    libbitcoin::client::zmq_socket socket;
    libbitcoin::client::obelisk_codec codec;
};

/**
 * Command-line interface for talking to the oblelisk server.
 */
class cli
{
public:
    ~cli();
    cli();

    int run();

private:
    void command();
    void cmd_exit();
    void cmd_help();
    void cmd_connect(std::stringstream& args);
    void cmd_disconnect(std::stringstream& args);
    void cmd_height(std::stringstream& args);
    void cmd_history(std::stringstream& args);

    bool check_connection();
    bool read_string(std::stringstream& args, std::string& out,
        const std::string& error_message);
    bool read_address(std::stringstream& args, bc::payment_address& out);

    bool done_;

    zmq::context_t context_;
    read_line terminal_;
    connection *connection_;
};

cli::~cli()
{
    delete connection_;
}

cli::cli()
  : done_(false), terminal_(context_), connection_(nullptr)
{
}

/**
 * The main loop for the example application. This loop can be woken up
 * by either events from the network or by input from the terminal.
 */
int cli::run()
{
    std::cout << "type \"help\" for instructions" << std::endl;
    terminal_.show_prompt();

    while (!done_)
    {
        std::vector<zmq_pollitem_t> items;
        items.reserve(2);
        items.push_back(terminal_.pollitem());
        if (connection_)
            items.push_back(connection_->socket.pollitem());
        zmq::poll(items.data(), items.size(), -1);

        if (items[0].revents)
            command();
        if (connection_ && items[1].revents)
            connection_->socket.forward(connection_->codec);
    }
    return 0;
}

/**
 * Reads a command from the terminal thread, and processes it appropriately.
 */
void cli::command()
{
    std::stringstream reader(terminal_.get_line());
    std::string command;
    reader >> command;

    if (command == "exit")              cmd_exit();
    else if (command == "help")         cmd_help();
    else if (command == "connect")      cmd_connect(reader);
    else if (command == "disconnect")   cmd_disconnect(reader);
    else if (command == "height")       cmd_height(reader);
    else if (command == "history")      cmd_history(reader);
    else
        std::cout << "unknown command " << command << std::endl;

    // Display another prompt, if needed:
    if (!done_)
        terminal_.show_prompt();
}

void cli::cmd_exit()
{
    done_ = true;
}

void cli::cmd_help()
{
    std::cout << "commands:" << std::endl;
    std::cout << "  exit              - leave the program" << std::endl;
    std::cout << "  help              - this menu" << std::endl;
    std::cout << "  connect <server>  - connect to a server" << std::endl;
    std::cout << "  disconnect        - disconnect from the server" << std::endl;
    std::cout << "  height            - get last block height" << std::endl;
    std::cout << "  history <address> - get an address' history" << std::endl;
}

void cli::cmd_connect(std::stringstream& args)
{
    std::string server;
    if (!read_string(args, server, "error: no server given"))
        return;
    std::cout << "connecting to " << server << std::endl;

    delete connection_;
    connection_ = nullptr;
    try
    {
        connection_ = new connection(context_, server);
    }
    catch (zmq::error_t)
    {
        std::cout << "error: failed to connect" << std::endl;
    }
}

void cli::cmd_disconnect(std::stringstream& args)
{
    if (!check_connection())
        return;
    delete connection_;
    connection_ = nullptr;
}

static void on_error(const std::error_code& ec)
{
    std::cout << "error: " << ec.message() << std::endl;
}

void cli::cmd_height(std::stringstream& args)
{
    if (!check_connection())
        return;

    auto handler = [](size_t height)
    {
        std::cout << "height: " << height << std::endl;
    };
    connection_->codec.fetch_last_height(on_error, handler);
}

void cli::cmd_history(std::stringstream& args)
{
    if (!check_connection())
        return;
    bc::payment_address address;
    if (!read_address(args, address))
        return;

    auto handler = [](const bc::blockchain::history_list& history)
    {
        for (auto row: history)
            std::cout << row.value << std::endl;
    };
    connection_->codec.address_fetch_history(on_error, handler, address);
}

/**
 * Verifies that a connection exists, and prints an error message otherwise.
 */
bool cli::check_connection()
{
    if (!connection_)
    {
        std::cout << "error: no connection" << std::endl;
        return false;
    }
    return true;
}

/**
 * Parses a string argument out of the command line,
 * or prints an error message if there is none.
 */
bool cli::read_string(std::stringstream& args, std::string& out,
    const std::string& error_message)
{
    args >> out;
    if (!out.size())
    {
        std::cout << error_message << std::endl;
        return false;
    }
    return true;
}

/**
 * Reads a bitcoin address from the command-line, or prints an error if
 * the address is missing or invalid.
 */
bool cli::read_address(std::stringstream& args, bc::payment_address& out)
{
    std::string address;
    if (!read_string(args, address, "error: no address given"))
        return false;
    if (!out.set_encoded(address))
    {
        std::cout << "error: invalid address " << address << std::endl;
        return false;
    }
    return true;
}

int main()
{
    cli c;
    return c.run();
}
<|endoftext|>


<commit_before>// Make use of the CMake build system or compile manually, e.g. with:
// g++ -std=c++11 example.cc -lsweep

#include <cstdlib>
#include <iostream>

#include <neo/neo.hpp>

int main(int argc, char* argv[]) try {
  if (argc != 2) {
    std::cerr << "Usage: ./example-c++ device\n";
    return EXIT_FAILURE;
  }

  std::cout << "Constructing sweep device..." << std::endl;
  neo::neo device{argv[1]};

  std::cout << "Motor Speed Setting: " << device.get_motor_speed()
    << " Hz" << std::endl;
//  std::cout << "Sample Rate Setting: " << device.get_sample_rate()
//    << " Hz" << std::endl;

  std::cout << "Beginning data acquisition as soon as motor speed stabilizes..."
    << std::endl;
  device.start_scanning();

  for (auto n = 0; n < 10; ++n) {
    const neo::scan scan = device.get_scan();

    std::cout << "Scan #" << n << ":" << std::endl;
    for (const neo::sample& sample : scan.samples) {
      std::cout << "angle " << sample.angle << " distance "
        << sample.distance << std::endl;
        //<< " strength " << sample.signal_strength << "\n";
    }
  }

  device.stop_scanning();
} catch (const neo::device_error& e) {
  std::cerr << "Error: " << e.what() << std::endl;
}

<commit_msg>fix(example baudrate): adding baudrate to example.<commit_after>// Make use of the CMake build system or compile manually, e.g. with:
// g++ -std=c++11 example.cc -lsweep

#include <cstdlib>
#include <iostream>

#include <neo/neo.hpp>

int main(int argc, char* argv[]) try {
  if (argc != 3) {
    std::cerr << "Usage: ./example-c++ device baudrate\n";
    return EXIT_FAILURE;
  }

  std::cout << "Constructing sweep device..." << std::endl;
  neo::neo device{argv[1], atoi(argv[2])};

  std::cout << "Motor Speed Setting: " << device.get_motor_speed()
    << " Hz" << std::endl;
//  std::cout << "Sample Rate Setting: " << device.get_sample_rate()
//    << " Hz" << std::endl;

  std::cout << "Beginning data acquisition as soon as motor speed stabilizes..."
    << std::endl;
  device.start_scanning();

  for (auto n = 0; n < 10; ++n) {
    const neo::scan scan = device.get_scan();

    std::cout << "Scan #" << n << ":" << std::endl;
    for (const neo::sample& sample : scan.samples) {
      std::cout << "angle " << sample.angle << " distance "
        << sample.distance << std::endl;
        //<< " strength " << sample.signal_strength << "\n";
    }
  }

  device.stop_scanning();
} catch (const neo::device_error& e) {
  std::cerr << "Error: " << e.what() << std::endl;
}

<|endoftext|>


<commit_before>#include <string.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <time.h>

#include "SuMo.h"
#include "Timer.h"

/* specific to file */
const int NUM_ARGS = 4;
const char* filename = "logData";
const char* description = "log data from DAQ";
using namespace std;
/********************/

/* subtract pedestal values on-line */
static bool PED_SUBTRCT = false;

static int LIMIT_READOUT_RATE  = 6000;  //usecs limit between event polling
static int NUM_SEQ_TIMEOUTS    = 100;    // number of sequential timeouts before ending run
const  float  MAX_INT_TIMER    = 800.;    // max cpu timer before ending run (secs)
/* note: usb timeout defined in include/stdUSB.h */

bool overwriteExistingFile = false;

int main(int argc, char* argv[]){
    if(argc == 2 && std::string(argv[1]) == "-h"){
        cout << endl;
        cout << filename << " :: " << description << endl;
        cout << filename << " :: takes " << NUM_ARGS-1 << " arguments" << endl;
        return 1;
    }
    else if(argc > NUM_ARGS+1 || argc < NUM_ARGS){
        cout << "error: too many number of arguments" << endl;
        return -1;
    }
    else{
        int num_checks = 5;
        int num_events = 100;
        SuMo command;
        char log_data_filename[100];

        strcpy(log_data_filename, argv[1]);
        num_events = atoi(argv[2]);
        int trig_mode = atoi(argv[3]);

        if(command.check_active_boards(num_checks))
        return 1;

        vector<packet_t**> events = command.get_data(num_events, trig_mode, 0);
        command.log_data(log_data_filename, events, trig_mode);

        return 0;
    }
}

vector<packet_t**> SuMo::get_data(unsigned int NUM_READS, int trig_mode, int acq_rate){

    int check_event;
    int asic_baseline[psecSampleCells];
    int count = 0;
    int psec_cnt = 0;
    int last_k;
    float  _now_, t = 0.;
    char logDataFilename[300];
    Timer timer = Timer();
    time_t now;
    unsigned short sample;
    int* Meta;

    vector<packet_t**> event_data;

    // read all front end cards
    bool all[numFrontBoards];
    for(int i = 0; i < numFrontBoards; i++) all[i] = true;

    load_ped();

    int number_of_frontend_cards = 0;

    for( int board = 0; board < numFrontBoards; board++){
        if(DC_ACTIVE[board]) number_of_frontend_cards++;

    }

    cout << "--------------------------------------------------------------" << endl;
    cout << "number of front-end boards detected = " << number_of_frontend_cards
    << " of " << numFrontBoards << " address slots in system" << endl;
    cout << "Trying for " << NUM_READS << " events logged to disk, in a timeout window of "
    << MAX_INT_TIMER << " seconds" << endl;
    cout << "--------------------------------------------------------------" << endl << endl;

    usleep(100000);

    /* cpu time zero */
    timer.start();

    bool reset_event = true;

    // set read mode to NULL
    set_usb_read_mode(0);
    if(mode==USB2x) set_usb_read_mode_slaveDevice(0);
    system_card_trig_valid(false);
    if(mode==USB2x) system_slave_card_trig_valid(false);

    //check system trigger number
    read_CC(false, false, 100);
    int board_trigger= CC_EVENT_COUNT_FROMCC0;
    int last_board_trigger = board_trigger;

    for(int k=0; k<NUM_READS; k++){
        set_usb_read_mode(0);
        if(mode==USB2x) set_usb_read_mode_slaveDevice(0);

        time(&now);
        t = timer.stop();
        // interrupt if past specified logging time
        if(t > MAX_INT_TIMER) {
            cout << endl << "readout timed out at " << t << "on event " << k << endl;
            break;
        }

        // trig_mode = 1 is external source or PSEC4 self trigger
        // trig_mode = 0 is over software (USB), i.e. calibration logging
        if(trig_mode == 0){
            manage_cc_fifo(1);
            if(mode==USB2x) manage_cc_fifo_slaveDevice(1);

            // 'rate-only' mode, only pull data every second
            if(trig_mode == 2) usleep(3e6);

            prep_sync();
            if(mode == USB2x) software_trigger_slaveDevice((unsigned int)15);
            software_trigger((unsigned int) 15);
            make_sync();

            //acq rate limit
            usleep(LIMIT_READOUT_RATE); // somewhat arbitrary hard-coded rate limitation
            //system_card_trig_valid(false);
            //if(mode == USB2x) system_slave_card_trig_valid(false);
        }
        else{
            manage_cc_fifo(1);
            if(mode==USB2x) manage_cc_fifo_slaveDevice(1);
            usleep(100);
            for(int iii=0; iii<2; iii++){
                system_card_trig_valid(false);
                if(mode==USB2x) system_slave_card_trig_valid(false);
            }

            //send in trig 'valid' signal
            sys_wait(100);
            prep_sync();
            if(mode==USB2x) system_slave_card_trig_valid(true);
            system_card_trig_valid(true);
            make_sync();
            //}
            //acq rate limit
            usleep(acq_rate+LIMIT_READOUT_RATE);
        }
        int num_pulls = 0;
        int evts = 0;
        int digs = 0;
        while(board_trigger==last_board_trigger && t < MAX_INT_TIMER){

            read_CC(false, false, 100);
            board_trigger = CC_EVENT_COUNT_FROMCC0;
            cout << "waiting for trigger...     on system event: "
            << board_trigger << " & readout attempt " << k
            << " @time " << t << "                        \r";
            cout.flush();
            usleep(1000);
            t = timer.stop();
            num_pulls++;
            if(num_pulls > 100) break;
            //if(num_pulls > 10)  break;   //use this is board trigger does not iterate
        }

        last_board_trigger = board_trigger;
        if(mode == USB2x) system_slave_card_trig_valid(false);
        system_card_trig_valid(false);
        //set_usb_read_mode_slaveDevice(0), set_usb_read_mode(0);
        evts = read_CC(false, false, 0);
        for(int chkdig=0; chkdig<numFrontBoards; chkdig++)
        digs+=DIGITIZING_START_FLAG[chkdig];

        //if(evts == 0){
        //reset_event = true;
        //k = k-1;
        //continue;
        //}
        //condition for dumping event and trying again.
        //else if( DIGITIZING_START_FLAG[2] == 0 || evts < 6 || evts != digs){
        if( evts == 0 || evts != digs){
            print_to_terminal(k, NUM_READS,CC_EVENT_COUNT_FROMCC0, board_trigger, t);
            cout << "    --NULL--       " << endl;
            //cout.flush();
            reset_event = true;
            k = k-1;             //repeat event
            continue;
        }

        // show event number at terminal
        else{
            if((k+1) % 1 == 0 || k==0){
                print_to_terminal(k, NUM_READS, CC_EVENT_COUNT_FROMCC0, board_trigger, t);
                cout << "          \r";
                cout.flush();
            }
        }
        /**************************************/
        //Do bulk read on all front-end cards
        int numBoards = read_AC(1, all, false);
        /**************************************/
        sys_wait(10000);

        for(int jj=0; jj<2; jj++){
            //prep_sync();
            //turn off 'trig valid flag' until checking if data in buffer
            if(mode == USB2x) system_slave_card_trig_valid(false);
            system_card_trig_valid(false);
            if(mode == USB2x) set_usb_read_mode_slaveDevice(0);
            set_usb_read_mode(0);
        }
        reset_event = true; //have event, go ahead and reset for next event

        // form data for filesave
        for(int targetAC = 0; targetAC < numFrontBoards; targetAC++){
            if(BOARDS_READOUT[targetAC] && numBoards > 0){
                psec_cnt = 0;
                // assign meta data
                Meta=get_AC_info(false, targetAC, false,k, t, t, evts);

                check_event = 0;

                for(int i = 0; i < AC_CHANNELS; i++){
                    if(i>0 && i % 6 == 0) psec_cnt ++;

                    for(int j = 0; j < psecSampleCells; j++){
                        sample = adcDat[targetAC]->AC_RAW_DATA[psec_cnt][i%6*256+j];
                        if(PED_SUBTRCT) sample -= PED_DATA[targetAC][i][j];

                        adcDat[targetAC]->Data[i][j] = (unsigned int) sample;
                    }
                }
                /* wraparound_correction, if desired: */
                int baseline[psecSampleCells];
                unwrap_baseline(baseline, 2);
                for (int j = 0; j < psecSampleCells; j++){
                    asic_baseline[j] = baseline[j];
                    adcDat[targetAC]->Data[AC_CHANNELS][j] = Meta[j];
                }
            }
            //if timeout on only some, but not all boards
            else if( numBoards > 0 && BOARDS_TIMEOUT[targetAC] && DC_ACTIVE[targetAC]){
                for(int i = 0; i < AC_CHANNELS; i++){
                    if(i>0 && i % 6 == 0) psec_cnt ++;

                    for(int j = 0; j < psecSampleCells; j++){
                        sample = 0xFF;
                        adcDat[targetAC]->Data[i][j] = sample;
                    }
                }
                for(int j = 0; j < psecSampleCells; j++){
                    adcDat[targetAC]->Data[AC_CHANNELS][j] =0;
                }
            }
        }
        event_data.push_back(adcDat);

        last_k = k;
    }

    cout << endl;
    cout << "Done on readout:  " << last_k+1 << " :: @time " << t << " sec" << endl;

    cleanup();

    dump_data();

    return event_data;
}

int SuMo::log_data(const char* log_filename, vector<packet_t**> event_data, int trig_mode){
    int asic_baseline[psecSampleCells];
    float  _now_, t = 0.;
    Timer timer = Timer();
    time_t now;
    int last_k;
    char logDataFilename[300];
    // 'scalar' mode
    ofstream rate_fs;
    if(trig_mode == 2){
        char logRateFilename[300];
        sprintf(logRateFilename, "%s.rate.dat", log_filename);
        rate_fs.open(logRateFilename, ios::trunc);
    }

    // full waveform, standard mode
    time(&now);
    char timestring[100];
    strftime(timestring, 80, "%Y-%m-%d-%H-%M", localtime(&now));
    // sprintf(logDataFilename, "%s-%s.acdc.dat", timestring, log_filename);
    sprintf(logDataFilename, "%s.dat", log_filename);

    // check if file exists, inquire whether to overwrite
    // shouldn't be an issue now since file timestamped in filename ^^
    string temp;
    while(fileExists(logDataFilename)){
        cout << "file already exists, try new filename: (or enter to overwrite / ctrl-C to quit): ";
        getline(cin, temp);
        if(temp.empty()) break;
        sprintf(logDataFilename, "%s.dat", temp.c_str());
    }

    ofstream ofs;
    ofs.open(logDataFilename, ios::trunc);

    // save pedestal data to file header for reference, easy access
    // zero pad to match data format

    /* wraparound_correction, if desired: */
    int baseline[psecSampleCells];
    unwrap_baseline(baseline, 2);
    for (int j = 0; j < psecSampleCells; j++){
        asic_baseline[j] = baseline[j];
    }

    /* Create header */
    char delim = ' ';
    ofs << "Event" << delim << "Board" << delim << "Sample";
    for(int c=1; c <= AC_CHANNELS; c++){
        ofs << delim << "Ch" << c;
    }
    ofs << delim << endl;

    /* Record events */
    // For each event
    for(int event = 0; event < event_data.size(); event++){
        packet_t** events = event_data[event];
        // For each board
        for (int board = 0; board < numFrontBoards; board++){
            if (!DC_ACTIVE[board]) continue;
            // For each channels
            for (int ch = 0; ch < AC_CHANNELS; ch++){
                ofs << event << delim << board << delim << ch;
                // For each sample
                for (int i = 0; i < psecSampleCells; i++) {
                    int ped_subtracted = events[board]->Data[ch][i] - PED_DATA[board][ch][i];
                    ofs << delim << dec << ped_subtracted; // std::dec
                }
                ofs << endl;
            }

        }

        if(trig_mode == 2){
            for(int board=0; board<numFrontBoards; board++){
                // Get the event vector for the given board
                if (DC_ACTIVE[board]){
                    if(BOARDS_READOUT[board]){

                        rate_fs << event << "\t" << board << "\t" << t << "\t";

                        for(int channel=0; channel < AC_CHANNELS; channel++)  rate_fs <<  events[board]->self_trig_scalar[channel] << "\t";

                        rate_fs << endl;
                    }
                }
            }
        }
        last_k = event;
    }

    cout << endl;
    cout << "Done on readout:  " << last_k+1 << " :: @time " <<t<< " sec" << endl;

    cleanup();

    ofs.close();

    if(trig_mode == 2) rate_fs.close();

    cout << "Data saved in file: " << logDataFilename << endl << "*****" << endl;

    return 0;
}

void SuMo::print_to_terminal(int k, int NUM_READS, int cc_event, int board_trig, double t){
    cout << "Readout:  " << k+1 << " of " << NUM_READS;
    cout <<" :: system|sw evt-" << cc_event << "|" << board_trig;
    cout <<" :: evtflags-";
    for(int evt_flag =0; evt_flag< numFrontBoards; evt_flag++) cout << EVENT_FLAG[evt_flag];
    cout << " :: digflags-";
    for(int dig_flag =0; dig_flag< numFrontBoards; dig_flag++) cout << DIGITIZING_START_FLAG[dig_flag];
    cout <<" :: @time "<< t << " sec ";
    //cout.flush();
}
<commit_msg>wrong header labels<commit_after>#include <string.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <time.h>

#include "SuMo.h"
#include "Timer.h"

/* specific to file */
const int NUM_ARGS = 4;
const char* filename = "logData";
const char* description = "log data from DAQ";
using namespace std;
/********************/

/* subtract pedestal values on-line */
static bool PED_SUBTRCT = false;

static int LIMIT_READOUT_RATE  = 6000;  //usecs limit between event polling
static int NUM_SEQ_TIMEOUTS    = 100;    // number of sequential timeouts before ending run
const  float  MAX_INT_TIMER    = 800.;    // max cpu timer before ending run (secs)
/* note: usb timeout defined in include/stdUSB.h */

bool overwriteExistingFile = false;

int main(int argc, char* argv[]){
    if(argc == 2 && std::string(argv[1]) == "-h"){
        cout << endl;
        cout << filename << " :: " << description << endl;
        cout << filename << " :: takes " << NUM_ARGS-1 << " arguments" << endl;
        return 1;
    }
    else if(argc > NUM_ARGS+1 || argc < NUM_ARGS){
        cout << "error: too many number of arguments" << endl;
        return -1;
    }
    else{
        int num_checks = 5;
        int num_events = 100;
        SuMo command;
        char log_data_filename[100];

        strcpy(log_data_filename, argv[1]);
        num_events = atoi(argv[2]);
        int trig_mode = atoi(argv[3]);

        if(command.check_active_boards(num_checks))
        return 1;

        vector<packet_t**> events = command.get_data(num_events, trig_mode, 0);
        command.log_data(log_data_filename, events, trig_mode);

        return 0;
    }
}

vector<packet_t**> SuMo::get_data(unsigned int NUM_READS, int trig_mode, int acq_rate){

    int check_event;
    int asic_baseline[psecSampleCells];
    int count = 0;
    int psec_cnt = 0;
    int last_k;
    float  _now_, t = 0.;
    char logDataFilename[300];
    Timer timer = Timer();
    time_t now;
    unsigned short sample;
    int* Meta;

    vector<packet_t**> event_data;

    // read all front end cards
    bool all[numFrontBoards];
    for(int i = 0; i < numFrontBoards; i++) all[i] = true;

    load_ped();

    int number_of_frontend_cards = 0;

    for( int board = 0; board < numFrontBoards; board++){
        if(DC_ACTIVE[board]) number_of_frontend_cards++;

    }

    cout << "--------------------------------------------------------------" << endl;
    cout << "number of front-end boards detected = " << number_of_frontend_cards
    << " of " << numFrontBoards << " address slots in system" << endl;
    cout << "Trying for " << NUM_READS << " events logged to disk, in a timeout window of "
    << MAX_INT_TIMER << " seconds" << endl;
    cout << "--------------------------------------------------------------" << endl << endl;

    usleep(100000);

    /* cpu time zero */
    timer.start();

    bool reset_event = true;

    // set read mode to NULL
    set_usb_read_mode(0);
    if(mode==USB2x) set_usb_read_mode_slaveDevice(0);
    system_card_trig_valid(false);
    if(mode==USB2x) system_slave_card_trig_valid(false);

    //check system trigger number
    read_CC(false, false, 100);
    int board_trigger= CC_EVENT_COUNT_FROMCC0;
    int last_board_trigger = board_trigger;

    for(int k=0; k<NUM_READS; k++){
        set_usb_read_mode(0);
        if(mode==USB2x) set_usb_read_mode_slaveDevice(0);

        time(&now);
        t = timer.stop();
        // interrupt if past specified logging time
        if(t > MAX_INT_TIMER) {
            cout << endl << "readout timed out at " << t << "on event " << k << endl;
            break;
        }

        // trig_mode = 1 is external source or PSEC4 self trigger
        // trig_mode = 0 is over software (USB), i.e. calibration logging
        if(trig_mode == 0){
            manage_cc_fifo(1);
            if(mode==USB2x) manage_cc_fifo_slaveDevice(1);

            // 'rate-only' mode, only pull data every second
            if(trig_mode == 2) usleep(3e6);

            prep_sync();
            if(mode == USB2x) software_trigger_slaveDevice((unsigned int)15);
            software_trigger((unsigned int) 15);
            make_sync();

            //acq rate limit
            usleep(LIMIT_READOUT_RATE); // somewhat arbitrary hard-coded rate limitation
            //system_card_trig_valid(false);
            //if(mode == USB2x) system_slave_card_trig_valid(false);
        }
        else{
            manage_cc_fifo(1);
            if(mode==USB2x) manage_cc_fifo_slaveDevice(1);
            usleep(100);
            for(int iii=0; iii<2; iii++){
                system_card_trig_valid(false);
                if(mode==USB2x) system_slave_card_trig_valid(false);
            }

            //send in trig 'valid' signal
            sys_wait(100);
            prep_sync();
            if(mode==USB2x) system_slave_card_trig_valid(true);
            system_card_trig_valid(true);
            make_sync();
            //}
            //acq rate limit
            usleep(acq_rate+LIMIT_READOUT_RATE);
        }
        int num_pulls = 0;
        int evts = 0;
        int digs = 0;
        while(board_trigger==last_board_trigger && t < MAX_INT_TIMER){

            read_CC(false, false, 100);
            board_trigger = CC_EVENT_COUNT_FROMCC0;
            cout << "waiting for trigger...     on system event: "
            << board_trigger << " & readout attempt " << k
            << " @time " << t << "                        \r";
            cout.flush();
            usleep(1000);
            t = timer.stop();
            num_pulls++;
            if(num_pulls > 100) break;
            //if(num_pulls > 10)  break;   //use this is board trigger does not iterate
        }

        last_board_trigger = board_trigger;
        if(mode == USB2x) system_slave_card_trig_valid(false);
        system_card_trig_valid(false);
        //set_usb_read_mode_slaveDevice(0), set_usb_read_mode(0);
        evts = read_CC(false, false, 0);
        for(int chkdig=0; chkdig<numFrontBoards; chkdig++)
        digs+=DIGITIZING_START_FLAG[chkdig];

        //if(evts == 0){
        //reset_event = true;
        //k = k-1;
        //continue;
        //}
        //condition for dumping event and trying again.
        //else if( DIGITIZING_START_FLAG[2] == 0 || evts < 6 || evts != digs){
        if( evts == 0 || evts != digs){
            print_to_terminal(k, NUM_READS,CC_EVENT_COUNT_FROMCC0, board_trigger, t);
            cout << "    --NULL--       " << endl;
            //cout.flush();
            reset_event = true;
            k = k-1;             //repeat event
            continue;
        }

        // show event number at terminal
        else{
            if((k+1) % 1 == 0 || k==0){
                print_to_terminal(k, NUM_READS, CC_EVENT_COUNT_FROMCC0, board_trigger, t);
                cout << "          \r";
                cout.flush();
            }
        }
        /**************************************/
        //Do bulk read on all front-end cards
        int numBoards = read_AC(1, all, false);
        /**************************************/
        sys_wait(10000);

        for(int jj=0; jj<2; jj++){
            //prep_sync();
            //turn off 'trig valid flag' until checking if data in buffer
            if(mode == USB2x) system_slave_card_trig_valid(false);
            system_card_trig_valid(false);
            if(mode == USB2x) set_usb_read_mode_slaveDevice(0);
            set_usb_read_mode(0);
        }
        reset_event = true; //have event, go ahead and reset for next event

        // form data for filesave
        for(int targetAC = 0; targetAC < numFrontBoards; targetAC++){
            if(BOARDS_READOUT[targetAC] && numBoards > 0){
                psec_cnt = 0;
                // assign meta data
                Meta=get_AC_info(false, targetAC, false,k, t, t, evts);

                check_event = 0;

                for(int i = 0; i < AC_CHANNELS; i++){
                    if(i>0 && i % 6 == 0) psec_cnt ++;

                    for(int j = 0; j < psecSampleCells; j++){
                        sample = adcDat[targetAC]->AC_RAW_DATA[psec_cnt][i%6*256+j];
                        if(PED_SUBTRCT) sample -= PED_DATA[targetAC][i][j];

                        adcDat[targetAC]->Data[i][j] = (unsigned int) sample;
                    }
                }
                /* wraparound_correction, if desired: */
                int baseline[psecSampleCells];
                unwrap_baseline(baseline, 2);
                for (int j = 0; j < psecSampleCells; j++){
                    asic_baseline[j] = baseline[j];
                    adcDat[targetAC]->Data[AC_CHANNELS][j] = Meta[j];
                }
            }
            //if timeout on only some, but not all boards
            else if( numBoards > 0 && BOARDS_TIMEOUT[targetAC] && DC_ACTIVE[targetAC]){
                for(int i = 0; i < AC_CHANNELS; i++){
                    if(i>0 && i % 6 == 0) psec_cnt ++;

                    for(int j = 0; j < psecSampleCells; j++){
                        sample = 0xFF;
                        adcDat[targetAC]->Data[i][j] = sample;
                    }
                }
                for(int j = 0; j < psecSampleCells; j++){
                    adcDat[targetAC]->Data[AC_CHANNELS][j] =0;
                }
            }
        }
        event_data.push_back(adcDat);

        last_k = k;
    }

    cout << endl;
    cout << "Done on readout:  " << last_k+1 << " :: @time " << t << " sec" << endl;

    cleanup();

    dump_data();

    return event_data;
}

int SuMo::log_data(const char* log_filename, vector<packet_t**> event_data, int trig_mode){
    int asic_baseline[psecSampleCells];
    float  _now_, t = 0.;
    Timer timer = Timer();
    time_t now;
    int last_k;
    char logDataFilename[300];
    // 'scalar' mode
    ofstream rate_fs;
    if(trig_mode == 2){
        char logRateFilename[300];
        sprintf(logRateFilename, "%s.rate", log_filename);
        rate_fs.open(logRateFilename, ios::trunc);
    }

    // full waveform, standard mode
    time(&now);
    char timestring[100];
    strftime(timestring, 80, "%Y-%m-%d-%H-%M", localtime(&now));
    // sprintf(logDataFilename, "%s-%s.acdc.dat", timestring, log_filename);
    sprintf(logDataFilename, "%s.acdc", log_filename);

    // check if file exists, inquire whether to overwrite
    // shouldn't be an issue now since file timestamped in filename ^^
    string temp;
    while(fileExists(logDataFilename)){
        cout << "file already exists, try new filename: (or enter to overwrite / ctrl-C to quit): ";
        getline(cin, temp);
        if(temp.empty()) break;
        sprintf(logDataFilename, "%s.acdc", temp.c_str());
    }

    ofstream ofs;
    ofs.open(logDataFilename, ios::trunc);

    // save pedestal data to file header for reference, easy access
    // zero pad to match data format

    /* wraparound_correction, if desired: */
    int baseline[psecSampleCells];
    unwrap_baseline(baseline, 2);
    for (int j = 0; j < psecSampleCells; j++){
        asic_baseline[j] = baseline[j];
    }

    /* Create header */
    char delim = ' ';
    ofs << "Event" << delim << "Board" << delim << "Channel" << delim << "Samples" << endl;

    /* Record events */
    // For each event
    for(int event = 0; event < event_data.size(); event++){
        packet_t** events = event_data[event];
        // For each board
        for (int board = 0; board < numFrontBoards; board++){
            if (!DC_ACTIVE[board]) continue;
            // For each channels
            for (int ch = 0; ch < AC_CHANNELS; ch++){
                ofs << event << delim << board << delim << ch + 1;
                // For each sample
                for (int i = 0; i < psecSampleCells; i++) {
                    int ped_subtracted = events[board]->Data[ch][i] - PED_DATA[board][ch][i];
                    ofs << delim << dec << ped_subtracted; // std::dec
                }
                ofs << endl;
            }

        }

        if(trig_mode == 2){
            for(int board=0; board<numFrontBoards; board++){
                // Get the event vector for the given board
                if (DC_ACTIVE[board]){
                    if(BOARDS_READOUT[board]){

                        rate_fs << event << "\t" << board << "\t" << t << "\t";

                        for(int channel=0; channel < AC_CHANNELS; channel++)  rate_fs <<  events[board]->self_trig_scalar[channel] << "\t";

                        rate_fs << endl;
                    }
                }
            }
        }
        last_k = event;
    }

    cout << endl;
    cout << "Done on readout:  " << last_k+1 << " :: @time " <<t<< " sec" << endl;

    cleanup();

    ofs.close();

    if(trig_mode == 2) rate_fs.close();

    cout << "Data saved in file: " << logDataFilename << endl << "*****" << endl;

    return 0;
}

void SuMo::print_to_terminal(int k, int NUM_READS, int cc_event, int board_trig, double t){
    cout << "Readout:  " << k+1 << " of " << NUM_READS;
    cout <<" :: system|sw evt-" << cc_event << "|" << board_trig;
    cout <<" :: evtflags-";
    for(int evt_flag =0; evt_flag< numFrontBoards; evt_flag++) cout << EVENT_FLAG[evt_flag];
    cout << " :: digflags-";
    for(int dig_flag =0; dig_flag< numFrontBoards; dig_flag++) cout << DIGITIZING_START_FLAG[dig_flag];
    cout <<" :: @time "<< t << " sec ";
    //cout.flush();
}
<|endoftext|>


<commit_before>///
/// @file  P2_mpi.cpp
/// @brief 2nd partial sieve function. P2(x, y) counts the
///        numbers <= x that have exactly 2 prime factors
///        each exceeding the a-th prime.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <primesieve.hpp>
#include <aligned_vector.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <mpi_reduce_sum.hpp>
#include <imath.hpp>
#include <print.hpp>

#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <iomanip>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Count the primes inside [prime, stop]
template <typename T>
int64_t count_primes(primesieve::iterator& it, int64_t& prime, T stop)
{
  int64_t count = 0;

  for (; prime <= stop; count++)
    prime = it.next_prime();

  return count;
}

/// Calculate the thread sieving distance. The idea is to
/// gradually increase the thread_distance in order to
/// keep all CPU cores busy.
///
void balanceLoad(int64_t* thread_distance,
                 int64_t low,
                 int64_t z,
                 int threads,
                 double start_time)
{
  double seconds = get_wtime() - start_time;

  int64_t min_distance = 1 << 23;
  int64_t max_distance = ceil_div(z - low, threads);

  if (seconds < 60)
    *thread_distance *= 2;
  if (seconds > 60)
    *thread_distance /= 2;

  *thread_distance = in_between(min_distance, *thread_distance, max_distance);
}

template <typename T>
T P2_OpenMP_thread(T x,
                   int64_t y,
                   int64_t z,
                   int64_t thread_distance,
                   int64_t thread_num,
                   int64_t low,
                   int64_t& pix,
                   int64_t& pix_count)
{
  pix = 0;
  pix_count = 0;
  low += thread_distance * thread_num;
  z = min(low + thread_distance, z);
  int64_t start = (int64_t) max(x / z, y);
  int64_t stop = (int64_t) min(x / low, isqrt(x));

  primesieve::iterator rit(stop + 1, start);
  primesieve::iterator it(low - 1, z);

  int64_t next = it.next_prime();
  int64_t prime = rit.prev_prime();
  T P2_thread = 0;

  // \sum_{i = pi[start]+1}^{pi[stop]} pi(x / primes[i])
  while (prime > start &&
         x / prime < z)
  {
    pix += count_primes(it, next, x / prime);
    P2_thread += pix;
    pix_count++;
    prime = rit.prev_prime();
  }

  pix += count_primes(it, next, z - 1);

  return P2_thread;
}

/// P2(x, y) counts the numbers <= x that have exactly 2
/// prime factors each exceeding the a-th prime.
/// Memory usage: O(z^(1/2))
///
template <typename T>
T P2_mpi_master(T x, int64_t y, int threads)
{
  static_assert(prt::is_signed<T>::value,
                "P2(T x, ...): T must be signed integer type");

  if (x < 4)
    return 0;

  T a = pi_legendre(y, threads);
  T b = pi_legendre((int64_t) isqrt(x), threads);

  if (a >= b)
    return 0;

  int64_t low = 2;
  int64_t z = (int64_t)(x / max(y, 1));
  int64_t min_distance = 1 << 23;
  int64_t thread_distance = min_distance;

  int proc_id = mpi_proc_id();
  int procs = mpi_num_procs();

  int64_t distance = z - low;
  int64_t proc_distance = ceil_div(distance, procs);
  low += proc_distance * proc_id;
  z = min(low + proc_distance, z);

  T p2 = 0;
  T pix_total = pi_legendre(low - 1, threads);

  if (is_mpi_master_proc())
    p2 = (a - 2) * (a + 1) / 2 - (b - 2) * (b + 1) / 2;

  aligned_vector<int64_t> pix(threads);
  aligned_vector<int64_t> pix_counts(threads);

  // \sum_{i=a+1}^{b} pi(x / primes[i])
  while (low < z)
  {
    int64_t max_threads = ceil_div(z - low, thread_distance);
    threads = in_between(1, threads, max_threads);
    double time = get_wtime();

    #pragma omp parallel for num_threads(threads) reduction(+: p2)
    for (int i = 0; i < threads; i++)
      p2 += P2_OpenMP_thread(x, y, z, thread_distance, i, low, pix[i], pix_counts[i]);

    low += thread_distance * threads;
    balanceLoad(&thread_distance, low, z, threads, time);

    // add missing sum contributions in order
    for (int i = 0; i < threads; i++)
    {
      p2 += pix_total * pix_counts[i];
      pix_total += pix[i];
    }

    if (is_print())
    {
      double percent = get_percent(low, z);
      cout << "\rStatus: " << fixed << setprecision(get_status_precision(x))
           << percent << '%' << flush;
    }
  }

  p2 = mpi_reduce_sum(p2);

  return p2;
}

} // namespace

namespace primecount {

int64_t P2_mpi(int64_t x, int64_t y, int threads)
{
  print("");
  print("=== P2_mpi(x, y) ===");
  print("Computation of the 2nd partial sieve function");
  print(x, y, threads);

  double time = get_wtime();
  int64_t p2 = P2_mpi_master(x, y, threads);

  print("P2", p2, time);
  return p2;
}

#ifdef HAVE_INT128_T

int128_t P2_mpi(int128_t x, int64_t y, int threads)
{
  print("");
  print("=== P2_mpi(x, y) ===");
  print("Computation of the 2nd partial sieve function");
  print(x, y, threads);

  double time = get_wtime();
  int128_t p2 = P2_mpi_master(x, y, threads);

  print("P2", p2, time);
  return p2;
}

#endif

} // namespace
<commit_msg>Refactor<commit_after>///
/// @file  P2_mpi.cpp
/// @brief 2nd partial sieve function. P2(x, y) counts the
///        numbers <= x that have exactly 2 prime factors
///        each exceeding the a-th prime.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <primesieve.hpp>
#include <aligned_vector.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <mpi_reduce_sum.hpp>
#include <imath.hpp>
#include <print.hpp>

#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <iomanip>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Count the primes inside [prime, stop]
template <typename T>
int64_t count_primes(primesieve::iterator& it, int64_t& prime, T stop)
{
  int64_t count = 0;

  for (; prime <= stop; count++)
    prime = it.next_prime();

  return count;
}

/// Calculate the thread sieving distance. The idea is to
/// gradually increase the thread_distance in order to
/// keep all CPU cores busy.
///
void balanceLoad(int64_t* thread_distance,
                 int64_t low,
                 int64_t z,
                 int threads,
                 double start_time)
{
  double seconds = get_wtime() - start_time;

  int64_t min_distance = 1 << 23;
  int64_t max_distance = ceil_div(z - low, threads);

  if (seconds < 60)
    *thread_distance *= 2;
  if (seconds > 60)
    *thread_distance /= 2;

  *thread_distance = in_between(min_distance, *thread_distance, max_distance);
}

template <typename T>
T P2_thread(T x,
            int64_t y,
            int64_t z,
            int64_t low,
            int64_t thread_num,
            int64_t thread_distance,
            int64_t& pix,
            int64_t& pix_count)
{
  pix = 0;
  pix_count = 0;
  low += thread_distance * thread_num;
  z = min(low + thread_distance, z);
  int64_t start = (int64_t) max(x / z, y);
  int64_t stop = (int64_t) min(x / low, isqrt(x));

  primesieve::iterator rit(stop + 1, start);
  primesieve::iterator it(low - 1, z);

  int64_t next = it.next_prime();
  int64_t prime = rit.prev_prime();
  T p2 = 0;

  // \sum_{i = pi[start]+1}^{pi[stop]} pi(x / primes[i])
  while (prime > start &&
         x / prime < z)
  {
    pix += count_primes(it, next, x / prime);
    p2 += pix;
    pix_count++;
    prime = rit.prev_prime();
  }

  pix += count_primes(it, next, z - 1);

  return p2;
}

/// P2(x, y) counts the numbers <= x that have exactly 2
/// prime factors each exceeding the a-th prime.
/// Memory usage: O(z^(1/2))
///
template <typename T>
T P2_mpi_master(T x, int64_t y, int threads)
{
  static_assert(prt::is_signed<T>::value,
                "P2(T x, ...): T must be signed integer type");

  if (x < 4)
    return 0;

  T a = pi_legendre(y, threads);
  T b = pi_legendre((int64_t) isqrt(x), threads);

  if (a >= b)
    return 0;

  int64_t low = 2;
  int64_t z = (int64_t)(x / max(y, 1));
  int64_t min_distance = 1 << 23;
  int64_t thread_distance = min_distance;

  int proc_id = mpi_proc_id();
  int procs = mpi_num_procs();

  int64_t distance = z - low;
  int64_t proc_distance = ceil_div(distance, procs);
  low += proc_distance * proc_id;
  z = min(low + proc_distance, z);

  T p2 = 0;
  T pix_total = pi_legendre(low - 1, threads);

  if (is_mpi_master_proc())
    p2 = (a - 2) * (a + 1) / 2 - (b - 2) * (b + 1) / 2;

  aligned_vector<int64_t> pix(threads);
  aligned_vector<int64_t> pix_counts(threads);

  // \sum_{i=a+1}^{b} pi(x / primes[i])
  while (low < z)
  {
    int64_t max_threads = ceil_div(z - low, thread_distance);
    threads = in_between(1, threads, max_threads);
    double time = get_wtime();

    #pragma omp parallel for num_threads(threads) reduction(+: p2)
    for (int i = 0; i < threads; i++)
      p2 += P2_thread(x, y, z, low, i, thread_distance, pix[i], pix_counts[i]);

    low += thread_distance * threads;
    balanceLoad(&thread_distance, low, z, threads, time);

    // add missing sum contributions in order
    for (int i = 0; i < threads; i++)
    {
      p2 += pix_total * pix_counts[i];
      pix_total += pix[i];
    }

    if (is_print())
    {
      double percent = get_percent(low, z);
      cout << "\rStatus: " << fixed << setprecision(get_status_precision(x))
           << percent << '%' << flush;
    }
  }

  p2 = mpi_reduce_sum(p2);

  return p2;
}

} // namespace

namespace primecount {

int64_t P2_mpi(int64_t x, int64_t y, int threads)
{
  print("");
  print("=== P2_mpi(x, y) ===");
  print("Computation of the 2nd partial sieve function");
  print(x, y, threads);

  double time = get_wtime();
  int64_t p2 = P2_mpi_master(x, y, threads);

  print("P2", p2, time);
  return p2;
}

#ifdef HAVE_INT128_T

int128_t P2_mpi(int128_t x, int64_t y, int threads)
{
  print("");
  print("=== P2_mpi(x, y) ===");
  print("Computation of the 2nd partial sieve function");
  print(x, y, threads);

  double time = get_wtime();
  int128_t p2 = P2_mpi_master(x, y, threads);

  print("P2", p2, time);
  return p2;
}

#endif

} // namespace
<|endoftext|>


<commit_before>#include "mmc.h"

#include <cmath>
#include <iostream>
#include <mpi.h>
#include <omp.h>
#include <vector>

using namespace std;

const int maxCheck = 16000000;
const int smallestGap = 500000;

bool isPrime(int);
int primeCalc(int[]);
void recvWork(int[], int);
void sendWork(int[], int, MPI_Request*);
void receiveSendResults(MMC_Manager&);
int receiveResults(MMC_Manager& manager);
int fillGaps(int*, MMC_Manager&);
bool incrementWorkUnit(int[], int, int);
void worker_function(MMC_Machine&);
void middle_manager_function(MMC_Machine&);
void top_manager_function(MMC_Machine&);

int main(void) {
    MPI_Init(NULL, NULL);
    Layout_t layout = read_cluster_layout_from_file();
    MPI_Barrier(MPI_COMM_WORLD);

    MMC_Machine machine(layout);

    if (machine.role() == "worker") {
        worker_function(machine);
    }
    else {
        if (machine.is_top()) {
            top_manager_function(machine);
        }
        else {
            middle_manager_function(machine);
        }
    }

    MPI_Finalize();
    return 0;
}

bool isPrime(int n) {
    int sqRoot = sqrt(n);
    for (int i = 2; i <= sqRoot; ++i) {
        if (n % i == 0) {
            return false;
        }
    }
    return true;
}

int primeCalc(int workInfo[]) {
    int total = 0;
    for (int i = workInfo[0]; i <= workInfo[1]; i += 2) {
        if (isPrime(i)) {
            ++total;
        }
    }
    return total;
}

void recvWork(int workInfo[], int commRank) {
    MPI_Recv(workInfo, 2, MPI_INT, commRank, WORK_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}

void sendWork(int workInfo[], int commRank, MPI_Request* request) {
    MPI_Isend(workInfo, 2, MPI_INT, commRank, WORK_TAG, MPI_COMM_WORLD, request);
}

void receiveSendResults(MMC_Manager& manager) {
    int total = receiveResults(manager);
    MPI_Send(&total, 1, MPI_INT, manager.manager_rank(), RESULTS_TAG, MPI_COMM_WORLD);
}

int receiveResults(MMC_Manager& manager) {
    int total = 0, recvTemp;
    int start = manager.first_worker(), end = manager.last_worker();
    for (int i = start; i <= end; ++i) {
        MPI_Recv(&recvTemp, 1, MPI_INT, i, RESULTS_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        total += recvTemp;
    }
    return total;
}

int fillGaps(int* gaps, MMC_Manager& manager) {
    int numLayers = (manager.layout()).size();
    gaps[0] = 0;
    gaps[1] = smallestGap;
    for (int i = 2; i < numLayers; ++i) {
        int sizeLower = (manager.layout())[i - 1].size();
        int sizeCurr = (manager.layout())[i].size();
        int multiplier = sizeLower / sizeCurr;
        gaps[i] = gaps[i - 1] * multiplier;
    }
    return gaps[manager.level()];
}

bool incrementWorkUnit(int workInfo[], int gapToUse, int workEnd) {
    if (workInfo[1] == workEnd) {
        return true;
    }
    else {
        workInfo[0] += gapToUse;
        workInfo[1] = workInfo[0] + gapToUse - 1;
        if (workInfo[1] > workEnd) {
            workInfo[1] = workEnd;
        }
    }
    return false;
}

void worker_function(MMC_Machine& machine) {
<<<<<<< HEAD
    MMC_Worker worker(machine);
=======
    MMC_Worker worker;
    worker = machine;
>>>>>>> origin/master
    int managerRank = worker.manager_rank();
    int workInfo[2];
    int primeCount = 0;

    bool hasMoreWork = worker.get_more_work();
    while (hasMoreWork) {
        recvWork(workInfo, managerRank);
        primeCount += primeCalc(workInfo);
        hasMoreWork = worker.get_more_work();
    }
    MPI_Send(&primeCount, 1, MPI_INT, managerRank, RESULTS_TAG, MPI_COMM_WORLD);
}

void middle_manager_function(MMC_Machine& machine) {
<<<<<<< HEAD
    MMC_Manager manager(machine);
=======
    MMC_Manager manager;
    manager = machine;
>>>>>>> origin/master
    int* gaps = new int[(manager.layout()).size()];
    int gapToUse = fillGaps(gaps, manager);

    int workEnd;
    int workInfo[2];
    int managerRank = manager.manager_rank();
    MPI_Request requestDummy;
    bool hasMoreWork = manager.get_more_work();
    while (hasMoreWork) {
        recvWork(workInfo, managerRank);
        workEnd = workInfo[1];
        workInfo[1] = workInfo[0] + gapToUse - 1;

        bool isDone = false;
        while (!isDone) {
            int nextRank = manager.next_worker();

            sendWork(workInfo, nextRank, &requestDummy);

            isDone = incrementWorkUnit(workInfo, gapToUse, workEnd);
        }
        hasMoreWork = manager.get_more_work();
    }
    delete[] (gaps);
    manager.clear_worker_queue();
    receiveSendResults(manager);
}

void top_manager_function(MMC_Machine& machine) {
    double startTime = omp_get_wtime();
<<<<<<< HEAD
    MMC_Manager manager(machine);
=======
    MMC_Manager manager;
    manager = machine;
>>>>>>> origin/master
    int* gaps = new int[(manager.layout()).size()];
    int gapToUse = fillGaps(gaps, manager);

    int workStart = 3, workEnd = maxCheck;
    int workInfo[2] = {workStart, workStart + (gapToUse -1)};
    MPI_Request requestDummy;
    bool isDone = false;
    while (!isDone) {
        int nextRank = manager.next_worker();

        sendWork(workInfo, nextRank, &requestDummy);

        isDone = incrementWorkUnit(workInfo, gapToUse, workEnd);
    }
    manager.clear_worker_queue();

    int totalPrimes = receiveResults(manager);
    ++totalPrimes;

    double endTime = omp_get_wtime();
    cout << totalPrimes << " primes found in " << endTime - startTime << " seconds." << endl;
}
<commit_msg>Update primes.cpp<commit_after>#include "mmc.h"

#include <cmath>
#include <iostream>
#include <mpi.h>
#include <omp.h>
#include <vector>

using namespace std;

const int maxCheck = 16000000;
const int smallestGap = 500000;

bool isPrime(int);
int primeCalc(int[]);
void recvWork(int[], int);
void sendWork(int[], int, MPI_Request*);
void receiveSendResults(MMC_Manager&);
int receiveResults(MMC_Manager& manager);
int fillGaps(int*, MMC_Manager&);
bool incrementWorkUnit(int[], int, int);
void worker_function(MMC_Machine&);
void middle_manager_function(MMC_Machine&);
void top_manager_function(MMC_Machine&);

int main(void) {
    MPI_Init(NULL, NULL);
    Layout_t layout = read_cluster_layout_from_file();
    MPI_Barrier(MPI_COMM_WORLD);

    MMC_Machine machine(layout);

    if (machine.role() == "worker") {
        worker_function(machine);
    }
    else {
        if (machine.is_top()) {
            top_manager_function(machine);
        }
        else {
            middle_manager_function(machine);
        }
    }

    MPI_Finalize();
    return 0;
}

bool isPrime(int n) {
    int sqRoot = sqrt(n);
    for (int i = 2; i <= sqRoot; ++i) {
        if (n % i == 0) {
            return false;
        }
    }
    return true;
}

int primeCalc(int workInfo[]) {
    int total = 0;
    for (int i = workInfo[0]; i <= workInfo[1]; i += 2) {
        if (isPrime(i)) {
            ++total;
        }
    }
    return total;
}

void recvWork(int workInfo[], int commRank) {
    MPI_Recv(workInfo, 2, MPI_INT, commRank, WORK_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}

void sendWork(int workInfo[], int commRank, MPI_Request* request) {
    MPI_Isend(workInfo, 2, MPI_INT, commRank, WORK_TAG, MPI_COMM_WORLD, request);
}

void receiveSendResults(MMC_Manager& manager) {
    int total = receiveResults(manager);
    MPI_Send(&total, 1, MPI_INT, manager.manager_rank(), RESULTS_TAG, MPI_COMM_WORLD);
}

int receiveResults(MMC_Manager& manager) {
    int total = 0, recvTemp;
    int start = manager.first_worker(), end = manager.last_worker();
    for (int i = start; i <= end; ++i) {
        MPI_Recv(&recvTemp, 1, MPI_INT, i, RESULTS_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        total += recvTemp;
    }
    return total;
}

int fillGaps(int* gaps, MMC_Manager& manager) {
    int numLayers = (manager.layout()).size();
    gaps[0] = 0;
    gaps[1] = smallestGap;
    for (int i = 2; i < numLayers; ++i) {
        int sizeLower = (manager.layout())[i - 1].size();
        int sizeCurr = (manager.layout())[i].size();
        int multiplier = sizeLower / sizeCurr;
        gaps[i] = gaps[i - 1] * multiplier;
    }
    return gaps[manager.level()];
}

bool incrementWorkUnit(int workInfo[], int gapToUse, int workEnd) {
    if (workInfo[1] == workEnd) {
        return true;
    }
    else {
        workInfo[0] += gapToUse;
        workInfo[1] = workInfo[0] + gapToUse - 1;
        if (workInfo[1] > workEnd) {
            workInfo[1] = workEnd;
        }
    }
    return false;
}

void worker_function(MMC_Machine& machine) {
    MMC_Worker worker(machine);
    int managerRank = worker.manager_rank();
    int workInfo[2];
    int primeCount = 0;

    bool hasMoreWork = worker.get_more_work();
    while (hasMoreWork) {
        recvWork(workInfo, managerRank);
        primeCount += primeCalc(workInfo);
        hasMoreWork = worker.get_more_work();
    }
    MPI_Send(&primeCount, 1, MPI_INT, managerRank, RESULTS_TAG, MPI_COMM_WORLD);
}

void middle_manager_function(MMC_Machine& machine) {
    MMC_Manager manager(machine);
    int* gaps = new int[(manager.layout()).size()];
    int gapToUse = fillGaps(gaps, manager);

    int workEnd;
    int workInfo[2];
    int managerRank = manager.manager_rank();
    MPI_Request requestDummy;
    bool hasMoreWork = manager.get_more_work();
    while (hasMoreWork) {
        recvWork(workInfo, managerRank);
        workEnd = workInfo[1];
        workInfo[1] = workInfo[0] + gapToUse - 1;

        bool isDone = false;
        while (!isDone) {
            int nextRank = manager.next_worker();

            sendWork(workInfo, nextRank, &requestDummy);

            isDone = incrementWorkUnit(workInfo, gapToUse, workEnd);
        }
        hasMoreWork = manager.get_more_work();
    }
    delete[] (gaps);
    manager.clear_worker_queue();
    receiveSendResults(manager);
}

void top_manager_function(MMC_Machine& machine) {
    double startTime = omp_get_wtime();
    MMC_Manager manager(machine);
    int* gaps = new int[(manager.layout()).size()];
    int gapToUse = fillGaps(gaps, manager);

    int workStart = 3, workEnd = maxCheck;
    int workInfo[2] = {workStart, workStart + (gapToUse -1)};
    MPI_Request requestDummy;
    bool isDone = false;
    while (!isDone) {
        int nextRank = manager.next_worker();

        sendWork(workInfo, nextRank, &requestDummy);

        isDone = incrementWorkUnit(workInfo, gapToUse, workEnd);
    }
    manager.clear_worker_queue();

    int totalPrimes = receiveResults(manager);
    ++totalPrimes;

    double endTime = omp_get_wtime();
    cout << totalPrimes << " primes found in " << endTime - startTime << " seconds." << endl;
}
<|endoftext|>