<commit_before>/***************************************************************************
* Copyright (c) 2016, Johan Mabille and Sylvain Corlay                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XTEST_UTILS_HPP
#define XTEST_UTILS_HPP

#include <limits>
#include <algorithm>
#include <cmath>
#include <vector>
#include <ostream>
#include <iomanip>
#include <string>
#include <typeinfo>

namespace xsimd
{

    template <class T>
    inline std::string value_type_name()
    {
        return typeid(T).name();
    }

    class vector4f;
    class vector2d;
    class vector8f;
    class vector4d;

    template <>
    inline std::string value_type_name<vector4f>()
    {
        return "vector4f";
    }

    template <>
    inline std::string value_type_name<vector2d>()
    {
        return "vector2d";
    }

    template <>
    inline std::string value_type_name<vector8f>()
    {
        return "vector8f";
    }

    template <>
    inline std::string value_type_name<vector4d>()
    {
        return "vector4d";
    }

    namespace detail
    {

        template <class T>
        bool check_is_small(const T& value, const T& tolerance)
        {
            using std::abs;
            return abs(value) < abs(tolerance);
        }

        template <class T>
        bool safe_division(const T& lhs, const T& rhs)
        {
            if(rhs < static_cast<T>(1) && lhs > rhs * (std::numeric_limits<T>::max)())
            {
                return (std::numeric_limits<T>::max)();
            }
            if(lhs == static_cast<T>(0) ||
               rhs > static_cast<T>(1) &&
               lhs < rhs * (std::numeric_limits<T>::min)())
            {
                return static_cast<T>(0);
            }
            return lhs / rhs;
        }

        template <class T>
        bool check_is_close(const T& lhs, const T& rhs, const T& relative_precision)
        {
            using std::abs;
            T diff = abs(lhs - rhs);
            T d1 = safe_division(diff, abs(rhs));
            T d2 = safe_division(diff, abs(lhs));

            return d1 <= relative_precision && d2 <= relative_precision;
        }
    }

    template <class T>
    bool scalar_comparison(const T& lhs, const T& rhs)
    {
        using std::max;
        using std::abs;

        T relative_precision = 2048 * std::numeric_limits<T>::epsilon();
        T absolute_zero_prox = 2048 * std::numeric_limits<T>::epsilon();

        if(max(abs(lhs), abs(rhs)) < T(1e-3))
        {
            return detail::check_is_small(lhs - rhs, absolute_zero_prox);
        }
        else
        {
            return detail::check_is_close(lhs, rhs, relative_precision);
        }
    }

    template <class T, class A>
    bool vector_comparison(const std::vector<T, A>& lhs, const std::vector<T, A>& rhs)
    {
        if(lhs.size() != rhs.size())
        {
            return false;
        }
        for(auto lhs_iter = lhs.begin(), rhs_iter = rhs.begin(); lhs_iter != lhs.end(); ++lhs_iter, ++rhs_iter)
        {
            if(!scalar_comparison(*lhs_iter, *rhs_iter))
            {
                return false;
            }
        }
        return true;
    }

    template <class T, class A>
    inline std::ostream& operator<<(std::ostream& os, const std::vector<T, A>& v)
    {
        os << '[';
        for(size_t i = 0; i < v.size() - 1; ++i)
        {
            os << v[i] << ',';
        }
        os << v.back() << ']' << std::endl;
        return os;
    }

    template <class T>
    inline bool check_almost_equal(const T& res, const T& ref, std::ostream& out)
    {
        out << std::setprecision(20);
        if(scalar_comparison(res, ref))
        {
            out << "OK" << std::endl;
            return true;
        }
        else
        {
            out << "BAD" << std::endl;
            out << "Expected : " << std::endl << ref << std::endl;
            out << "Got      : " << std::endl << res << std::endl;
            return false;
        }
    }

    template <class T, class A>
    inline bool check_almost_equal(const std::vector<T, A>& res, const std::vector<T, A>& ref, std::ostream& out)
    {
        out << std::setprecision(20);
        if(vector_comparison(res, ref))
        {
            out << "OK" << std::endl;
            return true;
        }
        else
        {
            out << "BAD" << std::endl;
            out << "Expected : " << std::endl << ref;
            out << "Got      : " << std::endl << res << std::endl;
            return false;
        }
    }

}

#endif

<commit_msg>Fix windows build<commit_after>/***************************************************************************
* Copyright (c) 2016, Johan Mabille and Sylvain Corlay                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XTEST_UTILS_HPP
#define XTEST_UTILS_HPP

#include <limits>
#include <algorithm>
#include <cmath>
#include <vector>
#include <ostream>
#include <iomanip>
#include <string>
#include <typeinfo>

namespace xsimd
{

    template <class T>
    inline std::string value_type_name()
    {
        return typeid(T).name();
    }

    class vector4f;
    class vector2d;
    class vector8f;
    class vector4d;

    template <>
    inline std::string value_type_name<vector4f>()
    {
        return "vector4f";
    }

    template <>
    inline std::string value_type_name<vector2d>()
    {
        return "vector2d";
    }

    template <>
    inline std::string value_type_name<vector8f>()
    {
        return "vector8f";
    }

    template <>
    inline std::string value_type_name<vector4d>()
    {
        return "vector4d";
    }

    namespace detail
    {

        template <class T>
        bool check_is_small(const T& value, const T& tolerance)
        {
            using std::abs;
            return abs(value) < abs(tolerance);
        }

        template <class T>
        T safe_division(const T& lhs, const T& rhs)
        {
            if(rhs < static_cast<T>(1) && lhs > rhs * (std::numeric_limits<T>::max)())
            {
                return (std::numeric_limits<T>::max)();
            }
            if(lhs == static_cast<T>(0) ||
               rhs > static_cast<T>(1) &&
               lhs < rhs * (std::numeric_limits<T>::min)())
            {
                return static_cast<T>(0);
            }
            return lhs / rhs;
        }

        template <class T>
        bool check_is_close(const T& lhs, const T& rhs, const T& relative_precision)
        {
            using std::abs;
            T diff = abs(lhs - rhs);
            T d1 = safe_division(diff, abs(rhs));
            T d2 = safe_division(diff, abs(lhs));

            return d1 <= relative_precision && d2 <= relative_precision;
        }
    }

    template <class T>
    bool scalar_comparison(const T& lhs, const T& rhs)
    {
        using std::max;
        using std::abs;

        T relative_precision = 2048 * std::numeric_limits<T>::epsilon();
        T absolute_zero_prox = 2048 * std::numeric_limits<T>::epsilon();

        if(max(abs(lhs), abs(rhs)) < T(1e-3))
        {
            return detail::check_is_small(lhs - rhs, absolute_zero_prox);
        }
        else
        {
            return detail::check_is_close(lhs, rhs, relative_precision);
        }
    }

    template <class T, class A>
    bool vector_comparison(const std::vector<T, A>& lhs, const std::vector<T, A>& rhs)
    {
        if(lhs.size() != rhs.size())
        {
            return false;
        }
        for(auto lhs_iter = lhs.begin(), rhs_iter = rhs.begin(); lhs_iter != lhs.end(); ++lhs_iter, ++rhs_iter)
        {
            if(!scalar_comparison(*lhs_iter, *rhs_iter))
            {
                return false;
            }
        }
        return true;
    }

    template <class T, class A>
    inline std::ostream& operator<<(std::ostream& os, const std::vector<T, A>& v)
    {
        os << '[';
        for(size_t i = 0; i < v.size() - 1; ++i)
        {
            os << v[i] << ',';
        }
        os << v.back() << ']' << std::endl;
        return os;
    }

    template <class T>
    inline bool check_almost_equal(const T& res, const T& ref, std::ostream& out)
    {
        out << std::setprecision(20);
        if(scalar_comparison(res, ref))
        {
            out << "OK" << std::endl;
            return true;
        }
        else
        {
            out << "BAD" << std::endl;
            out << "Expected : " << std::endl << ref << std::endl;
            out << "Got      : " << std::endl << res << std::endl;
            return false;
        }
    }

    template <class T, class A>
    inline bool check_almost_equal(const std::vector<T, A>& res, const std::vector<T, A>& ref, std::ostream& out)
    {
        out << std::setprecision(20);
        if(vector_comparison(res, ref))
        {
            out << "OK" << std::endl;
            return true;
        }
        else
        {
            out << "BAD" << std::endl;
            out << "Expected : " << std::endl << ref;
            out << "Got      : " << std::endl << res << std::endl;
            return false;
        }
    }

}

#endif

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 RISC-V Foundation
 * Copyright (c) 2016 The University of Virginia
 * Copyright (c) 2018 TU Dresden
 * Copyright (c) 2020 Barkhausen Institut
 * 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.
 */

#include "arch/riscv/faults.hh"

#include "arch/riscv/fs_workload.hh"
#include "arch/riscv/isa.hh"
#include "arch/riscv/registers.hh"
#include "arch/riscv/utility.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "debug/Fault.hh"
#include "sim/debug.hh"
#include "sim/full_system.hh"

namespace RiscvISA
{

void
RiscvFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    panic("Fault %s encountered at pc 0x%016llx.", name(), tc->pcState().pc());
}

void
RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    PCState pcState = tc->pcState();

    DPRINTFS(Fault, tc->getCpuPtr(), "Fault (%s) at PC: %s\n",
             name(), pcState);

    if (FullSystem) {
        PrivilegeMode pp = (PrivilegeMode)tc->readMiscReg(MISCREG_PRV);
        PrivilegeMode prv = PRV_M;
        STATUS status = tc->readMiscReg(MISCREG_STATUS);

        // Set fault handler privilege mode
        if (isInterrupt()) {
            if (pp != PRV_M &&
                bits(tc->readMiscReg(MISCREG_MIDELEG), _code) != 0) {
                prv = PRV_S;
            }
            if (pp == PRV_U &&
                bits(tc->readMiscReg(MISCREG_SIDELEG), _code) != 0) {
                prv = PRV_U;
            }
        } else {
            if (pp != PRV_M &&
                bits(tc->readMiscReg(MISCREG_MEDELEG), _code) != 0) {
                prv = PRV_S;
            }
            if (pp == PRV_U &&
                bits(tc->readMiscReg(MISCREG_SEDELEG), _code) != 0) {
                prv = PRV_U;
            }
        }

        // Set fault registers and status
        MiscRegIndex cause, epc, tvec, tval;
        switch (prv) {
          case PRV_U:
            cause = MISCREG_UCAUSE;
            epc = MISCREG_UEPC;
            tvec = MISCREG_UTVEC;
            tval = MISCREG_UTVAL;

            status.upie = status.uie;
            status.uie = 0;
            break;
          case PRV_S:
            cause = MISCREG_SCAUSE;
            epc = MISCREG_SEPC;
            tvec = MISCREG_STVEC;
            tval = MISCREG_STVAL;

            status.spp = pp;
            status.spie = status.sie;
            status.sie = 0;
            break;
          case PRV_M:
            cause = MISCREG_MCAUSE;
            epc = MISCREG_MEPC;
            tvec = MISCREG_MTVEC;
            tval = MISCREG_MTVAL;

            status.mpp = pp;
            status.mpie = status.sie;
            status.mie = 0;
            break;
          default:
            panic("Unknown privilege mode %d.", prv);
            break;
        }

        // Set fault cause, privilege, and return PC
        tc->setMiscReg(cause,
                       (isInterrupt() << (sizeof(uint64_t) * 4 - 1)) | _code);
        tc->setMiscReg(epc, tc->instAddr());
        tc->setMiscReg(tval, trap_value());
        tc->setMiscReg(MISCREG_PRV, prv);
        tc->setMiscReg(MISCREG_STATUS, status);

        // Set PC to fault handler address
        Addr addr = tc->readMiscReg(tvec) >> 2;
        if (isInterrupt() && bits(tc->readMiscReg(tvec), 1, 0) == 1)
            addr += 4 * _code;
        pcState.set(addr);
    } else {
        invokeSE(tc, inst);
        advancePC(pcState, inst);
    }
    tc->pcState(pcState);
}

void Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    tc->setMiscReg(MISCREG_PRV, PRV_M);
    STATUS status = tc->readMiscReg(MISCREG_STATUS);
    status.mie = 0;
    status.mprv = 0;
    tc->setMiscReg(MISCREG_STATUS, status);
    tc->setMiscReg(MISCREG_MCAUSE, 0);

    // Advance the PC to the implementation-defined reset vector
    auto workload = dynamic_cast<FsWorkload *>(tc->getSystemPtr()->workload);
    PCState pc = workload->resetVect();
    tc->pcState(pc);
}

void
UnknownInstFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    panic("Unknown instruction 0x%08x at pc 0x%016llx", inst->machInst,
        tc->pcState().pc());
}

void
IllegalInstFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    panic("Illegal instruction 0x%08x at pc 0x%016llx: %s", inst->machInst,
        tc->pcState().pc(), reason.c_str());
}

void
UnimplementedFault::invokeSE(ThreadContext *tc,
        const StaticInstPtr &inst)
{
    panic("Unimplemented instruction %s at pc 0x%016llx", instName,
        tc->pcState().pc());
}

void
IllegalFrmFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    panic("Illegal floating-point rounding mode 0x%x at pc 0x%016llx.",
            frm, tc->pcState().pc());
}

void
BreakpointFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    schedRelBreak(0);
}

void
SyscallFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    Fault *fault = NoFault;
    tc->syscall(fault);
}

} // namespace RiscvISA
<commit_msg>arch-riscv: fixed read of {M,S,U}TVEC.<commit_after>/*
 * Copyright (c) 2016 RISC-V Foundation
 * Copyright (c) 2016 The University of Virginia
 * Copyright (c) 2018 TU Dresden
 * Copyright (c) 2020 Barkhausen Institut
 * 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.
 */

#include "arch/riscv/faults.hh"

#include "arch/riscv/fs_workload.hh"
#include "arch/riscv/isa.hh"
#include "arch/riscv/registers.hh"
#include "arch/riscv/utility.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "debug/Fault.hh"
#include "sim/debug.hh"
#include "sim/full_system.hh"

namespace RiscvISA
{

void
RiscvFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    panic("Fault %s encountered at pc 0x%016llx.", name(), tc->pcState().pc());
}

void
RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    PCState pcState = tc->pcState();

    DPRINTFS(Fault, tc->getCpuPtr(), "Fault (%s) at PC: %s\n",
             name(), pcState);

    if (FullSystem) {
        PrivilegeMode pp = (PrivilegeMode)tc->readMiscReg(MISCREG_PRV);
        PrivilegeMode prv = PRV_M;
        STATUS status = tc->readMiscReg(MISCREG_STATUS);

        // Set fault handler privilege mode
        if (isInterrupt()) {
            if (pp != PRV_M &&
                bits(tc->readMiscReg(MISCREG_MIDELEG), _code) != 0) {
                prv = PRV_S;
            }
            if (pp == PRV_U &&
                bits(tc->readMiscReg(MISCREG_SIDELEG), _code) != 0) {
                prv = PRV_U;
            }
        } else {
            if (pp != PRV_M &&
                bits(tc->readMiscReg(MISCREG_MEDELEG), _code) != 0) {
                prv = PRV_S;
            }
            if (pp == PRV_U &&
                bits(tc->readMiscReg(MISCREG_SEDELEG), _code) != 0) {
                prv = PRV_U;
            }
        }

        // Set fault registers and status
        MiscRegIndex cause, epc, tvec, tval;
        switch (prv) {
          case PRV_U:
            cause = MISCREG_UCAUSE;
            epc = MISCREG_UEPC;
            tvec = MISCREG_UTVEC;
            tval = MISCREG_UTVAL;

            status.upie = status.uie;
            status.uie = 0;
            break;
          case PRV_S:
            cause = MISCREG_SCAUSE;
            epc = MISCREG_SEPC;
            tvec = MISCREG_STVEC;
            tval = MISCREG_STVAL;

            status.spp = pp;
            status.spie = status.sie;
            status.sie = 0;
            break;
          case PRV_M:
            cause = MISCREG_MCAUSE;
            epc = MISCREG_MEPC;
            tvec = MISCREG_MTVEC;
            tval = MISCREG_MTVAL;

            status.mpp = pp;
            status.mpie = status.sie;
            status.mie = 0;
            break;
          default:
            panic("Unknown privilege mode %d.", prv);
            break;
        }

        // Set fault cause, privilege, and return PC
        tc->setMiscReg(cause,
                       (isInterrupt() << (sizeof(uint64_t) * 4 - 1)) | _code);
        tc->setMiscReg(epc, tc->instAddr());
        tc->setMiscReg(tval, trap_value());
        tc->setMiscReg(MISCREG_PRV, prv);
        tc->setMiscReg(MISCREG_STATUS, status);

        // Set PC to fault handler address
        Addr addr = mbits(tc->readMiscReg(tvec), 63, 2);
        if (isInterrupt() && bits(tc->readMiscReg(tvec), 1, 0) == 1)
            addr += 4 * _code;
        pcState.set(addr);
    } else {
        invokeSE(tc, inst);
        advancePC(pcState, inst);
    }
    tc->pcState(pcState);
}

void Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    tc->setMiscReg(MISCREG_PRV, PRV_M);
    STATUS status = tc->readMiscReg(MISCREG_STATUS);
    status.mie = 0;
    status.mprv = 0;
    tc->setMiscReg(MISCREG_STATUS, status);
    tc->setMiscReg(MISCREG_MCAUSE, 0);

    // Advance the PC to the implementation-defined reset vector
    auto workload = dynamic_cast<FsWorkload *>(tc->getSystemPtr()->workload);
    PCState pc = workload->resetVect();
    tc->pcState(pc);
}

void
UnknownInstFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    panic("Unknown instruction 0x%08x at pc 0x%016llx", inst->machInst,
        tc->pcState().pc());
}

void
IllegalInstFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    panic("Illegal instruction 0x%08x at pc 0x%016llx: %s", inst->machInst,
        tc->pcState().pc(), reason.c_str());
}

void
UnimplementedFault::invokeSE(ThreadContext *tc,
        const StaticInstPtr &inst)
{
    panic("Unimplemented instruction %s at pc 0x%016llx", instName,
        tc->pcState().pc());
}

void
IllegalFrmFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    panic("Illegal floating-point rounding mode 0x%x at pc 0x%016llx.",
            frm, tc->pcState().pc());
}

void
BreakpointFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    schedRelBreak(0);
}

void
SyscallFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst)
{
    Fault *fault = NoFault;
    tc->syscall(fault);
}

} // namespace RiscvISA
<|endoftext|>


<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: Ali Saidi
 */

#ifndef __ARCH_SPARC_SYSTEM_HH__
#define __ARCH_SPARC_SYSTEM_HH__

#include <string>
#include <vector>

#include "base/loader/symtab.hh"
#include "cpu/pc_event.hh"
#include "kern/system_events.hh"
#include "sim/sim_object.hh"
#include "sim/system.hh"

class SparcSystem : public System
{
  public:
    struct Params : public System::Params
    {
        PhysicalMemory *rom;
        PhysicalMemory *nvram;
        PhysicalMemory *hypervisor_desc;
        PhysicalMemory *partition_desc;
        Addr reset_addr;
        Addr hypervisor_addr;
        Addr openboot_addr;
        Addr nvram_addr;
        Addr hypervisor_desc_addr;
        Addr partition_desc_addr;
        std::string reset_bin;
        std::string hypervisor_bin;
        std::string openboot_bin;
        std::string nvram_bin;
        std::string hypervisor_desc_bin;
        std::string partition_desc_bin;
        std::string boot_osflags;
    };

    SparcSystem(Params *p);

    ~SparcSystem();

    virtual bool breakpoint();

/**
 * Serialization stuff
 */
  public:
    virtual void serialize(std::ostream &os);
    virtual void unserialize(Checkpoint *cp, const std::string &section);

    /** reset binary symbol table */
    SymbolTable *resetSymtab;

    /** hypervison binary symbol table */
    SymbolTable *hypervisorSymtab;

    /** openboot symbol table */
    SymbolTable *openbootSymtab;

    /** nvram symbol table? */
    SymbolTable *nvramSymtab;

    /** hypervisor desc symbol table? */
    SymbolTable *hypervisorDescSymtab;

    /** partition desc symbol table? */
    SymbolTable *partitionDescSymtab;

    /** Object pointer for the reset binary */
    ObjectFile *reset;

    /** Object pointer for the hypervisor code */
    ObjectFile *hypervisor;

    /** Object pointer for the openboot code */
    ObjectFile *openboot;

    /** Object pointer for the nvram image */
    ObjectFile *nvram;

    /** Object pointer for the hypervisor description image */
    ObjectFile *hypervisor_desc;

    /** Object pointer for the partition description image */
    ObjectFile *partition_desc;

    /** System Tick for syncronized tick across all cpus. */
    Tick sysTick;

    /** functional port to ROM */
    FunctionalPort funcRomPort;

    /** functional port to nvram */
    FunctionalPort funcNvramPort;

    /** functional port to hypervisor description */
    FunctionalPort funcHypDescPort;

    /** functional port to partition description */
    FunctionalPort funcPartDescPort;

  protected:
    const Params *params() const { return (const Params *)_params; }

    /** Add a function-based event to reset binary. */
    template <class T>
    T *SparcSystem::addResetFuncEvent(const char *lbl)
    {
        return addFuncEvent<T>(resetSymtab, lbl);
    }

    /** Add a function-based event to the hypervisor. */
    template <class T>
    T *SparcSystem::addHypervisorFuncEvent(const char *lbl)
    {
        return addFuncEvent<T>(hypervisorSymtab, lbl);
    }

    /** Add a function-based event to the openboot. */
    template <class T>
    T *SparcSystem::addOpenbootFuncEvent(const char *lbl)
    {
        return addFuncEvent<T>(openbootSymtab, lbl);
    }

    virtual Addr fixFuncEventAddr(Addr addr)
    {
        //XXX This may eventually have to do something useful.
        return addr;
    }
};

#endif

<commit_msg>Compilation fixes.<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: Ali Saidi
 */

#ifndef __ARCH_SPARC_SYSTEM_HH__
#define __ARCH_SPARC_SYSTEM_HH__

#include <string>
#include <vector>

#include "base/loader/symtab.hh"
#include "cpu/pc_event.hh"
#include "kern/system_events.hh"
#include "sim/sim_object.hh"
#include "sim/system.hh"

class SparcSystem : public System
{
  public:
    struct Params : public System::Params
    {
        PhysicalMemory *rom;
        PhysicalMemory *nvram;
        PhysicalMemory *hypervisor_desc;
        PhysicalMemory *partition_desc;
        Addr reset_addr;
        Addr hypervisor_addr;
        Addr openboot_addr;
        Addr nvram_addr;
        Addr hypervisor_desc_addr;
        Addr partition_desc_addr;
        std::string reset_bin;
        std::string hypervisor_bin;
        std::string openboot_bin;
        std::string nvram_bin;
        std::string hypervisor_desc_bin;
        std::string partition_desc_bin;
        std::string boot_osflags;
    };

    SparcSystem(Params *p);

    ~SparcSystem();

    virtual bool breakpoint();

/**
 * Serialization stuff
 */
  public:
    virtual void serialize(std::ostream &os);
    virtual void unserialize(Checkpoint *cp, const std::string &section);

    /** reset binary symbol table */
    SymbolTable *resetSymtab;

    /** hypervison binary symbol table */
    SymbolTable *hypervisorSymtab;

    /** openboot symbol table */
    SymbolTable *openbootSymtab;

    /** nvram symbol table? */
    SymbolTable *nvramSymtab;

    /** hypervisor desc symbol table? */
    SymbolTable *hypervisorDescSymtab;

    /** partition desc symbol table? */
    SymbolTable *partitionDescSymtab;

    /** Object pointer for the reset binary */
    ObjectFile *reset;

    /** Object pointer for the hypervisor code */
    ObjectFile *hypervisor;

    /** Object pointer for the openboot code */
    ObjectFile *openboot;

    /** Object pointer for the nvram image */
    ObjectFile *nvram;

    /** Object pointer for the hypervisor description image */
    ObjectFile *hypervisor_desc;

    /** Object pointer for the partition description image */
    ObjectFile *partition_desc;

    /** System Tick for syncronized tick across all cpus. */
    Tick sysTick;

    /** functional port to ROM */
    FunctionalPort funcRomPort;

    /** functional port to nvram */
    FunctionalPort funcNvramPort;

    /** functional port to hypervisor description */
    FunctionalPort funcHypDescPort;

    /** functional port to partition description */
    FunctionalPort funcPartDescPort;

  protected:
    const Params *params() const { return (const Params *)_params; }

    /** Add a function-based event to reset binary. */
    template <class T>
    T *addResetFuncEvent(const char *lbl)
    {
        return addFuncEvent<T>(resetSymtab, lbl);
    }

    /** Add a function-based event to the hypervisor. */
    template <class T>
    T *addHypervisorFuncEvent(const char *lbl)
    {
        return addFuncEvent<T>(hypervisorSymtab, lbl);
    }

    /** Add a function-based event to the openboot. */
    template <class T>
    T *addOpenbootFuncEvent(const char *lbl)
    {
        return addFuncEvent<T>(openbootSymtab, lbl);
    }

    virtual Addr fixFuncEventAddr(Addr addr)
    {
        //XXX This may eventually have to do something useful.
        return addr;
    }
};

#endif

<|endoftext|>


<commit_before>#include <iostream>

#include <cuda.h>
#include <cuda_runtime_api.h>

#include "backends/backends.h"

using namespace blitz;

// N C H W
Shape input_shape(4);
// K C R S
Shape filter_shape(4);
// N K P Q
Shape output_shape(4);
// cpu workspace
Shape workspace_shape_cpu(1);
// gpu workspace
Shape workspace_shape_gpu(1);

void set_input_shape_nchw(size_t N, size_t C, size_t H, size_t W) {
  input_shape[0] = N;
  input_shape[1] = C;
  input_shape[2] = H;
  input_shape[3] = W;
}

void set_filter_shape_kcrs(size_t K, size_t C, size_t R, size_t S) {
  filter_shape[0] = K;
  filter_shape[1] = C;
  filter_shape[2] = R;
  filter_shape[3] = S;
}

void set_output_shape_nkpq(size_t N, size_t K, size_t P, size_t Q) {
  output_shape[0] = N;
  output_shape[1] = K;
  output_shape[2] = P;
  output_shape[3] = Q;
}

void compare_cpu_gpu(size_t size, float* output_cpu, float* output_gpu) {
  for (size_t i = 0; i < size; ++i) {
    if (output_cpu[i] > output_gpu[i] + 1e-2 ||
      output_cpu[i] < output_gpu[i] - 1e-2) {
      std::cout << "Index: " << i << ", CPU: " << output_cpu[i] <<
        ", GPU: " << output_gpu[i] << std::endl;
    }
  }
}

// conmpare gpu result to cpu result
void convolution_forward(
  size_t pad_h, size_t pad_w,
  size_t str_h, size_t str_w) {
  // set up cpu
  CPUTensor<float> input_cpu(input_shape);
  CPUTensor<float> filter_cpu(filter_shape);
  CPUTensor<float> output_cpu(output_shape);
  CPUTensor<float> workspace_cpu(workspace_shape_cpu);
  // set up gpu
  GPUTensor<float> input_gpu(input_shape);
  GPUTensor<float> filter_gpu(filter_shape);
  GPUTensor<float> output_gpu(output_shape);
  GPUTensor<float> workspace_gpu(workspace_shape_gpu);
  // set up copy
  CPUTensor<float> output_copy(output_shape);
  // init values
  Backend<CPUTensor, float>::UniformDistributionFunc(0.0, 1.0, &input_cpu);
  Backend<CPUTensor, float>::UniformDistributionFunc(0.0, 1.0, &filter_cpu);
  cudaMemcpy(input_gpu.data(), input_cpu.data(),
    input_cpu.size() * sizeof(float), cudaMemcpyHostToDevice);
  cudaMemcpy(filter_gpu.data(), filter_cpu.data(),
    filter_cpu.size() * sizeof(float), cudaMemcpyHostToDevice);
  // cpu convolution
  Backend<CPUTensor, float>::Convolution2DForwardFunc(
    &input_cpu, &filter_cpu,
    pad_h, pad_w,
    str_h, str_w,
    &workspace_cpu,
    &output_cpu);
  // gpu convolution
  Backend<GPUTensor, float>::Convolution2DForwardFunc(
    &input_gpu, &filter_gpu,
    pad_h, pad_w,
    str_h, str_w,
    &workspace_gpu,
    &output_gpu,
    "asm_implicit");
  // copy from gpu to cpu
  cudaMemcpy(output_copy.data(), output_gpu.data(),
    output_gpu.size() * sizeof(float), cudaMemcpyDeviceToHost);
  compare_cpu_gpu(output_cpu.size(), output_cpu.data(), output_copy.data());
}

void convolution_backward(
  size_t pad_h, size_t pad_w,
  size_t str_h, size_t str_w) {
}

void convolution_update(
  size_t pad_h, size_t pad_w,
  size_t str_h, size_t str_w) {
}

int main(int argc, char** argv) {
  const size_t NUM_ARGS = 14;
  // phase N C H W R S K P Q pad_h pad_w str_h str_w
  if (argc != NUM_ARGS + 1) {
    std::cerr << "Not enough args!" << std::endl;
    exit(1);
  }
  // get args
  const std::string phase = std::string(argv[1]);
  const size_t N = atoi(argv[2]);
  const size_t C = atoi(argv[3]);
  const size_t H = atoi(argv[4]);
  const size_t W = atoi(argv[5]);
  const size_t R = atoi(argv[6]);
  const size_t S = atoi(argv[7]);
  const size_t K = atoi(argv[8]);
  const size_t P = atoi(argv[9]);
  const size_t Q = atoi(argv[10]);
  const size_t pad_h = atoi(argv[11]);
  const size_t pad_w = atoi(argv[12]);
  const size_t str_h = atoi(argv[13]);
  const size_t str_w = atoi(argv[14]);
  // set shapes
  set_input_shape_nchw(N, C, H, W);
  set_filter_shape_kcrs(K, C, R, S);
  set_output_shape_nkpq(N, K, P, Q);
  // set workspace shape
  workspace_shape_gpu[0] =
    input_shape.size() + output_shape.size() + filter_shape.size();
  workspace_shape_cpu[0] = C * H * W * P * Q;
  // run convolution
  if (phase == "forward") {
    convolution_forward(pad_h, pad_w, str_h, str_w);
  } else if (phase == "backward") {
    convolution_backward(pad_h, pad_w, str_h, str_w);
  } else if (phase == "update") {
    convolution_update(pad_h, pad_w, str_h, str_w);
  }
  return 0;
}
<commit_msg>remove previous file<commit_after><|endoftext|>


<commit_before>#include "src/archive/Archiver.hpp"
#include "quazipfile.h"
#include "quazipfileinfo.h"
#include <QDir>
#include <QFile>
#include <QStringBuilder>

#include <QDebug>

qint64 copyData(QIODevice& inFile, QIODevice& outFile) {
  char buffer[4096];
  const qint64 readSize = inFile.read(buffer, 4096);

  if (readSize <= 0) {
    return -1;
  }

  const qint64 writeSize = outFile.write(buffer, readSize);

  if (writeSize != readSize) {
    return -1;
  }

  return writeSize;
}

bool removeFiles(const QStringList& fileList) {
  bool ret = true;

  foreach (const auto& filePath, fileList) {
    ret = ret && QFile::remove(filePath);
  }

  return ret;
}

Kryvos::Archiver::Archiver(QObject* parent)
  : QObject{parent} {
}

bool Kryvos::Archiver::compressFiles(const QString& fileCompressed,
                                     const QStringList& encryptedFiles,
                                     const QStringList& originalFiles) {
  QuaZip zip{fileCompressed};

  QDir{}.mkpath(QFileInfo(fileCompressed).absolutePath());

  const bool createdZip = zip.open(QuaZip::mdCreate);

  if (!createdZip) {
    QFile::remove(fileCompressed);
    return false;
  }

  qint64 compressedSize = 0;

  for (auto i = 0; i < encryptedFiles.length(); ++i) {
    const QString file = encryptedFiles.at(i);
    const QString originalFile = originalFiles.at(i);

    QFileInfo info{file};

    compressedSize = compressFile(&zip, file, info.fileName(), originalFile);

    if (!info.exists() || (compressedSize <= 0)) {
      QFile::remove(fileCompressed);
      return false;
    }
  }

  zip.close();

  if (zip.getZipError() != 0) {
    QFile::remove(fileCompressed);
    return false;
  }

  return true;
}

QStringList Kryvos::Archiver::extractDir(const QString& fileCompressed,
                                         const QString& dir) {
  QuaZip zip{fileCompressed};

  return extractDir(zip, dir);
}

qint64 Kryvos::Archiver::copyFileData(QIODevice& inFile,
                                      QIODevice& outFile,
                                      const QString& filePath,
                                      const qint64 fileSize,
                                      const QString& task) {
  qint64 processedSize = 0;

  while (!inFile.atEnd()) {
    const qint64 writeSize = copyData(inFile, outFile);

    if (-1 == writeSize) {
      processedSize = -1;
      break;
    }

    processedSize += writeSize;

    const auto nextFraction = static_cast<double>(processedSize) /
                              static_cast<double>(fileSize);
    const auto nextPercent = static_cast<int>(nextFraction * 100);

    if (!task.isEmpty()) {
      if (nextPercent > 99) {
        if (tr("Compress") == task) {
          emit progress(filePath, tr("Compressed"), nextPercent);
        }
        else if (tr("Extract") == task) {
          emit progress(filePath, tr("Extracted"), nextPercent);
        }
      }
      else {
        emit progress(filePath, task, nextPercent);
      }
    }
  }

  return fileSize;
}

qint64 Kryvos::Archiver::compressFile(QuaZip* zip,
                                      const QString& fileName,
                                      const QString& fileDestination,
                                      const QString& originalFilePath) {
  if (!zip) {
    return -1;
  }

  if (zip->getMode() != QuaZip::mdCreate &&
      zip->getMode() != QuaZip::mdAppend &&
      zip->getMode() != QuaZip::mdAdd) {
    return -1;
  }

  QFile inFile{fileName};

  const bool inFileOpen = inFile.open(QIODevice::ReadOnly);

  if (!inFileOpen) {
    return -1;
  }

  QuaZipFile outFile{zip};
  const bool outFileOpen =
    outFile.open(QIODevice::WriteOnly,
                 QuaZipNewInfo{fileDestination, inFile.fileName()});

  if (!outFileOpen) {
    return -1;
  }

  const QString task = tr("Compress");
  const qint64 copiedDataSize = copyFileData(inFile, outFile, originalFilePath,
                                             inFile.size(), task);

  if (copiedDataSize <= 0 || (outFile.getZipError() != UNZ_OK)) {
    return -1;
  }

  outFile.close();

  if (outFile.getZipError() != UNZ_OK) {
    return -1;
  }

  inFile.close();

  return copiedDataSize;
}

QStringList Kryvos::Archiver::extractDir(QuaZip& zip, const QString& dir) {
  if (!zip.open(QuaZip::mdUnzip)) {
    return QStringList{};
  }

  QDir directory{dir};

  if (!zip.goToFirstFile()) {
    return QStringList{};
  }

  QStringList extracted{};
  qint64 extractedSize = 0;

  do {
    const QString& name = zip.getCurrentFileName();
    const QString& absFilePath = directory.absoluteFilePath(name);

    extractedSize = extractFile(&zip, QString{}, absFilePath);

    if (extractedSize <= 0) {
      removeFiles(extracted);
      return QStringList{};
    }

    extracted.append(absFilePath);
  } while (zip.goToNextFile());

  zip.close();

  if (zip.getZipError() != 0) {
    removeFiles(extracted);
    return QStringList{};
  }

  return extracted;
}

qint64 Kryvos::Archiver::extractFile(QuaZip* zip,
                                     const QString& fileName,
                                     const QString& fileDest) {
  if (!zip) {
    return -1;
  }

  if (zip->getMode() != QuaZip::mdUnzip) {
    return -1;
  }

  if (!fileName.isEmpty()) {
    zip->setCurrentFile(fileName);
  }

  QuaZipFile inFile{zip};

  const bool inFileOpen = inFile.open(QIODevice::ReadOnly);

  if (!inFileOpen || inFile.getZipError() != UNZ_OK) {
    return -1;
  }

  QDir curDir{};

  if (fileDest.endsWith('/')) {
    const auto destPath = curDir.mkpath(fileDest);

    if (!destPath) {
      return -1;
    }
  } else {
    const auto destPath = curDir.mkpath(QFileInfo{fileDest}.absolutePath());

    if (!destPath) {
      return -1;
    }
  }

  QuaZipFileInfo64 info;
  if (!zip->getCurrentFileInfo(&info)) {
    return -1;
  }

  const auto srcPerm = info.getPermissions();

  if (fileDest.endsWith('/') && QFileInfo(fileDest).isDir()) {
    if (srcPerm != 0) {
      QFile{fileDest}.setPermissions(srcPerm);
    }

    return -1;
  }

  QFile outFile{};
  outFile.setFileName(fileDest);

  const bool outFileOpen = outFile.open(QIODevice::WriteOnly);

  if (!outFileOpen) {
    return -1;
  }

  const qint64 uncompressedSize = info.uncompressedSize;

  const QString task = tr("Extract");
  const qint64 copiedDataSize = copyFileData(inFile, outFile, fileDest,
                                             uncompressedSize, task);

  if ((copiedDataSize <= 0) || inFile.getZipError() != UNZ_OK) {
    outFile.close();
    removeFiles(QStringList{fileDest});
    return -1;
  }

  outFile.close();
  inFile.close();

  if (inFile.getZipError() != UNZ_OK) {
    removeFiles(QStringList{fileDest});
    return -1;
  }

  if (srcPerm != 0) {
    outFile.setPermissions(srcPerm);
  }

  return copiedDataSize;
}
<commit_msg>Update archiving messages<commit_after>#include "src/archive/Archiver.hpp"
#include "quazipfile.h"
#include "quazipfileinfo.h"
#include <QDir>
#include <QFile>
#include <QStringBuilder>

#include <QDebug>

qint64 copyData(QIODevice& inFile, QIODevice& outFile) {
  char buffer[4096];
  const qint64 readSize = inFile.read(buffer, 4096);

  if (readSize <= 0) {
    return -1;
  }

  const qint64 writeSize = outFile.write(buffer, readSize);

  if (writeSize != readSize) {
    return -1;
  }

  return writeSize;
}

bool removeFiles(const QStringList& fileList) {
  bool ret = true;

  foreach (const auto& filePath, fileList) {
    ret = ret && QFile::remove(filePath);
  }

  return ret;
}

Kryvos::Archiver::Archiver(QObject* parent)
  : QObject{parent} {
}

bool Kryvos::Archiver::compressFiles(const QString& fileCompressed,
                                     const QStringList& encryptedFiles,
                                     const QStringList& originalFiles) {
  QuaZip zip{fileCompressed};

  QDir{}.mkpath(QFileInfo(fileCompressed).absolutePath());

  const bool createdZip = zip.open(QuaZip::mdCreate);

  if (!createdZip) {
    QFile::remove(fileCompressed);
    return false;
  }

  qint64 compressedSize = 0;

  for (auto i = 0; i < encryptedFiles.length(); ++i) {
    const QString file = encryptedFiles.at(i);
    const QString originalFile = originalFiles.at(i);

    QFileInfo info{file};

    compressedSize = compressFile(&zip, file, info.fileName(), originalFile);

    if (!info.exists() || (compressedSize <= 0)) {
      QFile::remove(fileCompressed);
      return false;
    }
  }

  zip.close();

  if (zip.getZipError() != 0) {
    QFile::remove(fileCompressed);
    return false;
  }

  return true;
}

QStringList Kryvos::Archiver::extractDir(const QString& fileCompressed,
                                         const QString& dir) {
  QuaZip zip{fileCompressed};

  return extractDir(zip, dir);
}

qint64 Kryvos::Archiver::copyFileData(QIODevice& inFile,
                                      QIODevice& outFile,
                                      const QString& filePath,
                                      const qint64 fileSize,
                                      const QString& task) {
  qint64 processedSize = 0;

  while (!inFile.atEnd()) {
    const qint64 writeSize = copyData(inFile, outFile);

    if (-1 == writeSize) {
      processedSize = -1;
      break;
    }

    processedSize += writeSize;

    const auto nextFraction = static_cast<double>(processedSize) /
                              static_cast<double>(fileSize);
    const auto nextPercent = static_cast<int>(nextFraction * 100);

    if (!task.isEmpty()) {
      if (nextPercent > 99) {
        if (tr("Compressing") == task) {
          emit progress(filePath, tr("Compressed"), nextPercent);
        }
        else if (tr("Extracting") == task) {
          emit progress(filePath, tr("Extracted"), nextPercent);
        }
      }
      else {
        emit progress(filePath, task, nextPercent);
      }
    }
  }

  return fileSize;
}

qint64 Kryvos::Archiver::compressFile(QuaZip* zip,
                                      const QString& fileName,
                                      const QString& fileDestination,
                                      const QString& originalFilePath) {
  if (!zip) {
    return -1;
  }

  if (zip->getMode() != QuaZip::mdCreate &&
      zip->getMode() != QuaZip::mdAppend &&
      zip->getMode() != QuaZip::mdAdd) {
    return -1;
  }

  QFile inFile{fileName};

  const bool inFileOpen = inFile.open(QIODevice::ReadOnly);

  if (!inFileOpen) {
    return -1;
  }

  QuaZipFile outFile{zip};
  const bool outFileOpen =
    outFile.open(QIODevice::WriteOnly,
                 QuaZipNewInfo{fileDestination, inFile.fileName()});

  if (!outFileOpen) {
    return -1;
  }

  const QString task = tr("Compressing");
  const qint64 copiedDataSize = copyFileData(inFile, outFile, originalFilePath,
                                             inFile.size(), task);

  if (copiedDataSize <= 0 || (outFile.getZipError() != UNZ_OK)) {
    return -1;
  }

  outFile.close();

  if (outFile.getZipError() != UNZ_OK) {
    return -1;
  }

  inFile.close();

  return copiedDataSize;
}

QStringList Kryvos::Archiver::extractDir(QuaZip& zip, const QString& dir) {
  if (!zip.open(QuaZip::mdUnzip)) {
    return QStringList{};
  }

  QDir directory{dir};

  if (!zip.goToFirstFile()) {
    return QStringList{};
  }

  QStringList extracted{};
  qint64 extractedSize = 0;

  do {
    const QString& name = zip.getCurrentFileName();
    const QString& absFilePath = directory.absoluteFilePath(name);

    extractedSize = extractFile(&zip, QString{}, absFilePath);

    if (extractedSize <= 0) {
      removeFiles(extracted);
      return QStringList{};
    }

    extracted.append(absFilePath);
  } while (zip.goToNextFile());

  zip.close();

  if (zip.getZipError() != 0) {
    removeFiles(extracted);
    return QStringList{};
  }

  return extracted;
}

qint64 Kryvos::Archiver::extractFile(QuaZip* zip,
                                     const QString& fileName,
                                     const QString& fileDest) {
  if (!zip) {
    return -1;
  }

  if (zip->getMode() != QuaZip::mdUnzip) {
    return -1;
  }

  if (!fileName.isEmpty()) {
    zip->setCurrentFile(fileName);
  }

  QuaZipFile inFile{zip};

  const bool inFileOpen = inFile.open(QIODevice::ReadOnly);

  if (!inFileOpen || inFile.getZipError() != UNZ_OK) {
    return -1;
  }

  QDir curDir{};

  if (fileDest.endsWith('/')) {
    const auto destPath = curDir.mkpath(fileDest);

    if (!destPath) {
      return -1;
    }
  }
  else {
    const auto destPath = curDir.mkpath(QFileInfo{fileDest}.absolutePath());

    if (!destPath) {
      return -1;
    }
  }

  QuaZipFileInfo64 info;
  if (!zip->getCurrentFileInfo(&info)) {
    return -1;
  }

  const auto srcPerm = info.getPermissions();

  if (fileDest.endsWith('/') && QFileInfo(fileDest).isDir()) {
    if (srcPerm != 0) {
      QFile{fileDest}.setPermissions(srcPerm);
    }

    return -1;
  }

  QFile outFile{};
  outFile.setFileName(fileDest);

  const bool outFileOpen = outFile.open(QIODevice::WriteOnly);

  if (!outFileOpen) {
    return -1;
  }

  const qint64 uncompressedSize = info.uncompressedSize;

  const QString task = tr("Extracting");
  const qint64 copiedDataSize = copyFileData(inFile, outFile, fileDest,
                                             uncompressedSize, task);

  if ((copiedDataSize <= 0) || inFile.getZipError() != UNZ_OK) {
    outFile.close();
    removeFiles(QStringList{fileDest});
    return -1;
  }

  outFile.close();
  inFile.close();

  if (inFile.getZipError() != UNZ_OK) {
    removeFiles(QStringList{fileDest});
    return -1;
  }

  if (srcPerm != 0) {
    outFile.setPermissions(srcPerm);
  }

  return copiedDataSize;
}
<|endoftext|>


<commit_before>#include "scripting/script_environment.h"

#include "world.h"
#include "halley/support/logger.h"
#include "scripting/script_graph.h"
#include "scripting/script_state.h"

using namespace Halley;

ScriptEnvironment::ScriptEnvironment(const HalleyAPI& api, World& world, Resources& resources, const ScriptNodeTypeCollection& nodeTypeCollection)
	: api(api)
	, world(world)
	, resources(resources)
	, nodeTypeCollection(nodeTypeCollection)
{
}

void ScriptEnvironment::update(Time time, const ScriptGraph& graph, ScriptState& state)
{
	if (!state.hasStarted() || state.getGraphHash() != graph.getHash()) {
		state.start(graph.getStartNode(), graph.getHash());
	}

	// Allocate time for each thread
	auto& threads = state.getThreads();
	if (threads.empty()) {
		return;
	}
	for (auto& thread: threads) {
		thread.getTimeSlice() = time;
	}

	for (size_t i = 0; i < threads.size(); ++i) {
		auto& thread = threads[i];
		Time& timeLeft = thread.getTimeSlice();

		while (timeLeft > 0 && thread.getCurNode()) {
			const auto& node = graph.getNodes().at(thread.getCurNode().value());

			// Start node if not done yet
			if (!thread.isNodeStarted()) {
				thread.startNode(makeNodeData(node));
			}

			// Update
			auto [timeConsumed, state] = updateNode(time, node, thread.getCurData());
			timeLeft -= timeConsumed;

			if (state == ScriptNodeExecutionState::Terminate) {
				// Terminate script
				threads.clear();
				break;
			} else if (state == ScriptNodeExecutionState::Done) {
				// Proceed to next node(s)
				thread.finishNode();

				size_t nOutputsFound = 0;
				for (const auto& output: node.getOutputs()) {
					if (output.nodeId) {
						if (nOutputsFound == 0) {
							// Direct sequel
							thread.advanceToNode(output.nodeId.value());
						} else {
							// Spawn as new thread
							auto& newThread = threads.emplace_back(output.nodeId.value());
							newThread.getTimeSlice() = timeLeft;
						}

						++nOutputsFound;
					}
				}
				if (nOutputsFound == 0) {
					// Nothing follows this, terminate thread
					thread.advanceToNode({});
				}
			}
		}
	}

	// Remove stopped threads
	threads.erase(std::remove_if(threads.begin(), threads.end(), [&] (const ScriptStateThread& thread) { return !thread.getCurNode(); }), threads.end());
}

EntityRef ScriptEnvironment::getEntity(EntityId entityId)
{
	return world.getEntity(entityId);
}

IScriptNodeType::Result ScriptEnvironment::updateNode(Time time, const ScriptGraphNode& node, IScriptStateData* curData)
{
	const auto* nodeType = nodeTypeCollection.tryGetNodeType(node.getType());
	if (!nodeType) {
		Logger::logError("Unknown node type: \"" + node.getType() + "\"");
		return {0, ScriptNodeExecutionState::Done};
	}
	return nodeType->update(*this, time, node, curData);
}

std::unique_ptr<IScriptStateData> ScriptEnvironment::makeNodeData(const ScriptGraphNode& node)
{
	const auto* nodeType = nodeTypeCollection.tryGetNodeType(node.getType());
	if (!nodeType) {
		Logger::logError("Unknown node type: \"" + node.getType() + "\"");
		return {};
	}

	auto result = nodeType->makeData();
	if (result) {
		nodeType->initData(*result, node);
	}
	return result;
}
<commit_msg>Don't infinite loop when a node suspends with no timeslice consumed<commit_after>#include "scripting/script_environment.h"

#include "world.h"
#include "halley/support/logger.h"
#include "scripting/script_graph.h"
#include "scripting/script_state.h"

using namespace Halley;

ScriptEnvironment::ScriptEnvironment(const HalleyAPI& api, World& world, Resources& resources, const ScriptNodeTypeCollection& nodeTypeCollection)
	: api(api)
	, world(world)
	, resources(resources)
	, nodeTypeCollection(nodeTypeCollection)
{
}

void ScriptEnvironment::update(Time time, const ScriptGraph& graph, ScriptState& state)
{
	if (!state.hasStarted() || state.getGraphHash() != graph.getHash()) {
		state.start(graph.getStartNode(), graph.getHash());
	}

	// Allocate time for each thread
	auto& threads = state.getThreads();
	if (threads.empty()) {
		return;
	}
	for (auto& thread: threads) {
		thread.getTimeSlice() = time;
	}

	for (size_t i = 0; i < threads.size(); ++i) {
		auto& thread = threads[i];
		Time& timeLeft = thread.getTimeSlice();
		bool suspended = false;

		while (!suspended && timeLeft > 0 && thread.getCurNode()) {
			const auto& node = graph.getNodes().at(thread.getCurNode().value());

			// Start node if not done yet
			if (!thread.isNodeStarted()) {
				thread.startNode(makeNodeData(node));
			}

			// Update
			auto [timeConsumed, state] = updateNode(time, node, thread.getCurData());
			timeLeft -= timeConsumed;

			if (state == ScriptNodeExecutionState::Terminate) {
				// Terminate script
				threads.clear();
				break;
			} else if (state == ScriptNodeExecutionState::Done) {
				// Proceed to next node(s)
				thread.finishNode();

				size_t nOutputsFound = 0;
				for (const auto& output: node.getOutputs()) {
					if (output.nodeId) {
						if (nOutputsFound == 0) {
							// Direct sequel
							thread.advanceToNode(output.nodeId.value());
						} else {
							// Spawn as new thread
							auto& newThread = threads.emplace_back(output.nodeId.value());
							newThread.getTimeSlice() = timeLeft;
						}

						++nOutputsFound;
					}
				}
				if (nOutputsFound == 0) {
					// Nothing follows this, terminate thread
					thread.advanceToNode({});
				}
			} else if (state == ScriptNodeExecutionState::Executing) {
				suspended = true;
			}
		}
	}

	// Remove stopped threads
	threads.erase(std::remove_if(threads.begin(), threads.end(), [&] (const ScriptStateThread& thread) { return !thread.getCurNode(); }), threads.end());
}

EntityRef ScriptEnvironment::getEntity(EntityId entityId)
{
	return world.getEntity(entityId);
}

IScriptNodeType::Result ScriptEnvironment::updateNode(Time time, const ScriptGraphNode& node, IScriptStateData* curData)
{
	const auto* nodeType = nodeTypeCollection.tryGetNodeType(node.getType());
	if (!nodeType) {
		Logger::logError("Unknown node type: \"" + node.getType() + "\"");
		return {0, ScriptNodeExecutionState::Done};
	}
	return nodeType->update(*this, time, node, curData);
}

std::unique_ptr<IScriptStateData> ScriptEnvironment::makeNodeData(const ScriptGraphNode& node)
{
	const auto* nodeType = nodeTypeCollection.tryGetNodeType(node.getType());
	if (!nodeType) {
		Logger::logError("Unknown node type: \"" + node.getType() + "\"");
		return {};
	}

	auto result = nodeType->makeData();
	if (result) {
		nodeType->initData(*result, node);
	}
	return result;
}
<|endoftext|>


<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <stdexcept>

#include <GL/glew.h>

#include <visionaray/detail/platform.h>

#if defined(VSNRAY_OS_DARWIN)

#include <AvailabilityMacros.h>

#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9

    #pragma GCC diagnostic ignored "-Wdeprecated"
    #pragma GCC diagnostic ignored "-Wdeprecated-declarations"

#endif

#include <OpenGL/gl.h>
#include <GLUT/glut.h>

#else // VSNRAY_OS_DARWIN

#if defined(VSNRAY_OS_WIN32)

#include <windows.h>

#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif

#endif
#include <GL/gl.h>
#include <GL/glut.h>
#ifdef FREEGLUT
#include <GL/freeglut_ext.h>
#endif

#endif

#include "input/glut.h"
#include "viewer_glut.h"

using namespace visionaray;

struct viewer_glut::impl
{
    static viewer_glut*     viewer;
    static mouse::button    down_button;
    static int              win_id;

    impl(viewer_glut* instance);

    void init(
            int argc,
            char** argv,
            std::string window_title,
            bool full_screen,
            int width,
            int height
            );

    static void close_func();
    static void display_func();
    static void idle_func();
    static void keyboard_func(unsigned char key, int, int);
    static void keyboard_up_func(unsigned char key, int, int);
    static void motion_func(int x, int y);
    static void mouse_func(int button, int state, int x, int y);
    static void passive_motion_func(int x, int y);
    static void reshape_func(int w, int h);
    static void special_func(int key, int, int);
    static void special_up_func(int key, int, int);
};

viewer_glut*    viewer_glut::impl::viewer       = nullptr;
mouse::button   viewer_glut::impl::down_button  = mouse::NoButton;
int             viewer_glut::impl::win_id       = 0;

//-------------------------------------------------------------------------------------------------
// Private implementation methods
//-------------------------------------------------------------------------------------------------

viewer_glut::impl::impl(viewer_glut* instance)
{
    viewer_glut::impl::viewer = instance;
}

//-------------------------------------------------------------------------------------------------
// Init GLUT
//

void viewer_glut::impl::init(
        int argc,
        char** argv,
        std::string window_title,
        bool full_screen,
        int width,
        int height
        )
{
    glutInit(&argc, argv);

    glutInitDisplayMode(/*GLUT_3_2_CORE_PROFILE |*/ GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);

    glutInitWindowSize(width, height);
    win_id = glutCreateWindow(window_title.c_str());

    if (full_screen)
    {
        glutFullScreen();
    }

    glutDisplayFunc(display_func);
    glutIdleFunc(idle_func);
    glutKeyboardFunc(keyboard_func);
    glutKeyboardUpFunc(keyboard_up_func);
    glutMotionFunc(motion_func);
    glutMouseFunc(mouse_func);
    glutPassiveMotionFunc(passive_motion_func);
    glutReshapeFunc(reshape_func);
    glutSpecialFunc(special_func);
    glutSpecialUpFunc(special_up_func);
#ifdef FREEGLUT
    glutCloseFunc(close_func);
#else
    atexit(close_func);
#endif

    if (glewInit() != GLEW_OK)
    {
        throw std::runtime_error("glewInit() failed");
    }
}

//-------------------------------------------------------------------------------------------------
// Dispatch to virtual event handlers
//

void viewer_glut::impl::close_func()
{
    viewer->on_close();
}

void viewer_glut::impl::display_func()
{
    viewer->on_display();

    glutSwapBuffers();
}

void viewer_glut::impl::idle_func()
{
    viewer->on_idle();
}

void viewer_glut::impl::keyboard_func(unsigned char key, int, int)
{
    auto k = keyboard::map_glut_key(key);
    auto m = keyboard::map_glut_modifiers(glutGetModifiers());

    viewer->on_key_press( key_event(keyboard::KeyPress, k, m) );
}

void viewer_glut::impl::keyboard_up_func(unsigned char key, int, int)
{
    auto k = keyboard::map_glut_key(key);
    auto m = keyboard::map_glut_modifiers(glutGetModifiers());

    viewer->on_key_release( key_event(keyboard::KeyRelease, k, m) );
}

void viewer_glut::impl::motion_func(int x, int y)
{
    mouse::pos p = { x, y };

    mouse_event event(
            mouse::Move,
            p,
            down_button,
            keyboard::NoKey
            );

    viewer->on_mouse_move(event);
}

void viewer_glut::impl::mouse_func(int button, int state, int x, int y)
{
    mouse::pos p = { x, y };

    auto b = mouse::map_glut_button(button);
    auto m = keyboard::map_glut_modifiers(glutGetModifiers());

    if (state == GLUT_DOWN)
    {
        viewer->on_mouse_down( mouse_event(mouse::ButtonDown, p, b, m) );
        down_button = b;
    }
    else if (state == GLUT_UP)
    {
        viewer->on_mouse_up( mouse_event(mouse::ButtonUp, p, b, m) );
        down_button = mouse::NoButton;
    }
}

void viewer_glut::impl::passive_motion_func(int x, int y)
{
    mouse::pos p = { x, y };

    mouse_event event(
            mouse::Move,
            p,
            mouse::NoButton,
            keyboard::NoKey
            );

    viewer->on_mouse_move(event);
}

void viewer_glut::impl::reshape_func(int w, int h)
{
    viewer->on_resize(w, h);
}

void viewer_glut::impl::special_func(int key, int, int)
{
    auto k = keyboard::map_glut_special(key);
    auto m = keyboard::map_glut_modifiers(glutGetModifiers());

    viewer->on_key_press( key_event(keyboard::KeyPress, k, m) );
}

void viewer_glut::impl::special_up_func(int key, int, int)
{
    auto k = keyboard::map_glut_special(key);
    auto m = keyboard::map_glut_modifiers(glutGetModifiers());

    viewer->on_key_release( key_event(keyboard::KeyRelease, k, m) );
}

//-------------------------------------------------------------------------------------------------
// Public interface
//

viewer_glut::viewer_glut(
        int width,
        int height,
        std::string window_title
        )
    : viewer_base(width, height, window_title)
    , impl_(new impl(this))
{
}

viewer_glut::~viewer_glut()
{
}

void viewer_glut::init(int argc, char** argv)
{
    viewer_base::init(argc, argv);
    impl_->init(argc, argv, window_title(), full_screen(), width(), height());
}

void viewer_glut::event_loop()
{
    glutMainLoop();
}

void viewer_glut::resize(int width, int height)
{
    viewer_base::resize(width, height);
    glutReshapeWindow(width, height);
}

void viewer_glut::swap_buffers()
{
    glutSwapBuffers();
}

void viewer_glut::toggle_full_screen()
{
    // OK to use statics, this is GLUT, anyway...

    static int win_x  = glutGet(GLUT_WINDOW_X);
    static int win_y  = glutGet(GLUT_WINDOW_Y);
    static int width  = glutGet(GLUT_WINDOW_WIDTH);
    static int height = glutGet(GLUT_WINDOW_HEIGHT);

    if (full_screen())
    {
        glutReshapeWindow( width, height );
        glutPositionWindow( win_x, win_y );
    }
    else
    {
        win_x  = glutGet(GLUT_WINDOW_X);
        win_y  = glutGet(GLUT_WINDOW_Y);
        width  = glutGet(GLUT_WINDOW_WIDTH);
        height = glutGet(GLUT_WINDOW_HEIGHT);
        glutFullScreen();
    }

    viewer_base::toggle_full_screen();
}

void viewer_glut::quit()
{
    glutDestroyWindow(impl_->win_id);
#ifdef FREEGLUT
    glutLeaveMainLoop();
    viewer_base::quit();
#else
    viewer_base::quit();
    exit(EXIT_SUCCESS); // TODO
#endif
}

//-------------------------------------------------------------------------------------------------
// Event handlers
//

void viewer_glut::on_idle()
{
    glutPostRedisplay();
}
<commit_msg>Missing include, atexit needs stdlib.h<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <cstdlib>
#include <stdexcept>

#include <GL/glew.h>

#include <visionaray/detail/platform.h>

#if defined(VSNRAY_OS_DARWIN)

#include <AvailabilityMacros.h>

#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9

    #pragma GCC diagnostic ignored "-Wdeprecated"
    #pragma GCC diagnostic ignored "-Wdeprecated-declarations"

#endif

#include <OpenGL/gl.h>
#include <GLUT/glut.h>

#else // VSNRAY_OS_DARWIN

#if defined(VSNRAY_OS_WIN32)

#include <windows.h>

#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif

#endif
#include <GL/gl.h>
#include <GL/glut.h>
#ifdef FREEGLUT
#include <GL/freeglut_ext.h>
#endif

#endif

#include "input/glut.h"
#include "viewer_glut.h"

using namespace visionaray;

struct viewer_glut::impl
{
    static viewer_glut*     viewer;
    static mouse::button    down_button;
    static int              win_id;

    impl(viewer_glut* instance);

    void init(
            int argc,
            char** argv,
            std::string window_title,
            bool full_screen,
            int width,
            int height
            );

    static void close_func();
    static void display_func();
    static void idle_func();
    static void keyboard_func(unsigned char key, int, int);
    static void keyboard_up_func(unsigned char key, int, int);
    static void motion_func(int x, int y);
    static void mouse_func(int button, int state, int x, int y);
    static void passive_motion_func(int x, int y);
    static void reshape_func(int w, int h);
    static void special_func(int key, int, int);
    static void special_up_func(int key, int, int);
};

viewer_glut*    viewer_glut::impl::viewer       = nullptr;
mouse::button   viewer_glut::impl::down_button  = mouse::NoButton;
int             viewer_glut::impl::win_id       = 0;

//-------------------------------------------------------------------------------------------------
// Private implementation methods
//-------------------------------------------------------------------------------------------------

viewer_glut::impl::impl(viewer_glut* instance)
{
    viewer_glut::impl::viewer = instance;
}

//-------------------------------------------------------------------------------------------------
// Init GLUT
//

void viewer_glut::impl::init(
        int argc,
        char** argv,
        std::string window_title,
        bool full_screen,
        int width,
        int height
        )
{
    glutInit(&argc, argv);

    glutInitDisplayMode(/*GLUT_3_2_CORE_PROFILE |*/ GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);

    glutInitWindowSize(width, height);
    win_id = glutCreateWindow(window_title.c_str());

    if (full_screen)
    {
        glutFullScreen();
    }

    glutDisplayFunc(display_func);
    glutIdleFunc(idle_func);
    glutKeyboardFunc(keyboard_func);
    glutKeyboardUpFunc(keyboard_up_func);
    glutMotionFunc(motion_func);
    glutMouseFunc(mouse_func);
    glutPassiveMotionFunc(passive_motion_func);
    glutReshapeFunc(reshape_func);
    glutSpecialFunc(special_func);
    glutSpecialUpFunc(special_up_func);
#ifdef FREEGLUT
    glutCloseFunc(close_func);
#else
    atexit(close_func);
#endif

    if (glewInit() != GLEW_OK)
    {
        throw std::runtime_error("glewInit() failed");
    }
}

//-------------------------------------------------------------------------------------------------
// Dispatch to virtual event handlers
//

void viewer_glut::impl::close_func()
{
    viewer->on_close();
}

void viewer_glut::impl::display_func()
{
    viewer->on_display();

    glutSwapBuffers();
}

void viewer_glut::impl::idle_func()
{
    viewer->on_idle();
}

void viewer_glut::impl::keyboard_func(unsigned char key, int, int)
{
    auto k = keyboard::map_glut_key(key);
    auto m = keyboard::map_glut_modifiers(glutGetModifiers());

    viewer->on_key_press( key_event(keyboard::KeyPress, k, m) );
}

void viewer_glut::impl::keyboard_up_func(unsigned char key, int, int)
{
    auto k = keyboard::map_glut_key(key);
    auto m = keyboard::map_glut_modifiers(glutGetModifiers());

    viewer->on_key_release( key_event(keyboard::KeyRelease, k, m) );
}

void viewer_glut::impl::motion_func(int x, int y)
{
    mouse::pos p = { x, y };

    mouse_event event(
            mouse::Move,
            p,
            down_button,
            keyboard::NoKey
            );

    viewer->on_mouse_move(event);
}

void viewer_glut::impl::mouse_func(int button, int state, int x, int y)
{
    mouse::pos p = { x, y };

    auto b = mouse::map_glut_button(button);
    auto m = keyboard::map_glut_modifiers(glutGetModifiers());

    if (state == GLUT_DOWN)
    {
        viewer->on_mouse_down( mouse_event(mouse::ButtonDown, p, b, m) );
        down_button = b;
    }
    else if (state == GLUT_UP)
    {
        viewer->on_mouse_up( mouse_event(mouse::ButtonUp, p, b, m) );
        down_button = mouse::NoButton;
    }
}

void viewer_glut::impl::passive_motion_func(int x, int y)
{
    mouse::pos p = { x, y };

    mouse_event event(
            mouse::Move,
            p,
            mouse::NoButton,
            keyboard::NoKey
            );

    viewer->on_mouse_move(event);
}

void viewer_glut::impl::reshape_func(int w, int h)
{
    viewer->on_resize(w, h);
}

void viewer_glut::impl::special_func(int key, int, int)
{
    auto k = keyboard::map_glut_special(key);
    auto m = keyboard::map_glut_modifiers(glutGetModifiers());

    viewer->on_key_press( key_event(keyboard::KeyPress, k, m) );
}

void viewer_glut::impl::special_up_func(int key, int, int)
{
    auto k = keyboard::map_glut_special(key);
    auto m = keyboard::map_glut_modifiers(glutGetModifiers());

    viewer->on_key_release( key_event(keyboard::KeyRelease, k, m) );
}

//-------------------------------------------------------------------------------------------------
// Public interface
//

viewer_glut::viewer_glut(
        int width,
        int height,
        std::string window_title
        )
    : viewer_base(width, height, window_title)
    , impl_(new impl(this))
{
}

viewer_glut::~viewer_glut()
{
}

void viewer_glut::init(int argc, char** argv)
{
    viewer_base::init(argc, argv);
    impl_->init(argc, argv, window_title(), full_screen(), width(), height());
}

void viewer_glut::event_loop()
{
    glutMainLoop();
}

void viewer_glut::resize(int width, int height)
{
    viewer_base::resize(width, height);
    glutReshapeWindow(width, height);
}

void viewer_glut::swap_buffers()
{
    glutSwapBuffers();
}

void viewer_glut::toggle_full_screen()
{
    // OK to use statics, this is GLUT, anyway...

    static int win_x  = glutGet(GLUT_WINDOW_X);
    static int win_y  = glutGet(GLUT_WINDOW_Y);
    static int width  = glutGet(GLUT_WINDOW_WIDTH);
    static int height = glutGet(GLUT_WINDOW_HEIGHT);

    if (full_screen())
    {
        glutReshapeWindow( width, height );
        glutPositionWindow( win_x, win_y );
    }
    else
    {
        win_x  = glutGet(GLUT_WINDOW_X);
        win_y  = glutGet(GLUT_WINDOW_Y);
        width  = glutGet(GLUT_WINDOW_WIDTH);
        height = glutGet(GLUT_WINDOW_HEIGHT);
        glutFullScreen();
    }

    viewer_base::toggle_full_screen();
}

void viewer_glut::quit()
{
    glutDestroyWindow(impl_->win_id);
#ifdef FREEGLUT
    glutLeaveMainLoop();
    viewer_base::quit();
#else
    viewer_base::quit();
    exit(EXIT_SUCCESS); // TODO
#endif
}

//-------------------------------------------------------------------------------------------------
// Event handlers
//

void viewer_glut::on_idle()
{
    glutPostRedisplay();
}
<|endoftext|>


<commit_before>#include "appinfo.h"

const Version AppInfo::version = Version(0, 0, 7, 0, 101);
const std::string AppInfo::name = "JASP";

std::string AppInfo::getShortDesc(bool includeMassive)
{
	return AppInfo::name + " " + AppInfo::version.asString(includeMassive, true);
}
<commit_msg>Version bump: 0.7.0 Beta 2<commit_after>#include "appinfo.h"

const Version AppInfo::version = Version(0, 0, 7, 0, 102);
const std::string AppInfo::name = "JASP";

std::string AppInfo::getShortDesc(bool includeMassive)
{
	return AppInfo::name + " " + AppInfo::version.asString(includeMassive, true);
}
<|endoftext|>


<commit_before>//-- Copyright 2015 Intrig
//-- See https://github.com/intrig/xenon for license.
#include <iostream>
#include <vector>
#include <ict/xenon.h>

using std::cout;
using std::cerr;
using ict::message;

struct nv_pairs {
    nv_pairs(const std::string & name, int64_t value) : name(name), value(value) {}
    std::string name;
    int64_t value;
};

int main(int, char**) {
    try {
        auto fields = std::vector<nv_pairs>();

        cout << "loading\n";
        ict::spec_server doc("icd.xddl");
        cout << "assigning\n";
        auto msg = ict::parse(doc, "0101046B102C000114E03003603800203801C03801E03801F030037030002030"
              "00903000603000E0300120300130380000300110300030380080300200300210"
              "3001903001603000F03000703000403000C03000503000D1A03C9E16C18070DE"
              "2C7CFF3C7CC1001E00E01C000389");

        cout << "iterating over top level nodes only\n";
        for (auto c = msg.begin(); c != msg.end(); ++c) {
            // and now we can process each node
            cout << c->name() << '\n';
        }

        // using a linear cursor, we can iterate through the entire message in a depth first way
        cout << "putting fields and their values into a vector: " << ict::to_text(msg);
        for (auto c = ict::linear_begin(msg.root()); c != msg.end(); ++c) {
            // consumes() means it consumes bits from the message, usually a field in the message
            if (c->consumes()) fields.emplace_back(c->name(), c->value());
        }
        cout << "done, processed " << fields.size() << " fields\n\n";
        fields.clear();

        // We an also do the same thing using the ict::recurse() algorithm that takes a root node and
        // a lambda expression.  This is currently more efficient and recommended over the linear_cursor
        // method above.
        cout << "again, using recurse algorithm\n";
        // The first cursor parameter in the lambda expression is a cursor to the current node, the second
        // cursor parameter is its parent, which is unused in this case.
        ict::recurse(msg.root(), [&](message::cursor c, message::cursor) {
            if (c->consumes()) fields.emplace_back(c->name(), c->value());
        });
        cout << "done, processed " << fields.size() << " fields\n\n";

        cout << "now find a field: DATA/MSG_TYPE\n";
        auto c = ict::find(msg.root(), "DATA/MSG_TYPE");

        if (c != msg.end()) cout << "found it! " << ict::description(c) << "\n\n";

        cout << "now find using a non-anchored path: //RLP_CAP_INFO_BLOCK/MAX_MS_NAK_ROUNDS_FWD\n";
        c = ict::find(msg.root(), "//RLP_CAP_INFO_BLOCK/MAX_MS_NAK_ROUNDS_FWD");
        if (c != msg.end()) cout << "found it! " << c->value() << "\n\n";

    } catch (ict::exception & e) { cerr << e.what() << '\n';
        return 1;
    }
}
<commit_msg>added path_string() call to decode example<commit_after>//-- Copyright 2015 Intrig
//-- See https://github.com/intrig/xenon for license.
#include <iostream>
#include <vector>
#include <ict/xenon.h>

using std::cout;
using std::cerr;
using ict::message;

struct nv_pairs {
    nv_pairs(const std::string & name, int64_t value) : name(name), value(value) {}
    std::string name;
    int64_t value;
};

int main(int, char**) {
    try {
        auto fields = std::vector<nv_pairs>();

        cout << "loading\n";
        ict::spec_server doc("icd.xddl");
        cout << "assigning\n";
        auto msg = ict::parse(doc, "0101046B102C000114E03003603800203801C03801E03801F030037030002030"
              "00903000603000E0300120300130380000300110300030380080300200300210"
              "3001903001603000F03000703000403000C03000503000D1A03C9E16C18070DE"
              "2C7CFF3C7CC1001E00E01C000389");

        cout << "iterating over top level nodes only\n";
        for (auto c = msg.begin(); c != msg.end(); ++c) {
            // and now we can process each node
            cout << c->name() << '\n';
        }

        // using a linear cursor, we can iterate through the entire message in a depth first way
        cout << "putting fields and their values into a vector: " << ict::to_text(msg);
        for (auto c = ict::linear_begin(msg.root()); c != msg.end(); ++c) {
            // consumes() means it consumes bits from the message, usually a field
            if (c->consumes()) fields.emplace_back(c->name(), c->value());
        }
        cout << "done, processed " << fields.size() << " fields\n\n";
        fields.clear();

        // We an also do the same thing using the ict::recurse() algorithm that takes a root node and
        // a lambda expression.  This is currently more efficient and recommended over the linear_cursor
        // method above.
        cout << "again, using recurse algorithm\n";
        // The first cursor parameter in the lambda expression is a cursor to the current node, the second
        // cursor parameter is its parent, which is unused in this case.
        ict::recurse(msg.root(), [&](message::cursor c, message::cursor) {
            if (c->consumes()) fields.emplace_back(c->name(), c->value());
        });
        cout << "done, processed " << fields.size() << " fields\n\n";

        cout << "now find a field: DATA/MSG_TYPE\n";
        auto c = ict::find(msg.root(), "DATA/MSG_TYPE");

        if (c != msg.end()) cout << "found it! " << ict::description(c) << "\n\n";

        cout << "now find using a non-anchored path: //RLP_CAP_INFO_BLOCK/MAX_MS_NAK_ROUNDS_FWD\n";
        c = ict::find(msg.root(), "//RLP_CAP_INFO_BLOCK/MAX_MS_NAK_ROUNDS_FWD");
        if (c != msg.end()) {
            cout << "found it! " << c->value() << "\n";
            cout << "full path is: " << ict::path_string(c) << "\n\n";
        }

    } catch (ict::exception & e) { cerr << e.what() << '\n';
        return 1;
    }
}
<|endoftext|>


<commit_before>/* <x0/FileInfo.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 * http://www.xzero.ws/
 *
 * (c) 2009-2010 Christian Parpart <trapni@gentoo.org>
 */

#include <x0/io/FileInfo.h>
#include <x0/io/FileInfoService.h>

namespace x0 {

FileInfo::FileInfo(FileInfoService& service, const std::string& filename) :
	service_(service),
	stat_(),
	errno_(),
	inotifyId_(-1),
	cachedAt_(ev_now(service.loop_)),
	filename_(filename),
	etag_(),
	mtime_(),
	mimetype_()
{
	if (::stat(filename_.c_str(), &stat_) == 0) {
		etag_ = service_.make_etag(*this);
		mimetype_ = service_.get_mimetype(filename_);
	}
	errno_ = errno;
}

void FileInfo::clear()
{
	clearCustomData();

	etag_ = service_.make_etag(*this);
	mtime_.clear(); // gets computed on-demand
	mimetype_ = service_.get_mimetype(filename_);
}

} // namespace x0
<commit_msg>[io] FileInfo: fixes errno value (of 0) for valid stat()s<commit_after>/* <x0/FileInfo.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 * http://www.xzero.ws/
 *
 * (c) 2009-2010 Christian Parpart <trapni@gentoo.org>
 */

#include <x0/io/FileInfo.h>
#include <x0/io/FileInfoService.h>

namespace x0 {

FileInfo::FileInfo(FileInfoService& service, const std::string& filename) :
	service_(service),
	stat_(),
	errno_(0),
	inotifyId_(-1),
	cachedAt_(ev_now(service.loop_)),
	filename_(filename),
	etag_(),
	mtime_(),
	mimetype_()
{
	if (::stat(filename_.c_str(), &stat_) == 0) {
		etag_ = service_.make_etag(*this);
		mimetype_ = service_.get_mimetype(filename_);
	} else
		errno_ = errno;
}

void FileInfo::clear()
{
	clearCustomData();

	etag_ = service_.make_etag(*this);
	mtime_.clear(); // gets computed on-demand
	mimetype_ = service_.get_mimetype(filename_);
}

} // namespace x0
<|endoftext|>


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

#include <algorithm>
#include <numeric>
#include <sstream>
#include <string>

#include "printers.h"
#include "profile.h"
#include "profiler.h"

#include "amx/amx.h"
#include "amx/amxdbg.h"

namespace {

int AMXAPI Debug(AMX *amx) {
	return samp_profiler::Profiler::Get(amx)->Debug();
}

} // anonymouse namespace

namespace samp_profiler {

// statics
bool Profiler::substract_child_time_;
std::map<AMX*, Profiler*> Profiler::instances_;

Profiler::Profiler() {}

// Extracts the names of native functions from the native table.
static void GetNatives(AMX *amx, std::vector<Profiler::Function> &natives) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	AMX_FUNCSTUBNT *nativeTable = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);

	int numberOfNatives;
	amx_NumNatives(amx, &numberOfNatives);

	for (int i = 0; i < numberOfNatives; i++) {
		natives.push_back(Profiler::Function(nativeTable[i].address,
			reinterpret_cast<char*>(amx->base + nativeTable[i].nameofs)));
	}
}

// Extracts the names of public functions from the native table.
static void GetPublics(AMX *amx, std::vector<Profiler::Function> &publics) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	AMX_FUNCSTUBNT *publicTable = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->publics);

	int numberOfPublics;
	amx_NumPublics(amx, &numberOfPublics);

	for (int i = 0; i < numberOfPublics; i++) {
		publics.push_back(Profiler::Function(publicTable[i].address,
			reinterpret_cast<char*>(amx->base + publicTable[i].nameofs)));
	}
}

// Reads from a code section at a given location.
static inline cell ReadAmxCode(AMX *amx, cell where) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	return *reinterpret_cast<cell*>(amx->base + hdr->cod + where);
}

// Comparison functiosn for different stats sorting modes
static bool ByCalls(const std::pair<cell, PerformanceCounter> &op1,
						 const std::pair<cell, PerformanceCounter> &op2) {
	return op1.second.GetNumberOfCalls() > op2.second.GetNumberOfCalls();
}

static bool ByTime(const std::pair<cell, PerformanceCounter> &op1,
						const std::pair<cell, PerformanceCounter> &op2) {
	return op1.second.GetTime() > op2.second.GetTime();
}

static bool ByTimePerCall(const std::pair<cell, PerformanceCounter> &op1,
							   const std::pair<cell, PerformanceCounter> &op2) {
	return static_cast<double>(op1.second.GetTime()) / static_cast<double>(op1.second.GetNumberOfCalls())
		 > static_cast<double>(op2.second.GetTime()) / static_cast<double>(op2.second.GetNumberOfCalls());
}

bool Profiler::IsScriptProfilable(AMX *amx) {
	uint16_t flags;
	amx_Flags(amx, &flags);

	if ((flags & AMX_FLAG_DEBUG) != 0) {
		return true;
	}

	if ((flags & AMX_FLAG_NOCHECKS) == 0) {
		return true;
	}

	return false;
}

// static
void Profiler::SetSubstractChildTime(bool set) {
	Profiler::substract_child_time_ = set;
}

// static
void Profiler::Attach(AMX *amx) {
	Profiler *prof = new Profiler(amx);
	instances_[amx] = prof;
	prof->Activate();
}

// static
void Profiler::Attach(AMX *amx, const DebugInfo &debugInfo) {
	Attach(amx);
	Get(amx)->SetDebugInfo(debugInfo);
}

// static
void Profiler::Detach(AMX *amx) {
	Profiler *prof = Profiler::Get(amx);
	if (prof != 0) {
		prof->Deactivate();
		delete prof;
	}
	instances_.erase(amx);
}

// static
Profiler *Profiler::Get(AMX *amx) {
	std::map<AMX*, Profiler*>::iterator it = instances_.find(amx);
	if (it != instances_.end()) {
		return it->second;
	}
	return 0;
}

Profiler::Profiler(AMX *amx)
	: active_(false)
	, amx_(amx)
	, debug_(amx->debug)
{
	// Since PrintStats is done in AmxUnload and amx->base is already freed before
	// AmxUnload gets called, therefore both native and public tables are not accessible,
	// from there, so they must be stored separately in some global place.
	GetNatives(amx, natives_);
	GetPublics(amx, publics_);
}

void Profiler::SetDebugInfo(const DebugInfo &info) {
	debugInfo_ = info;
}

void Profiler::Activate() {
	if (!active_) {
		active_ = true;
		amx_SetDebugHook(amx_, ::Debug);
	}
}

bool Profiler::IsActive() const {
	return active_;
}

void Profiler::Deactivate() {
	if (active_) {
		active_ = false;
		amx_SetDebugHook(amx_, debug_);
	}
}

void Profiler::ResetStats() {
	counters_.clear();
}

void Profiler::PrintStats(Printer &printer, OutputSortMode order) {
	std::vector<std::pair<cell, PerformanceCounter> > stats(
		counters_.begin(), counters_.end());

	switch (order) {
	case SORT_BY_CALLS:
		std::sort(stats.begin(), stats.end(), ByCalls);
		break;
	case SORT_BY_TIME:
		std::sort(stats.begin(), stats.end(), ByTime);
		break;
	case SORT_BY_TIME_PER_CALL:
		std::sort(stats.begin(), stats.end(), ByTimePerCall);
		break;
	default:
		// leave as is
		break;
	}

	Profile profile;

	for (std::vector<std::pair<cell, PerformanceCounter> >::iterator stat_it = stats.begin();
			stat_it != stats.end(); ++stat_it)
	{
		cell address = stat_it->first;
		PerformanceCounter &counter = stat_it->second;

		if (address <= 0) {
			profile.push_back(ProfileEntry(natives_[-address].name(), "native", counter));
		} else {
			bool found = false;
			// Search in public table
			for (std::vector<Profiler::Function>::iterator pub_it = publics_.begin();
					pub_it != publics_.end(); ++pub_it)
			{
				if (pub_it->address() == address)  {
					profile.push_back(ProfileEntry(pub_it->name(), "public", counter));
					found = true;
					break;
				}
			}
			// Search in symbol table
			if (!found) {
				if (debugInfo_.IsLoaded()) {
					std::string name = debugInfo_.GetFunctionName(address);
					if (!name.empty()) {
						profile.push_back(ProfileEntry(debugInfo_.GetFunctionName(address), "ordinary", counter));
						found = true;
					}
				}
			}
			// Not found
			if (!found) {
				std::stringstream ss;
				ss << "0x" << std::hex << address;
				profile.push_back(ProfileEntry(ss.str(), "unknown", counter));
			}
		}
	}

	printer.Print(profile);
}

int Profiler::Debug() {
	// Get previous stack frame.
	cell prevFrame = amx_->stp;

	if (!call_stack_.empty()) {
		prevFrame = call_stack_.top().frame();
	}

	// Check whether current frame is different.
	if (amx_->frm < prevFrame) {
		// Probably entered a function body (first BREAK after PROC).
		cell address = amx_->cip - 2*sizeof(cell);
		// Check if we have a PROC opcode behind.
		if (ReadAmxCode(amx_, address) == 46) {
			EnterFunction(CallInfo(amx_->frm, address, CallInfo::ORDINARY));
		}
	} else if (amx_->frm > prevFrame) {
		if (call_stack_.top().functionType() != CallInfo::PUBLIC) { // entry points are handled by Exec
			// Left the function
			cell address = call_stack_.top().address();
			LeaveFunction(address);
		}
	}

	if (debug_ != 0) {
		// Others could set their own debug hooks
		return debug_(amx_);
	}

	return AMX_ERR_NONE;
}

int Profiler::Callback(cell index, cell *result, cell *params) {
	cell address = -index;

	EnterFunction(CallInfo(amx_->frm, address, CallInfo::NATIVE));
	int error = amx_Callback(amx_, index, result, params);
	LeaveFunction(address);

	return error;
}

int Profiler::Exec(cell *retval, int index) {
	if (index >= 0 || index == AMX_EXEC_MAIN) {
		AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx_->base);
		cell address = 0;
		if (index == AMX_EXEC_MAIN) {
			address = hdr->cip;
		} else {
			AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + hdr->publics);
			address = publics[index].address;
		}

		EnterFunction(CallInfo(amx_->stk - 3*sizeof(cell), address, CallInfo::PUBLIC));
		int error = amx_Exec(amx_, retval, index);
		LeaveFunction(address);

		return error;
	} else {
		return amx_Exec(amx_, retval, index);
	}
}

void Profiler::EnterFunction(const CallInfo &info) {
	if (active_) {
		PerformanceCounter &counter = counters_[info.address()];
		if (call_stack_.empty() || !Profiler::substract_child_time_) {
			counter.Start();
		} else {
			counter.Start(&counters_[call_stack_.top().address()]);
		}
	}
	call_stack_.push(info);
}

void Profiler::LeaveFunction(cell address) {
	while (true) {
		cell topAddress = call_stack_.top().address();
		if (active_) {
			counters_[topAddress].Stop();
		}
		call_stack_.pop();
		if (topAddress == address) {
			break;
		}
	}
}

bool Profiler::GetLastCall(CallInfo &call) const {
	if (!call_stack_.empty()) {
		call = call_stack_.top();
		return true;
	}
	return false;
}

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

#include <algorithm>
#include <numeric>
#include <sstream>
#include <string>

#include "printers.h"
#include "profile.h"
#include "profiler.h"

#include "amx/amx.h"
#include "amx/amxdbg.h"

namespace {

int AMXAPI Debug(AMX *amx) {
	return samp_profiler::Profiler::Get(amx)->Debug();
}

} // anonymous namespace

namespace samp_profiler {

// statics
bool Profiler::substract_child_time_;
std::map<AMX*, Profiler*> Profiler::instances_;

Profiler::Profiler() {}

// Extracts the names of native functions from the native table.
static void GetNatives(AMX *amx, std::vector<Profiler::Function> &natives) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	AMX_FUNCSTUBNT *nativeTable = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);

	int numberOfNatives;
	amx_NumNatives(amx, &numberOfNatives);

	for (int i = 0; i < numberOfNatives; i++) {
		natives.push_back(Profiler::Function(nativeTable[i].address,
			reinterpret_cast<char*>(amx->base + nativeTable[i].nameofs)));
	}
}

// Extracts the names of public functions from the native table.
static void GetPublics(AMX *amx, std::vector<Profiler::Function> &publics) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	AMX_FUNCSTUBNT *publicTable = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->publics);

	int numberOfPublics;
	amx_NumPublics(amx, &numberOfPublics);

	for (int i = 0; i < numberOfPublics; i++) {
		publics.push_back(Profiler::Function(publicTable[i].address,
			reinterpret_cast<char*>(amx->base + publicTable[i].nameofs)));
	}
}

// Reads from a code section at a given location.
static inline cell ReadAmxCode(AMX *amx, cell where) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	return *reinterpret_cast<cell*>(amx->base + hdr->cod + where);
}

// Comparison functiosn for different stats sorting modes
static bool ByCalls(const std::pair<cell, PerformanceCounter> &op1,
						 const std::pair<cell, PerformanceCounter> &op2) {
	return op1.second.GetNumberOfCalls() > op2.second.GetNumberOfCalls();
}

static bool ByTime(const std::pair<cell, PerformanceCounter> &op1,
						const std::pair<cell, PerformanceCounter> &op2) {
	return op1.second.GetTime() > op2.second.GetTime();
}

static bool ByTimePerCall(const std::pair<cell, PerformanceCounter> &op1,
							   const std::pair<cell, PerformanceCounter> &op2) {
	return static_cast<double>(op1.second.GetTime()) / static_cast<double>(op1.second.GetNumberOfCalls())
		 > static_cast<double>(op2.second.GetTime()) / static_cast<double>(op2.second.GetNumberOfCalls());
}

bool Profiler::IsScriptProfilable(AMX *amx) {
	uint16_t flags;
	amx_Flags(amx, &flags);

	if ((flags & AMX_FLAG_DEBUG) != 0) {
		return true;
	}

	if ((flags & AMX_FLAG_NOCHECKS) == 0) {
		return true;
	}

	return false;
}

// static
void Profiler::SetSubstractChildTime(bool set) {
	Profiler::substract_child_time_ = set;
}

// static
void Profiler::Attach(AMX *amx) {
	Profiler *prof = new Profiler(amx);
	instances_[amx] = prof;
	prof->Activate();
}

// static
void Profiler::Attach(AMX *amx, const DebugInfo &debugInfo) {
	Attach(amx);
	Get(amx)->SetDebugInfo(debugInfo);
}

// static
void Profiler::Detach(AMX *amx) {
	Profiler *prof = Profiler::Get(amx);
	if (prof != 0) {
		prof->Deactivate();
		delete prof;
	}
	instances_.erase(amx);
}

// static
Profiler *Profiler::Get(AMX *amx) {
	std::map<AMX*, Profiler*>::iterator it = instances_.find(amx);
	if (it != instances_.end()) {
		return it->second;
	}
	return 0;
}

Profiler::Profiler(AMX *amx)
	: active_(false)
	, amx_(amx)
	, debug_(amx->debug)
{
	// Since PrintStats is done in AmxUnload and amx->base is already freed before
	// AmxUnload gets called, therefore both native and public tables are not accessible,
	// from there, so they must be stored separately in some global place.
	GetNatives(amx, natives_);
	GetPublics(amx, publics_);
}

void Profiler::SetDebugInfo(const DebugInfo &info) {
	debugInfo_ = info;
}

void Profiler::Activate() {
	if (!active_) {
		active_ = true;
		amx_SetDebugHook(amx_, ::Debug);
	}
}

bool Profiler::IsActive() const {
	return active_;
}

void Profiler::Deactivate() {
	if (active_) {
		active_ = false;
		amx_SetDebugHook(amx_, debug_);
	}
}

void Profiler::ResetStats() {
	counters_.clear();
}

void Profiler::PrintStats(Printer &printer, OutputSortMode order) {
	std::vector<std::pair<cell, PerformanceCounter> > stats(
		counters_.begin(), counters_.end());

	switch (order) {
	case SORT_BY_CALLS:
		std::sort(stats.begin(), stats.end(), ByCalls);
		break;
	case SORT_BY_TIME:
		std::sort(stats.begin(), stats.end(), ByTime);
		break;
	case SORT_BY_TIME_PER_CALL:
		std::sort(stats.begin(), stats.end(), ByTimePerCall);
		break;
	default:
		// leave as is
		break;
	}

	Profile profile;

	for (std::vector<std::pair<cell, PerformanceCounter> >::iterator stat_it = stats.begin();
			stat_it != stats.end(); ++stat_it)
	{
		cell address = stat_it->first;
		PerformanceCounter &counter = stat_it->second;

		if (address <= 0) {
			profile.push_back(ProfileEntry(natives_[-address].name(), "native", counter));
		} else {
			bool found = false;
			// Search in public table
			for (std::vector<Profiler::Function>::iterator pub_it = publics_.begin();
					pub_it != publics_.end(); ++pub_it)
			{
				if (pub_it->address() == address)  {
					profile.push_back(ProfileEntry(pub_it->name(), "public", counter));
					found = true;
					break;
				}
			}
			// Search in symbol table
			if (!found) {
				if (debugInfo_.IsLoaded()) {
					std::string name = debugInfo_.GetFunctionName(address);
					if (!name.empty()) {
						profile.push_back(ProfileEntry(debugInfo_.GetFunctionName(address), "ordinary", counter));
						found = true;
					}
				}
			}
			// Not found
			if (!found) {
				std::stringstream ss;
				ss << "0x" << std::hex << address;
				profile.push_back(ProfileEntry(ss.str(), "unknown", counter));
			}
		}
	}

	printer.Print(profile);
}

int Profiler::Debug() {
	// Get previous stack frame.
	cell prevFrame = amx_->stp;

	if (!call_stack_.empty()) {
		prevFrame = call_stack_.top().frame();
	}

	// Check whether current frame is different.
	if (amx_->frm < prevFrame) {
		// Probably entered a function body (first BREAK after PROC).
		cell address = amx_->cip - 2*sizeof(cell);
		// Check if we have a PROC opcode behind.
		if (ReadAmxCode(amx_, address) == 46) {
			EnterFunction(CallInfo(amx_->frm, address, CallInfo::ORDINARY));
		}
	} else if (amx_->frm > prevFrame) {
		if (call_stack_.top().functionType() != CallInfo::PUBLIC) { // entry points are handled by Exec
			// Left the function
			cell address = call_stack_.top().address();
			LeaveFunction(address);
		}
	}

	if (debug_ != 0) {
		// Others could set their own debug hooks
		return debug_(amx_);
	}

	return AMX_ERR_NONE;
}

int Profiler::Callback(cell index, cell *result, cell *params) {
	cell address = -index;

	EnterFunction(CallInfo(amx_->frm, address, CallInfo::NATIVE));
	int error = amx_Callback(amx_, index, result, params);
	LeaveFunction(address);

	return error;
}

int Profiler::Exec(cell *retval, int index) {
	if (index >= 0 || index == AMX_EXEC_MAIN) {
		AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx_->base);
		cell address = 0;
		if (index == AMX_EXEC_MAIN) {
			address = hdr->cip;
		} else {
			AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + hdr->publics);
			address = publics[index].address;
		}

		EnterFunction(CallInfo(amx_->stk - 3*sizeof(cell), address, CallInfo::PUBLIC));
		int error = amx_Exec(amx_, retval, index);
		LeaveFunction(address);

		return error;
	} else {
		return amx_Exec(amx_, retval, index);
	}
}

void Profiler::EnterFunction(const CallInfo &info) {
	if (active_) {
		PerformanceCounter &counter = counters_[info.address()];
		if (call_stack_.empty() || !Profiler::substract_child_time_) {
			counter.Start();
		} else {
			counter.Start(&counters_[call_stack_.top().address()]);
		}
	}
	call_stack_.push(info);
}

void Profiler::LeaveFunction(cell address) {
	while (true) {
		cell topAddress = call_stack_.top().address();
		if (active_) {
			counters_[topAddress].Stop();
		}
		call_stack_.pop();
		if (topAddress == address) {
			break;
		}
	}
}

bool Profiler::GetLastCall(CallInfo &call) const {
	if (!call_stack_.empty()) {
		call = call_stack_.top();
		return true;
	}
	return false;
}

} // namespace samp_profiler
<|endoftext|>