<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/pm/p10_update_ec_state.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019,2022                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/// @file  p10_update_ec_state.C
/// @brief Update the core configured data in CCSR register and then deals with
///        deconfigured cores to verify the chiplet state..if it is still running then
///        will put the core to stop 11 state
///
/// *HWP HW Owner        : Greg Still <stillgs@us.ibm.com>
/// *HWP FW Owner        : Prasad Bg Ranganath <prasadbgr@in.ibm.com>
/// *HWP Team            : PM
/// *HWP Level           : 2
/// *HWP Consumed by     : HB,PGPE,CME,OCC
///

// -----------------------------------------------------------------------------
//  Includes
// -----------------------------------------------------------------------------
#include "p10_update_ec_state.H"
#include "p10_hcd_common.H"
#include "p10_hcd_cache_stopclocks.H"
#include "p10_hcd_core_poweroff.H"
#include "p10_hcd_l3_purge.H"
#include "p10_hcd_l2_purge.H"
#include "p10_hcd_powerbus_purge.H"
#include "p10_hcd_l2_tlbie_quiesce.H"
#include "p10_hcd_ncu_purge.H"
#include "p10_hcd_chtm_purge.H"
#include "p10_hcd_core_stopclocks.H"
#include "p10_hcd_cache_poweroff.H"
#include "p10_hcd_core_shadows_disable.H"
#include "p10_hcd_core_stopgrid.H"
#include <p10_scom_proc.H>
#include <p10_scom_c.H>
#include <p10_scom_eq.H>

using namespace scomt;
using namespace proc;
using namespace c;
using namespace eq;

// -----------------------------------------------------------------------------
//  Function prototypes
// -----------------------------------------------------------------------------
static fapi2::ReturnCode update_ec_config(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target);

fapi2::ReturnCode verify_ec_hw_state(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target);

fapi2::ReturnCode p10_check_core_l3_clock_power_state(
    const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_core_target,
    uint8_t i_core_unit_pos);

// -----------------------------------------------------------------------------
//  Constants
// -----------------------------------------------------------------------------

// See .H for documentation
fapi2::ReturnCode p10_update_ec_state(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    uint8_t i_qssr_skip)
{

    FAPI_IMP("> p10_update_ec_state");

    FAPI_TRY(update_ec_config(i_target),
             "Error update_core_config detected");
    //TODO Need to find the right way to get deconfigured target
    FAPI_TRY(verify_ec_hw_state(i_target));

fapi_try_exit:
    FAPI_INF("< p10_update_ec_state");

    return fapi2::current_err;
} // END p10_update_ec_state

fapi2::ReturnCode verify_ec_hw_state(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_INF (">>verify_hw_state");
#if 0
    uint8_t l_present_core_unit_pos;
    uint8_t l_functional_core_unit_pos;

    uint8_t l_core_match = 0;

    //Get the perv target lists
    auto l_core_present_target_vector = i_target.getChildren<fapi2::TARGET_TYPE_CORE>(
                                            fapi2::TARGET_STATE_PRESENT);

    //Get the functional lists
    auto l_core_functional_vector =
        i_target.getChildren<fapi2::TARGET_TYPE_CORE>
        (fapi2::TARGET_STATE_FUNCTIONAL);

    //Verify Core state
    for (auto core_present_it : l_core_present_target_vector)
    {
        FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS,
                                core_present_it,
                                l_present_core_unit_pos));

        l_core_match = 1;

        FAPI_INF("Present core %d ", l_present_core_unit_pos);

        for (auto core_functional_it : l_core_functional_vector)
        {
            FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS,
                                    core_functional_it,
                                    l_functional_core_unit_pos));
            FAPI_INF("  Functional EC %d",
                     l_functional_core_unit_pos);

            if (l_functional_core_unit_pos == l_present_core_unit_pos)
            {
                l_core_match = 1;
                break;
            }
            else
            {
                l_core_match = 0;
            }
        }//end of functional

        if (!l_core_match)
        {
            for ( auto l_core_target : core_present_it.getChildren<fapi2::TARGET_TYPE_CORE>(fapi2::TARGET_STATE_PRESENT) )
            {
                FAPI_INF("Core present but non functional %d",
                         l_present_core_unit_pos);

                //Check the clock state and power state
                FAPI_TRY(p10_check_core_l3_clock_power_state(l_core_target, l_present_core_unit_pos));

            }
        }
    }//end of present

fapi_try_exit:
#endif
    FAPI_INF("< update_core_config...");
    return fapi2::current_err;

}

/// @brief Update the CCSR for cores
///
/// @param[in]     i_target   Reference to TARGET_TYPE_PROC_CHIP target
/// @return  FAPI2_RC_SUCCESS if success, else error code.
static fapi2::ReturnCode update_ec_config(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_INF("> update_core_config...");

    uint8_t l_present_core_unit_pos;
    uint8_t l_functional_core_unit_pos;
    fapi2::buffer<uint64_t> l_core_config = 0;
    fapi2::buffer<uint64_t> l_pscom_config = 0;

    auto l_core_present_vector =
        i_target.getChildren<fapi2::TARGET_TYPE_CORE>
        (fapi2::TARGET_STATE_PRESENT);

    auto l_core_functional_vector =
        i_target.getChildren<fapi2::TARGET_TYPE_CORE>
        (fapi2::TARGET_STATE_FUNCTIONAL);

    FAPI_INF("  Number of present cores = %d; Number of functional cores = %d",
             l_core_present_vector.size(),
             l_core_functional_vector.size());

    // For each present core,  set multicast groups and the CCSR
    for (auto core_present_it : l_core_present_vector)
    {
        FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS,
                                core_present_it,
                                l_present_core_unit_pos));

        FAPI_INF("  Checking if present EC %d is functional",
                 l_present_core_unit_pos);

        for (auto core_functional_it : l_core_functional_vector)
        {
            FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS,
                                    core_functional_it,
                                    l_functional_core_unit_pos));
            FAPI_DBG("  Functional EC %d",
                     l_functional_core_unit_pos);

            if (l_functional_core_unit_pos == l_present_core_unit_pos)
            {
                // Set the appropriate bit in the Core Configuration Status
                // Register buffer
                FAPI_INF("  Setting EC %d as good in value to be written to CCSR",
                         l_present_core_unit_pos);
                l_core_config.setBit(l_present_core_unit_pos);

                auto l_eq = core_functional_it.getParent<fapi2::TARGET_TYPE_EQ>();

                l_present_core_unit_pos = l_present_core_unit_pos % 4;

                //Update the pscom enable bit
                l_pscom_config.setBit(l_present_core_unit_pos + 5);

                FAPI_TRY(fapi2::putScom(l_eq, CPLT_CTRL3_WO_OR, l_pscom_config));
                break;
            }  // Current core
        } // Functional core loop
    }  // Present core loop

    // Write the recalculated OCC Core Configuration Status Register
    FAPI_INF("  Writing OCC CCSR");
    FAPI_TRY(fapi2::putScom(i_target, TP_TPCHIP_OCC_OCI_OCB_CCSR_RW, l_core_config));

fapi_try_exit:
    FAPI_INF("< update_core_config...");
    return fapi2::current_err;

}

#define CORE_START_POSITION 5
#define CACHE_START_POSITION 9

fapi2::ReturnCode p10_check_core_l3_clock_power_state(
    const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_core_target,
    uint8_t i_core_unit_pos)
{
    fapi2::buffer<uint64_t> l_data = 0;
    uint64_t l_pfet_sense = 0;
    uint8_t l_core_relative_pos  = i_core_unit_pos % 4;
    uint8_t l_l3_relative_pos    = i_core_unit_pos % 4;
    uint8_t l_core_clock_State = 0;
    uint8_t l_l3_clock_State = 0;

    do
    {
        auto l_eq_target = i_core_target.getParent<fapi2::TARGET_TYPE_EQ>();
        //Read the power state of core/l2
        FAPI_TRY(GET_CPMS_CL2_PFETSTAT(i_core_target, l_data));
        GET_CPMS_CL2_PFETSTAT_VDD_PFETS_ENABLED_SENSE(l_data, l_pfet_sense);

        //verify L3/core clocks are on
        FAPI_TRY(GET_CLOCK_STAT_SL(l_eq_target, l_data));
        l_core_clock_State = l_data & BIT64(l_core_relative_pos + CORE_START_POSITION);
        l_l3_clock_State   = l_data & BIT64(l_l3_relative_pos + CACHE_START_POSITION);

        //Verify core is powered on
        //If core is powered on
        //  then if core(ECl2) clocks are on
        //      then need to purge the l2 and stop the core clocks
        //  if L3 clocks are on
        //      then purge L3 and stop the l3 clocks
        //  Power off the core and L3
        if( l_pfet_sense)
        {
            if (!l_core_clock_State)
            {
                FAPI_TRY(p10_hcd_l2_purge(i_core_target));
                FAPI_TRY(p10_hcd_l2_tlbie_quiesce(i_core_target));
                FAPI_TRY(p10_hcd_ncu_purge(i_core_target));
                FAPI_TRY(p10_hcd_core_shadows_disable(i_core_target));
                FAPI_TRY(p10_hcd_core_stopclocks(i_core_target));
                FAPI_TRY(p10_hcd_core_stopgrid(i_core_target));
            }

            FAPI_TRY(p10_hcd_core_poweroff(i_core_target));

            if (!l_l3_clock_State)
            {
                FAPI_TRY(p10_hcd_chtm_purge(i_core_target));
                FAPI_TRY(p10_hcd_l3_purge(i_core_target));
                FAPI_TRY(p10_hcd_powerbus_purge(i_core_target));
                FAPI_TRY(p10_hcd_cache_stopclocks(i_core_target));
            }

            FAPI_TRY(p10_hcd_cache_poweroff(i_core_target));
        }
    }
    while(0);

fapi_try_exit:
    FAPI_INF("< p10_check_core_clock_power_state...");
    return fapi2::current_err;

}
<commit_msg>Make p10_update_ec_state match header prototype<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/pm/p10_update_ec_state.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019,2022                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/// @file  p10_update_ec_state.C
/// @brief Update the core configured data in CCSR register and then deals with
///        deconfigured cores to verify the chiplet state..if it is still running then
///        will put the core to stop 11 state
///
/// *HWP HW Owner        : Greg Still <stillgs@us.ibm.com>
/// *HWP FW Owner        : Prasad Bg Ranganath <prasadbgr@in.ibm.com>
/// *HWP Team            : PM
/// *HWP Level           : 2
/// *HWP Consumed by     : HB,PGPE,CME,OCC
///

// -----------------------------------------------------------------------------
//  Includes
// -----------------------------------------------------------------------------
#include "p10_update_ec_state.H"
#include "p10_hcd_common.H"
#include "p10_hcd_cache_stopclocks.H"
#include "p10_hcd_core_poweroff.H"
#include "p10_hcd_l3_purge.H"
#include "p10_hcd_l2_purge.H"
#include "p10_hcd_powerbus_purge.H"
#include "p10_hcd_l2_tlbie_quiesce.H"
#include "p10_hcd_ncu_purge.H"
#include "p10_hcd_chtm_purge.H"
#include "p10_hcd_core_stopclocks.H"
#include "p10_hcd_cache_poweroff.H"
#include "p10_hcd_core_shadows_disable.H"
#include "p10_hcd_core_stopgrid.H"
#include <p10_scom_proc.H>
#include <p10_scom_c.H>
#include <p10_scom_eq.H>

using namespace scomt;
using namespace proc;
using namespace c;
using namespace eq;

// -----------------------------------------------------------------------------
//  Function prototypes
// -----------------------------------------------------------------------------
static fapi2::ReturnCode update_ec_config(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target);

fapi2::ReturnCode verify_ec_hw_state(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target);

fapi2::ReturnCode p10_check_core_l3_clock_power_state(
    const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_core_target,
    uint8_t i_core_unit_pos);

// -----------------------------------------------------------------------------
//  Constants
// -----------------------------------------------------------------------------

// See .H for documentation
fapi2::ReturnCode p10_update_ec_state(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{

    FAPI_IMP("> p10_update_ec_state");

    FAPI_TRY(update_ec_config(i_target),
             "Error update_core_config detected");
    //TODO Need to find the right way to get deconfigured target
    FAPI_TRY(verify_ec_hw_state(i_target));

fapi_try_exit:
    FAPI_INF("< p10_update_ec_state");

    return fapi2::current_err;
} // END p10_update_ec_state

fapi2::ReturnCode verify_ec_hw_state(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_INF (">>verify_hw_state");
#if 0
    uint8_t l_present_core_unit_pos;
    uint8_t l_functional_core_unit_pos;

    uint8_t l_core_match = 0;

    //Get the perv target lists
    auto l_core_present_target_vector = i_target.getChildren<fapi2::TARGET_TYPE_CORE>(
                                            fapi2::TARGET_STATE_PRESENT);

    //Get the functional lists
    auto l_core_functional_vector =
        i_target.getChildren<fapi2::TARGET_TYPE_CORE>
        (fapi2::TARGET_STATE_FUNCTIONAL);

    //Verify Core state
    for (auto core_present_it : l_core_present_target_vector)
    {
        FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS,
                                core_present_it,
                                l_present_core_unit_pos));

        l_core_match = 1;

        FAPI_INF("Present core %d ", l_present_core_unit_pos);

        for (auto core_functional_it : l_core_functional_vector)
        {
            FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS,
                                    core_functional_it,
                                    l_functional_core_unit_pos));
            FAPI_INF("  Functional EC %d",
                     l_functional_core_unit_pos);

            if (l_functional_core_unit_pos == l_present_core_unit_pos)
            {
                l_core_match = 1;
                break;
            }
            else
            {
                l_core_match = 0;
            }
        }//end of functional

        if (!l_core_match)
        {
            for ( auto l_core_target : core_present_it.getChildren<fapi2::TARGET_TYPE_CORE>(fapi2::TARGET_STATE_PRESENT) )
            {
                FAPI_INF("Core present but non functional %d",
                         l_present_core_unit_pos);

                //Check the clock state and power state
                FAPI_TRY(p10_check_core_l3_clock_power_state(l_core_target, l_present_core_unit_pos));

            }
        }
    }//end of present

fapi_try_exit:
#endif
    FAPI_INF("< update_core_config...");
    return fapi2::current_err;

}

/// @brief Update the CCSR for cores
///
/// @param[in]     i_target   Reference to TARGET_TYPE_PROC_CHIP target
/// @return  FAPI2_RC_SUCCESS if success, else error code.
static fapi2::ReturnCode update_ec_config(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_INF("> update_core_config...");

    uint8_t l_present_core_unit_pos;
    uint8_t l_functional_core_unit_pos;
    fapi2::buffer<uint64_t> l_core_config = 0;
    fapi2::buffer<uint64_t> l_pscom_config = 0;

    auto l_core_present_vector =
        i_target.getChildren<fapi2::TARGET_TYPE_CORE>
        (fapi2::TARGET_STATE_PRESENT);

    auto l_core_functional_vector =
        i_target.getChildren<fapi2::TARGET_TYPE_CORE>
        (fapi2::TARGET_STATE_FUNCTIONAL);

    FAPI_INF("  Number of present cores = %d; Number of functional cores = %d",
             l_core_present_vector.size(),
             l_core_functional_vector.size());

    // For each present core,  set multicast groups and the CCSR
    for (auto core_present_it : l_core_present_vector)
    {
        FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS,
                                core_present_it,
                                l_present_core_unit_pos));

        FAPI_INF("  Checking if present EC %d is functional",
                 l_present_core_unit_pos);

        for (auto core_functional_it : l_core_functional_vector)
        {
            FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS,
                                    core_functional_it,
                                    l_functional_core_unit_pos));
            FAPI_DBG("  Functional EC %d",
                     l_functional_core_unit_pos);

            if (l_functional_core_unit_pos == l_present_core_unit_pos)
            {
                // Set the appropriate bit in the Core Configuration Status
                // Register buffer
                FAPI_INF("  Setting EC %d as good in value to be written to CCSR",
                         l_present_core_unit_pos);
                l_core_config.setBit(l_present_core_unit_pos);

                auto l_eq = core_functional_it.getParent<fapi2::TARGET_TYPE_EQ>();

                l_present_core_unit_pos = l_present_core_unit_pos % 4;

                //Update the pscom enable bit
                l_pscom_config.setBit(l_present_core_unit_pos + 5);

                FAPI_TRY(fapi2::putScom(l_eq, CPLT_CTRL3_WO_OR, l_pscom_config));
                break;
            }  // Current core
        } // Functional core loop
    }  // Present core loop

    // Write the recalculated OCC Core Configuration Status Register
    FAPI_INF("  Writing OCC CCSR");
    FAPI_TRY(fapi2::putScom(i_target, TP_TPCHIP_OCC_OCI_OCB_CCSR_RW, l_core_config));

fapi_try_exit:
    FAPI_INF("< update_core_config...");
    return fapi2::current_err;

}

#define CORE_START_POSITION 5
#define CACHE_START_POSITION 9

fapi2::ReturnCode p10_check_core_l3_clock_power_state(
    const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_core_target,
    uint8_t i_core_unit_pos)
{
    fapi2::buffer<uint64_t> l_data = 0;
    uint64_t l_pfet_sense = 0;
    uint8_t l_core_relative_pos  = i_core_unit_pos % 4;
    uint8_t l_l3_relative_pos    = i_core_unit_pos % 4;
    uint8_t l_core_clock_State = 0;
    uint8_t l_l3_clock_State = 0;

    do
    {
        auto l_eq_target = i_core_target.getParent<fapi2::TARGET_TYPE_EQ>();
        //Read the power state of core/l2
        FAPI_TRY(GET_CPMS_CL2_PFETSTAT(i_core_target, l_data));
        GET_CPMS_CL2_PFETSTAT_VDD_PFETS_ENABLED_SENSE(l_data, l_pfet_sense);

        //verify L3/core clocks are on
        FAPI_TRY(GET_CLOCK_STAT_SL(l_eq_target, l_data));
        l_core_clock_State = l_data & BIT64(l_core_relative_pos + CORE_START_POSITION);
        l_l3_clock_State   = l_data & BIT64(l_l3_relative_pos + CACHE_START_POSITION);

        //Verify core is powered on
        //If core is powered on
        //  then if core(ECl2) clocks are on
        //      then need to purge the l2 and stop the core clocks
        //  if L3 clocks are on
        //      then purge L3 and stop the l3 clocks
        //  Power off the core and L3
        if( l_pfet_sense)
        {
            if (!l_core_clock_State)
            {
                FAPI_TRY(p10_hcd_l2_purge(i_core_target));
                FAPI_TRY(p10_hcd_l2_tlbie_quiesce(i_core_target));
                FAPI_TRY(p10_hcd_ncu_purge(i_core_target));
                FAPI_TRY(p10_hcd_core_shadows_disable(i_core_target));
                FAPI_TRY(p10_hcd_core_stopclocks(i_core_target));
                FAPI_TRY(p10_hcd_core_stopgrid(i_core_target));
            }

            FAPI_TRY(p10_hcd_core_poweroff(i_core_target));

            if (!l_l3_clock_State)
            {
                FAPI_TRY(p10_hcd_chtm_purge(i_core_target));
                FAPI_TRY(p10_hcd_l3_purge(i_core_target));
                FAPI_TRY(p10_hcd_powerbus_purge(i_core_target));
                FAPI_TRY(p10_hcd_cache_stopclocks(i_core_target));
            }

            FAPI_TRY(p10_hcd_cache_poweroff(i_core_target));
        }
    }
    while(0);

fapi_try_exit:
    FAPI_INF("< p10_check_core_clock_power_state...");
    return fapi2::current_err;

}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 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 "autopilot_tester.h"
#include <chrono>

TEST_CASE("Offboard takeoff and land", "[multicopter][offboard]")
{
	AutopilotTester tester;
	Offboard::PositionNedYaw takeoff_position {0.0f, 0.0f, -2.0f, 0.0f};
	tester.connect(connection_url);
	tester.wait_until_ready();
	tester.store_home();
	tester.arm();
	std::chrono::seconds goto_timeout = std::chrono::seconds(90);
	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
	tester.offboard_land();
	tester.wait_until_disarmed(std::chrono::seconds(120));
	tester.check_home_within(1.0f);
}

TEST_CASE("Offboard position control", "[multicopter][offboard]")
{
	AutopilotTester tester;
	Offboard::PositionNedYaw takeoff_position {0.0f, 0.0f, -2.0f, 0.0f};
	Offboard::PositionNedYaw setpoint_1 {0.0f, 5.0f, -2.0f, 180.0f};
	Offboard::PositionNedYaw setpoint_2 {5.0f, 5.0f, -4.0f, 180.0f};
	Offboard::PositionNedYaw setpoint_3 {5.0f, 0.0f, -4.0f, 90.0f};
	tester.connect(connection_url);
	tester.wait_until_ready();
	tester.store_home();
	tester.arm();
	std::chrono::seconds goto_timeout = std::chrono::seconds(90);
	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
	tester.offboard_goto(setpoint_1, 0.1f, goto_timeout);
	tester.offboard_goto(setpoint_2, 0.1f, goto_timeout);
	tester.offboard_goto(setpoint_3, 0.1f, goto_timeout);
	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
	tester.offboard_land();
	tester.wait_until_disarmed(std::chrono::seconds(120));
	tester.check_home_within(1.0f);
}
<commit_msg>mavsdk_tests: fix timeout at 1x speed<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 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 "autopilot_tester.h"
#include <chrono>

TEST_CASE("Offboard takeoff and land", "[multicopter][offboard]")
{
	AutopilotTester tester;
	Offboard::PositionNedYaw takeoff_position {0.0f, 0.0f, -2.0f, 0.0f};
	tester.connect(connection_url);
	tester.wait_until_ready();
	tester.store_home();
	tester.arm();
	std::chrono::seconds goto_timeout = std::chrono::seconds(90);
	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
	tester.offboard_land();
	tester.wait_until_disarmed(std::chrono::seconds(120));
	tester.check_home_within(1.0f);
}

TEST_CASE("Offboard position control", "[multicopter][offboard]")
{
	AutopilotTester tester;
	Offboard::PositionNedYaw takeoff_position {0.0f, 0.0f, -2.0f, 0.0f};
	Offboard::PositionNedYaw setpoint_1 {0.0f, 5.0f, -2.0f, 180.0f};
	Offboard::PositionNedYaw setpoint_2 {5.0f, 5.0f, -4.0f, 180.0f};
	Offboard::PositionNedYaw setpoint_3 {5.0f, 0.0f, -4.0f, 90.0f};
	tester.connect(connection_url);
	tester.wait_until_ready();
	tester.store_home();
	tester.arm();
	std::chrono::seconds goto_timeout = std::chrono::seconds(120);
	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
	tester.offboard_goto(setpoint_1, 0.1f, goto_timeout);
	tester.offboard_goto(setpoint_2, 0.1f, goto_timeout);
	tester.offboard_goto(setpoint_3, 0.1f, goto_timeout);
	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
	tester.offboard_land();
	tester.wait_until_disarmed(std::chrono::seconds(120));
	tester.check_home_within(1.0f);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2013 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * 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: Thomas Grass
 *          Andreas Hansson
 *          Sascha Bischoff
 */

#include <sstream>

#include "base/random.hh"
#include "cpu/testers/traffic_gen/traffic_gen.hh"
#include "debug/Checkpoint.hh"
#include "debug/TrafficGen.hh"
#include "sim/stats.hh"
#include "sim/system.hh"

using namespace std;

TrafficGen::TrafficGen(const TrafficGenParams* p)
    : MemObject(p),
      system(p->system),
      masterID(system->getMasterId(name())),
      configFile(p->config_file),
      elasticReq(p->elastic_req),
      nextTransitionTick(0),
      nextPacketTick(0),
      port(name() + ".port", *this),
      retryPkt(NULL),
      retryPktTick(0),
      updateEvent(this),
      drainManager(NULL)
{
}

TrafficGen*
TrafficGenParams::create()
{
    return new TrafficGen(this);
}

BaseMasterPort&
TrafficGen::getMasterPort(const string& if_name, PortID idx)
{
    if (if_name == "port") {
        return port;
    } else {
        return MemObject::getMasterPort(if_name, idx);
    }
}

void
TrafficGen::init()
{
    if (!port.isConnected())
        fatal("The port of %s is not connected!\n", name());

    // if the system is in timing mode active the request generator
    if (system->isTimingMode()) {
        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");

        parseConfig();

        // enter initial state
        enterState(currState);
    } else {
        DPRINTF(TrafficGen,
                "Traffic generator is only active in timing mode\n");
    }
}

void
TrafficGen::initState()
{
    // when not restoring from a checkpoint, make sure we kick things off
    if (system->isTimingMode()) {
        // call nextPacketTick on the state to advance it
        nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
        schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick));
    } else {
        DPRINTF(TrafficGen,
                "Traffic generator is only active in timing mode\n");
    }
}

unsigned int
TrafficGen::drain(DrainManager *dm)
{
    if (!updateEvent.scheduled()) {
        // no event has been scheduled yet (e.g. switched from atomic mode)
        return 0;
    }

    if (retryPkt == NULL) {
        // shut things down
        nextPacketTick = MaxTick;
        nextTransitionTick = MaxTick;
        deschedule(updateEvent);
        return 0;
    } else {
        drainManager = dm;
        return 1;
    }
}

void
TrafficGen::serialize(ostream &os)
{
    DPRINTF(Checkpoint, "Serializing TrafficGen\n");

    // save ticks of the graph event if it is scheduled
    Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;

    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);

    SERIALIZE_SCALAR(nextEvent);

    SERIALIZE_SCALAR(nextTransitionTick);

    SERIALIZE_SCALAR(nextPacketTick);

    SERIALIZE_SCALAR(currState);
}

void
TrafficGen::unserialize(Checkpoint* cp, const string& section)
{
    // restore scheduled events
    Tick nextEvent;
    UNSERIALIZE_SCALAR(nextEvent);
    if (nextEvent != 0) {
        schedule(updateEvent, nextEvent);
    }

    UNSERIALIZE_SCALAR(nextTransitionTick);

    UNSERIALIZE_SCALAR(nextPacketTick);

    // @todo In the case of a stateful generator state such as the
    // trace player we would also have to restore the position in the
    // trace playback and the tick offset
    UNSERIALIZE_SCALAR(currState);
}

void
TrafficGen::update()
{
    // if we have reached the time for the next state transition, then
    // perform the transition
    if (curTick() >= nextTransitionTick) {
        transition();
    } else {
        assert(curTick() >= nextPacketTick);
        // get the next packet and try to send it
        PacketPtr pkt = states[currState]->getNextPacket();
        numPackets++;
        if (!port.sendTimingReq(pkt)) {
            retryPkt = pkt;
            retryPktTick = curTick();
        }
    }

    // if we are waiting for a retry, do not schedule any further
    // events, in the case of a transition or a successful send, go
    // ahead and determine when the next update should take place
    if (retryPkt == NULL) {
        // schedule next update event based on either the next execute
        // tick or the next transition, which ever comes first
        nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
        Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
        DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
        schedule(updateEvent, nextEventTick);
    }
}

void
TrafficGen::parseConfig()
{
    // keep track of the transitions parsed to create the matrix when
    // done
    vector<Transition> transitions;

    // open input file
    ifstream infile;
    infile.open(configFile.c_str(), ifstream::in);
    if (!infile.is_open()) {
        fatal("Traffic generator %s config file not found at %s\n",
              name(), configFile);
    }

    // read line by line and determine the action based on the first
    // keyword
    string keyword;
    string line;

    while (getline(infile, line).good()) {
        // see if this line is a comment line, and if so skip it
        if (line.find('#') != 1) {
            // create an input stream for the tokenization
            istringstream is(line);

            // determine the keyword
            is >> keyword;

            if (keyword == "STATE") {
                // parse the behaviour of this state
                uint32_t id;
                Tick duration;
                string mode;

                is >> id >> duration >> mode;

                if (mode == "TRACE") {
                    string traceFile;
                    Addr addrOffset;

                    is >> traceFile >> addrOffset;

                    states[id] = new TraceGen(name(), masterID, duration,
                                              traceFile, addrOffset);
                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
                } else if (mode == "IDLE") {
                    states[id] = new IdleGen(name(), masterID, duration);
                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
                } else if (mode == "LINEAR" || mode == "RANDOM") {
                    uint32_t read_percent;
                    Addr start_addr;
                    Addr end_addr;
                    Addr blocksize;
                    Tick min_period;
                    Tick max_period;
                    Addr data_limit;

                    is >> read_percent >> start_addr >> end_addr >>
                        blocksize >> min_period >> max_period >> data_limit;

                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
                            " period %d to %d, %d%% reads\n",
                            mode, start_addr, end_addr, blocksize, min_period,
                            max_period, read_percent);

                    if (blocksize > system->cacheLineSize())
                        fatal("TrafficGen %s block size (%d) is larger than "
                              "system block size (%d)\n", name(),
                              blocksize, system->cacheLineSize());

                    if (read_percent > 100)
                        fatal("%s cannot have more than 100% reads", name());

                    if (min_period > max_period)
                        fatal("%s cannot have min_period > max_period", name());

                    if (mode == "LINEAR") {
                        states[id] = new LinearGen(name(), masterID,
                                                   duration, start_addr,
                                                   end_addr, blocksize,
                                                   min_period, max_period,
                                                   read_percent, data_limit);
                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
                    } else if (mode == "RANDOM") {
                        states[id] = new RandomGen(name(), masterID,
                                                   duration, start_addr,
                                                   end_addr, blocksize,
                                                   min_period, max_period,
                                                   read_percent, data_limit);
                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
                    }
                } else {
                    fatal("%s: Unknown traffic generator mode: %s",
                          name(), mode);
                }
            } else if (keyword == "TRANSITION") {
                Transition transition;

                is >> transition.from >> transition.to >> transition.p;

                transitions.push_back(transition);

                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
                        transition.to);
            } else if (keyword == "INIT") {
                // set the initial state as the active state
                is >> currState;

                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
            }
        }
    }

    // resize and populate state transition matrix
    transitionMatrix.resize(states.size());
    for (size_t i = 0; i < states.size(); i++) {
        transitionMatrix[i].resize(states.size());
    }

    for (vector<Transition>::iterator t = transitions.begin();
         t != transitions.end(); ++t) {
        transitionMatrix[t->from][t->to] = t->p;
    }

    // ensure the egress edges do not have a probability larger than
    // one
    for (size_t i = 0; i < states.size(); i++) {
        double sum = 0;
        for (size_t j = 0; j < states.size(); j++) {
            sum += transitionMatrix[i][j];
        }

        // avoid comparing floating point numbers
        if (abs(sum - 1.0) > 0.001)
            fatal("%s has transition probability != 1 for state %d\n",
                  name(), i);
    }

    // close input file
    infile.close();
}

void
TrafficGen::transition()
{
    // exit the current state
    states[currState]->exit();

    // determine next state
    double p = random_mt.gen_real1();
    assert(currState < transitionMatrix.size());
    double cumulative = 0.0;
    size_t i = 0;
    do {
        cumulative += transitionMatrix[currState][i];
        ++i;
    } while (cumulative < p && i < transitionMatrix[currState].size());

    enterState(i - 1);
}

void
TrafficGen::enterState(uint32_t newState)
{
    DPRINTF(TrafficGen, "Transition to state %d\n", newState);

    currState = newState;
    // we could have been delayed and not transitioned on the exact
    // tick when we were supposed to (due to back pressure when
    // sending a packet)
    nextTransitionTick = curTick() + states[currState]->duration;
    states[currState]->enter();
}

void
TrafficGen::recvRetry()
{
    assert(retryPkt != NULL);

    DPRINTF(TrafficGen, "Received retry\n");
    numRetries++;
    // attempt to send the packet, and if we are successful start up
    // the machinery again
    if (port.sendTimingReq(retryPkt)) {
        retryPkt = NULL;
        // remember how much delay was incurred due to back-pressure
        // when sending the request, we also use this to derive
        // the tick for the next packet
        Tick delay = curTick() - retryPktTick;
        retryPktTick = 0;
        retryTicks += delay;

        if (drainManager == NULL) {
            // packet is sent, so find out when the next one is due
            nextPacketTick = states[currState]->nextPacketTick(elasticReq,
                                                               delay);
            Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
            schedule(updateEvent, std::max(curTick(), nextEventTick));
        } else {
            // shut things down
            nextPacketTick = MaxTick;
            nextTransitionTick = MaxTick;
            drainManager->signalDrainDone();
            // Clear the drain event once we're done with it.
            drainManager = NULL;
        }
    }
}

void
TrafficGen::regStats()
{
    // Initialise all the stats
    using namespace Stats;

    numPackets
        .name(name() + ".numPackets")
        .desc("Number of packets generated");

    numRetries
        .name(name() + ".numRetries")
        .desc("Number of retries");

    retryTicks
        .name(name() + ".retryTicks")
        .desc("Time spent waiting due to back-pressure (ticks)");
}

bool
TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
{
    delete pkt->req;
    delete pkt;

    return true;
}
<commit_msg>cpu: Add basic check to TrafficGen initial state<commit_after>/*
 * Copyright (c) 2012-2013 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * 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: Thomas Grass
 *          Andreas Hansson
 *          Sascha Bischoff
 */

#include <sstream>

#include "base/random.hh"
#include "cpu/testers/traffic_gen/traffic_gen.hh"
#include "debug/Checkpoint.hh"
#include "debug/TrafficGen.hh"
#include "sim/stats.hh"
#include "sim/system.hh"

using namespace std;

TrafficGen::TrafficGen(const TrafficGenParams* p)
    : MemObject(p),
      system(p->system),
      masterID(system->getMasterId(name())),
      configFile(p->config_file),
      elasticReq(p->elastic_req),
      nextTransitionTick(0),
      nextPacketTick(0),
      port(name() + ".port", *this),
      retryPkt(NULL),
      retryPktTick(0),
      updateEvent(this),
      drainManager(NULL)
{
}

TrafficGen*
TrafficGenParams::create()
{
    return new TrafficGen(this);
}

BaseMasterPort&
TrafficGen::getMasterPort(const string& if_name, PortID idx)
{
    if (if_name == "port") {
        return port;
    } else {
        return MemObject::getMasterPort(if_name, idx);
    }
}

void
TrafficGen::init()
{
    if (!port.isConnected())
        fatal("The port of %s is not connected!\n", name());

    // if the system is in timing mode active the request generator
    if (system->isTimingMode()) {
        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");

        parseConfig();

        // enter initial state
        enterState(currState);
    } else {
        DPRINTF(TrafficGen,
                "Traffic generator is only active in timing mode\n");
    }
}

void
TrafficGen::initState()
{
    // when not restoring from a checkpoint, make sure we kick things off
    if (system->isTimingMode()) {
        // call nextPacketTick on the state to advance it
        nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
        schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick));
    } else {
        DPRINTF(TrafficGen,
                "Traffic generator is only active in timing mode\n");
    }
}

unsigned int
TrafficGen::drain(DrainManager *dm)
{
    if (!updateEvent.scheduled()) {
        // no event has been scheduled yet (e.g. switched from atomic mode)
        return 0;
    }

    if (retryPkt == NULL) {
        // shut things down
        nextPacketTick = MaxTick;
        nextTransitionTick = MaxTick;
        deschedule(updateEvent);
        return 0;
    } else {
        drainManager = dm;
        return 1;
    }
}

void
TrafficGen::serialize(ostream &os)
{
    DPRINTF(Checkpoint, "Serializing TrafficGen\n");

    // save ticks of the graph event if it is scheduled
    Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;

    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);

    SERIALIZE_SCALAR(nextEvent);

    SERIALIZE_SCALAR(nextTransitionTick);

    SERIALIZE_SCALAR(nextPacketTick);

    SERIALIZE_SCALAR(currState);
}

void
TrafficGen::unserialize(Checkpoint* cp, const string& section)
{
    // restore scheduled events
    Tick nextEvent;
    UNSERIALIZE_SCALAR(nextEvent);
    if (nextEvent != 0) {
        schedule(updateEvent, nextEvent);
    }

    UNSERIALIZE_SCALAR(nextTransitionTick);

    UNSERIALIZE_SCALAR(nextPacketTick);

    // @todo In the case of a stateful generator state such as the
    // trace player we would also have to restore the position in the
    // trace playback and the tick offset
    UNSERIALIZE_SCALAR(currState);
}

void
TrafficGen::update()
{
    // if we have reached the time for the next state transition, then
    // perform the transition
    if (curTick() >= nextTransitionTick) {
        transition();
    } else {
        assert(curTick() >= nextPacketTick);
        // get the next packet and try to send it
        PacketPtr pkt = states[currState]->getNextPacket();
        numPackets++;
        if (!port.sendTimingReq(pkt)) {
            retryPkt = pkt;
            retryPktTick = curTick();
        }
    }

    // if we are waiting for a retry, do not schedule any further
    // events, in the case of a transition or a successful send, go
    // ahead and determine when the next update should take place
    if (retryPkt == NULL) {
        // schedule next update event based on either the next execute
        // tick or the next transition, which ever comes first
        nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
        Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
        DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
        schedule(updateEvent, nextEventTick);
    }
}

void
TrafficGen::parseConfig()
{
    // keep track of the transitions parsed to create the matrix when
    // done
    vector<Transition> transitions;

    // open input file
    ifstream infile;
    infile.open(configFile.c_str(), ifstream::in);
    if (!infile.is_open()) {
        fatal("Traffic generator %s config file not found at %s\n",
              name(), configFile);
    }

    bool init_state_set = false;

    // read line by line and determine the action based on the first
    // keyword
    string keyword;
    string line;

    while (getline(infile, line).good()) {
        // see if this line is a comment line, and if so skip it
        if (line.find('#') != 1) {
            // create an input stream for the tokenization
            istringstream is(line);

            // determine the keyword
            is >> keyword;

            if (keyword == "STATE") {
                // parse the behaviour of this state
                uint32_t id;
                Tick duration;
                string mode;

                is >> id >> duration >> mode;

                if (mode == "TRACE") {
                    string traceFile;
                    Addr addrOffset;

                    is >> traceFile >> addrOffset;

                    states[id] = new TraceGen(name(), masterID, duration,
                                              traceFile, addrOffset);
                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
                } else if (mode == "IDLE") {
                    states[id] = new IdleGen(name(), masterID, duration);
                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
                } else if (mode == "LINEAR" || mode == "RANDOM") {
                    uint32_t read_percent;
                    Addr start_addr;
                    Addr end_addr;
                    Addr blocksize;
                    Tick min_period;
                    Tick max_period;
                    Addr data_limit;

                    is >> read_percent >> start_addr >> end_addr >>
                        blocksize >> min_period >> max_period >> data_limit;

                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
                            " period %d to %d, %d%% reads\n",
                            mode, start_addr, end_addr, blocksize, min_period,
                            max_period, read_percent);

                    if (blocksize > system->cacheLineSize())
                        fatal("TrafficGen %s block size (%d) is larger than "
                              "system block size (%d)\n", name(),
                              blocksize, system->cacheLineSize());

                    if (read_percent > 100)
                        fatal("%s cannot have more than 100% reads", name());

                    if (min_period > max_period)
                        fatal("%s cannot have min_period > max_period", name());

                    if (mode == "LINEAR") {
                        states[id] = new LinearGen(name(), masterID,
                                                   duration, start_addr,
                                                   end_addr, blocksize,
                                                   min_period, max_period,
                                                   read_percent, data_limit);
                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
                    } else if (mode == "RANDOM") {
                        states[id] = new RandomGen(name(), masterID,
                                                   duration, start_addr,
                                                   end_addr, blocksize,
                                                   min_period, max_period,
                                                   read_percent, data_limit);
                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
                    }
                } else {
                    fatal("%s: Unknown traffic generator mode: %s",
                          name(), mode);
                }
            } else if (keyword == "TRANSITION") {
                Transition transition;

                is >> transition.from >> transition.to >> transition.p;

                transitions.push_back(transition);

                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
                        transition.to);
            } else if (keyword == "INIT") {
                // set the initial state as the active state
                is >> currState;

                init_state_set = true;

                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
            }
        }
    }

    if (!init_state_set)
        fatal("%s: initial state not specified (add 'INIT <id>' line "
              "to the config file)\n", name());

    // resize and populate state transition matrix
    transitionMatrix.resize(states.size());
    for (size_t i = 0; i < states.size(); i++) {
        transitionMatrix[i].resize(states.size());
    }

    for (vector<Transition>::iterator t = transitions.begin();
         t != transitions.end(); ++t) {
        transitionMatrix[t->from][t->to] = t->p;
    }

    // ensure the egress edges do not have a probability larger than
    // one
    for (size_t i = 0; i < states.size(); i++) {
        double sum = 0;
        for (size_t j = 0; j < states.size(); j++) {
            sum += transitionMatrix[i][j];
        }

        // avoid comparing floating point numbers
        if (abs(sum - 1.0) > 0.001)
            fatal("%s has transition probability != 1 for state %d\n",
                  name(), i);
    }

    // close input file
    infile.close();
}

void
TrafficGen::transition()
{
    // exit the current state
    states[currState]->exit();

    // determine next state
    double p = random_mt.gen_real1();
    assert(currState < transitionMatrix.size());
    double cumulative = 0.0;
    size_t i = 0;
    do {
        cumulative += transitionMatrix[currState][i];
        ++i;
    } while (cumulative < p && i < transitionMatrix[currState].size());

    enterState(i - 1);
}

void
TrafficGen::enterState(uint32_t newState)
{
    DPRINTF(TrafficGen, "Transition to state %d\n", newState);

    currState = newState;
    // we could have been delayed and not transitioned on the exact
    // tick when we were supposed to (due to back pressure when
    // sending a packet)
    nextTransitionTick = curTick() + states[currState]->duration;
    states[currState]->enter();
}

void
TrafficGen::recvRetry()
{
    assert(retryPkt != NULL);

    DPRINTF(TrafficGen, "Received retry\n");
    numRetries++;
    // attempt to send the packet, and if we are successful start up
    // the machinery again
    if (port.sendTimingReq(retryPkt)) {
        retryPkt = NULL;
        // remember how much delay was incurred due to back-pressure
        // when sending the request, we also use this to derive
        // the tick for the next packet
        Tick delay = curTick() - retryPktTick;
        retryPktTick = 0;
        retryTicks += delay;

        if (drainManager == NULL) {
            // packet is sent, so find out when the next one is due
            nextPacketTick = states[currState]->nextPacketTick(elasticReq,
                                                               delay);
            Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
            schedule(updateEvent, std::max(curTick(), nextEventTick));
        } else {
            // shut things down
            nextPacketTick = MaxTick;
            nextTransitionTick = MaxTick;
            drainManager->signalDrainDone();
            // Clear the drain event once we're done with it.
            drainManager = NULL;
        }
    }
}

void
TrafficGen::regStats()
{
    // Initialise all the stats
    using namespace Stats;

    numPackets
        .name(name() + ".numPackets")
        .desc("Number of packets generated");

    numRetries
        .name(name() + ".numRetries")
        .desc("Number of retries");

    retryTicks
        .name(name() + ".retryTicks")
        .desc("Time spent waiting due to back-pressure (ticks)");
}

bool
TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
{
    delete pkt->req;
    delete pkt;

    return true;
}
<|endoftext|>


<commit_before>// @(#):$Id$
// Author: Andrei Gheata   01/03/11

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

////////////////////////////////////////////////////////////////////////////
//
// TGeoBranchArray - An array of daughter indices making a geometry path.
//   Can be used to backup/restore a state. To setup an object of this type,
// one should use:
//   TGeoBranchArray *array = new TGeoBranchArray(level);
//   array->InitFromNavigator(nav); (To initialize from current navigator state)
// The navigator can be updated to reflect this path array:
//   array->UpdateNavigator();
//
/////////////////////////////////////////////////////////////////////////////

#include "TGeoBranchArray.h"

#include "TMath.h"
#include "TThread.h"
#include "TString.h"
#include "TGeoMatrix.h"
#include "TGeoNavigator.h"
#include "TGeoManager.h"

ClassImp(TGeoBranchArray)

//______________________________________________________________________________
TGeoBranchArray::TGeoBranchArray(UShort_t level)
                :fLevel(level),
                 fArray(NULL),
                 fMatrix(NULL),
                 fClient(NULL)
{
// Constructor. Alocates the array with a size given by level.
   fArray = new UShort_t[level];
}

//______________________________________________________________________________
TGeoBranchArray::~TGeoBranchArray()
{
// Destructor.
   delete [] fArray;
   delete fMatrix;
}

//______________________________________________________________________________
TGeoBranchArray::TGeoBranchArray(const TGeoBranchArray&  other)
                :TObject(other),
                 fLevel(other.fLevel),
                 fArray(NULL),
                 fMatrix(NULL),
                 fClient(other.fClient)
{
// Copy constructor.
   if (fLevel) fArray = new UShort_t[fLevel];
   if (other.fMatrix) fMatrix = new TGeoHMatrix(*(other.fMatrix));
}

//______________________________________________________________________________
TGeoBranchArray& TGeoBranchArray::operator=(const TGeoBranchArray& other)
{
// Assignment.
   if (&other == this) return *this;
   fLevel = other.fLevel;
   if (fLevel) fArray = new UShort_t[fLevel];
   if (other.fMatrix) {
      fMatrix = new TGeoHMatrix();
      fMatrix->CopyFrom(other.fMatrix);
   }
   fClient = other.fClient;
   return *this;
}

//______________________________________________________________________________
void TGeoBranchArray::AddLevel(UShort_t dindex)
{
// Add and extra daughter to the current path array. No validity check performed !
   if (!fLevel) {
      Error("AddLevel", "You must initialize from navigator or copy from another branch array first.");
      return;
   }
   fLevel++;
   UShort_t *array = new UShort_t[fLevel];
   memcpy(array, fArray, (fLevel-1)*sizeof(UShort_t));
   array[fLevel-1] = dindex;
   delete [] fArray;
   fArray = array;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator ==(const TGeoBranchArray& other) const
{
// Is equal operator.
   Int_t value = Compare(&other);
   if (value==0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator !=(const TGeoBranchArray& other) const
{
// Not equal operator.
   Int_t value = Compare(&other);
   if (value!=0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator >(const TGeoBranchArray& other) const
{
// Is equal operator.
   Int_t value = Compare(&other);
   if (value>0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator <(const TGeoBranchArray& other) const
{
// Is equal operator.
   Int_t value = Compare(&other);
   if (value<0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator >=(const TGeoBranchArray& other) const
{
// Is equal operator.
   Int_t value = Compare(&other);
   if (value>=0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator <=(const TGeoBranchArray& other) const
{
// Is equal operator.
   Int_t value = Compare(&other);
   if (value<=0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Long64_t TGeoBranchArray::BinarySearch(Long64_t n, const TGeoBranchArray **array, TGeoBranchArray *value)
{
// Binary search in an array of n pointers to branch arrays, to locate value.
// Returns element index or index of nearest element smaller than value
   Long64_t nabove, nbelow, middle;
   const TGeoBranchArray *pind;
   nabove = n+1;
   nbelow = 0;
   while(nabove-nbelow > 1) {
      middle = (nabove+nbelow)/2;
      pind = array[middle-1];
      if (*value == *pind) return middle-1;
      if (*value  < *pind) nabove = middle;
      else                          nbelow = middle;
   }
   return nbelow-1;
}

//______________________________________________________________________________
Int_t TGeoBranchArray::Compare(const TObject *obj) const
{
// Compare with other object of same type. Returns -1 if this is smaller (first
// smaller array value prevails), 0 if equal (size and values) and 1 if this is
// larger.
   UShort_t i;
   TGeoBranchArray *other = (TGeoBranchArray*)obj;
   UShort_t otherLevel = other->GetLevel();
   UShort_t maxLevel = TMath::Min(fLevel, otherLevel);
   UShort_t *otherArray = other->GetArray();
   for (i=0; i<maxLevel; i++) {
      if (fArray[i]==otherArray[i]) continue;
      if (fArray[i]<otherArray[i]) return -1;
      return 1;
   }
   if (fLevel==otherLevel) return 0;
   if (fLevel<otherLevel) return -1;
   return 1;
}

//______________________________________________________________________________
void TGeoBranchArray::CleanMatrix()
{
// Garbage collect the stored matrix.
   delete fMatrix; fMatrix = 0;
}

//______________________________________________________________________________
TGeoNode *TGeoBranchArray::GetNode(UShort_t level) const
{
   TGeoNode *node = gGeoManager->GetTopNode();
   if (!level) return node;
   if (level>fLevel) return NULL;
   for (Int_t i=0; i<level; i++) node = node->GetVolume()->GetNode(fArray[i]);
   return node;
}

//______________________________________________________________________________
void TGeoBranchArray::InitFromNavigator(TGeoNavigator *nav)
{
// Init the branch array from current navigator state.
   TThread::Lock();
   UShort_t level = (UShort_t)nav->GetLevel();
   if (!fMatrix) fMatrix = new TGeoHMatrix();
   fMatrix->CopyFrom(nav->GetCurrentMatrix());
   if (!level) {
//      delete [] fArray; fArray = 0;
      fLevel = 0;
      return;
   }
   if (!fArray || level>fLevel) {
      delete [] fArray;
      fArray = new UShort_t[level];
   }
   fLevel = level;
   TGeoNode *mother = nav->GetMother(fLevel);
   for (Int_t i=fLevel-1; i>=0; i--) {
      TGeoNode *node = nav->GetMother(i);
      Int_t index = mother->GetVolume()->GetIndex(node);
      fArray[fLevel-i-1] = index;
      mother = node;
   }
   TThread::UnLock();
}

//______________________________________________________________________________
void TGeoBranchArray::GetPath(TString &path) const
{
// Fill path pointed by the array.
   path = "/";
   TGeoNode *node = GetNode(0);
   path += node->GetName();
   for (Int_t i=0; i<fLevel; i++) {
      path += "/";
      node = node->GetVolume()->GetNode(fArray[i]);
      path += node->GetName();
   }
}

//______________________________________________________________________________
void TGeoBranchArray::Print(Option_t *) const
{
// Print branch information
   TString path;
   GetPath(path);
   printf("branch:    %s\n", path.Data());
}

//______________________________________________________________________________
void TGeoBranchArray::Sort(Int_t n, TGeoBranchArray **array, Int_t *index, Bool_t down)
{
// Sorting of an array of branch array pointers.
   for (Int_t i=0; i<n; i++) index[i] = i;
   if (down)
      std::sort(index, index + n, compareBAdesc(array));
   else
      std::sort(index, index + n, compareBAasc(array));
}

//______________________________________________________________________________
void TGeoBranchArray::UpdateNavigator(TGeoNavigator *nav) const
{
// Update the navigator to reflect the branch.
   nav->CdTop();
   for (Int_t i=0; i<fLevel; i++) nav->CdDown(fArray[i]);
}
<commit_msg>Fix deadlock in TGeoBranchArray<commit_after>// @(#):$Id$
// Author: Andrei Gheata   01/03/11

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

////////////////////////////////////////////////////////////////////////////
//
// TGeoBranchArray - An array of daughter indices making a geometry path.
//   Can be used to backup/restore a state. To setup an object of this type,
// one should use:
//   TGeoBranchArray *array = new TGeoBranchArray(level);
//   array->InitFromNavigator(nav); (To initialize from current navigator state)
// The navigator can be updated to reflect this path array:
//   array->UpdateNavigator();
//
/////////////////////////////////////////////////////////////////////////////

#include "TGeoBranchArray.h"

#include "TMath.h"
#include "TThread.h"
#include "TString.h"
#include "TGeoMatrix.h"
#include "TGeoNavigator.h"
#include "TGeoManager.h"

ClassImp(TGeoBranchArray)

//______________________________________________________________________________
TGeoBranchArray::TGeoBranchArray(UShort_t level)
                :fLevel(level),
                 fArray(NULL),
                 fMatrix(NULL),
                 fClient(NULL)
{
// Constructor. Alocates the array with a size given by level.
   fArray = new UShort_t[level];
}

//______________________________________________________________________________
TGeoBranchArray::~TGeoBranchArray()
{
// Destructor.
   delete [] fArray;
   delete fMatrix;
}

//______________________________________________________________________________
TGeoBranchArray::TGeoBranchArray(const TGeoBranchArray&  other)
                :TObject(other),
                 fLevel(other.fLevel),
                 fArray(NULL),
                 fMatrix(NULL),
                 fClient(other.fClient)
{
// Copy constructor.
   if (fLevel) fArray = new UShort_t[fLevel];
   if (other.fMatrix) fMatrix = new TGeoHMatrix(*(other.fMatrix));
}

//______________________________________________________________________________
TGeoBranchArray& TGeoBranchArray::operator=(const TGeoBranchArray& other)
{
// Assignment.
   if (&other == this) return *this;
   TThread::Lock();
   fLevel = other.fLevel;
   if (fLevel) fArray = new UShort_t[fLevel];
   if (other.fMatrix) {
      fMatrix = new TGeoHMatrix();
      fMatrix->CopyFrom(other.fMatrix);
   }
   fClient = other.fClient;
   TThread::UnLock();
   return *this;
}

//______________________________________________________________________________
void TGeoBranchArray::AddLevel(UShort_t dindex)
{
// Add and extra daughter to the current path array. No validity check performed !
   if (!fLevel) {
      Error("AddLevel", "You must initialize from navigator or copy from another branch array first.");
      return;
   }
   fLevel++;
   UShort_t *array = new UShort_t[fLevel];
   memcpy(array, fArray, (fLevel-1)*sizeof(UShort_t));
   array[fLevel-1] = dindex;
   delete [] fArray;
   fArray = array;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator ==(const TGeoBranchArray& other) const
{
// Is equal operator.
   Int_t value = Compare(&other);
   if (value==0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator !=(const TGeoBranchArray& other) const
{
// Not equal operator.
   Int_t value = Compare(&other);
   if (value!=0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator >(const TGeoBranchArray& other) const
{
// Is equal operator.
   Int_t value = Compare(&other);
   if (value>0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator <(const TGeoBranchArray& other) const
{
// Is equal operator.
   Int_t value = Compare(&other);
   if (value<0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator >=(const TGeoBranchArray& other) const
{
// Is equal operator.
   Int_t value = Compare(&other);
   if (value>=0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGeoBranchArray::operator <=(const TGeoBranchArray& other) const
{
// Is equal operator.
   Int_t value = Compare(&other);
   if (value<=0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Long64_t TGeoBranchArray::BinarySearch(Long64_t n, const TGeoBranchArray **array, TGeoBranchArray *value)
{
// Binary search in an array of n pointers to branch arrays, to locate value.
// Returns element index or index of nearest element smaller than value
   Long64_t nabove, nbelow, middle;
   const TGeoBranchArray *pind;
   nabove = n+1;
   nbelow = 0;
   while(nabove-nbelow > 1) {
      middle = (nabove+nbelow)/2;
      pind = array[middle-1];
      if (*value == *pind) return middle-1;
      if (*value  < *pind) nabove = middle;
      else                          nbelow = middle;
   }
   return nbelow-1;
}

//______________________________________________________________________________
Int_t TGeoBranchArray::Compare(const TObject *obj) const
{
// Compare with other object of same type. Returns -1 if this is smaller (first
// smaller array value prevails), 0 if equal (size and values) and 1 if this is
// larger.
   UShort_t i;
   TGeoBranchArray *other = (TGeoBranchArray*)obj;
   UShort_t otherLevel = other->GetLevel();
   UShort_t maxLevel = TMath::Min(fLevel, otherLevel);
   UShort_t *otherArray = other->GetArray();
   for (i=0; i<maxLevel; i++) {
      if (fArray[i]==otherArray[i]) continue;
      if (fArray[i]<otherArray[i]) return -1;
      return 1;
   }
   if (fLevel==otherLevel) return 0;
   if (fLevel<otherLevel) return -1;
   return 1;
}

//______________________________________________________________________________
void TGeoBranchArray::CleanMatrix()
{
// Garbage collect the stored matrix.
   delete fMatrix; fMatrix = 0;
}

//______________________________________________________________________________
TGeoNode *TGeoBranchArray::GetNode(UShort_t level) const
{
   TGeoNode *node = gGeoManager->GetTopNode();
   if (!level) return node;
   if (level>fLevel) return NULL;
   for (Int_t i=0; i<level; i++) node = node->GetVolume()->GetNode(fArray[i]);
   return node;
}

//______________________________________________________________________________
void TGeoBranchArray::InitFromNavigator(TGeoNavigator *nav)
{
// Init the branch array from current navigator state.
   TThread::Lock();
   UShort_t level = (UShort_t)nav->GetLevel();
   if (!fMatrix) fMatrix = new TGeoHMatrix();
   fMatrix->CopyFrom(nav->GetCurrentMatrix());
   if (!level) {
//      delete [] fArray; fArray = 0;
      fLevel = 0;
      TThread::UnLock();
      return;
   }
   if (!fArray || level>fLevel) {
      delete [] fArray;
      fArray = new UShort_t[level];
   }
   fLevel = level;
   TGeoNode *mother = nav->GetMother(fLevel);
   for (Int_t i=fLevel-1; i>=0; i--) {
      TGeoNode *node = nav->GetMother(i);
      Int_t index = mother->GetVolume()->GetIndex(node);
      fArray[fLevel-i-1] = index;
      mother = node;
   }
   TThread::UnLock();
}

//______________________________________________________________________________
void TGeoBranchArray::GetPath(TString &path) const
{
// Fill path pointed by the array.
   path = "/";
   TGeoNode *node = GetNode(0);
   path += node->GetName();
   for (Int_t i=0; i<fLevel; i++) {
      path += "/";
      node = node->GetVolume()->GetNode(fArray[i]);
      path += node->GetName();
   }
}

//______________________________________________________________________________
void TGeoBranchArray::Print(Option_t *) const
{
// Print branch information
   TString path;
   GetPath(path);
   printf("branch:    %s\n", path.Data());
}

//______________________________________________________________________________
void TGeoBranchArray::Sort(Int_t n, TGeoBranchArray **array, Int_t *index, Bool_t down)
{
// Sorting of an array of branch array pointers.
   for (Int_t i=0; i<n; i++) index[i] = i;
   if (down)
      std::sort(index, index + n, compareBAdesc(array));
   else
      std::sort(index, index + n, compareBAasc(array));
}

//______________________________________________________________________________
void TGeoBranchArray::UpdateNavigator(TGeoNavigator *nav) const
{
// Update the navigator to reflect the branch.
   nav->CdTop();
   for (Int_t i=0; i<fLevel; i++) nav->CdDown(fArray[i]);
}
<|endoftext|>


<commit_before><commit_msg>crosstool's gcc gives lots of warnings like "warning: suggest parentheses around && within ||" For base/string_util.cc, just add the suggested parentheses.<commit_after><|endoftext|>


<commit_before>/*
  SVGMin - Aggressive SVG minifier

  Copyright (C) 2009 Ariya Hidayat (ariya.hidayat@gmail.com)

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

#include "svgminifier.h"

#include <QtCore>

#include "qcssparser_p.h"

class SvgMinifier::Private
{
public:
    QString inFile;
    QString outFile;
    bool autoFormat;
    QStringList excludedTags;
    QStringList excludedPrefixes;
    QStringList excludedId;
};

SvgMinifier::SvgMinifier()
{
    d = new Private;
    d->autoFormat = false;
}

SvgMinifier::~SvgMinifier()
{
    delete d;
}

void SvgMinifier::setInputFile(const QString &in)
{
    d->inFile = in;
}

void SvgMinifier::setOutputFile(const QString &out)
{
    d->outFile = out;
}

void SvgMinifier::setAutoFormat(bool format)
{
    d->autoFormat = format;
}

void SvgMinifier::addTagExclude(const QString &tag)
{
    d->excludedTags += tag;
}

void SvgMinifier::addPrefixExclude(const QString &prefix)
{
    d->excludedPrefixes += prefix;
}

void SvgMinifier::addIdExclude(const QString &id)
{
    d->excludedId += id;
}

static bool listContains(const QStringList &list, const QStringRef &str)
{
    if (str.isEmpty())
        return false;
    QString check = str.toString();
    foreach (const QString &s, list)
        if (check.startsWith(s))
            return true;
    return false;
}

static QXmlStreamAttributes parseStyle(const QStringRef &styleRef)
{
    QXmlStreamAttributes attributes;
    QCss::Parser parser;

    parser.init(styleRef.toString());
    QString key;

    while (parser.hasNext()) {
        parser.skipSpace();

        if (!parser.hasNext())
            break;
        parser.next();

        QString name = parser.lexem();

        parser.skipSpace();
        if (!parser.test(QCss::COLON))
            break;

        parser.skipSpace();
        if (!parser.hasNext())
            break;

        const int firstSymbol = parser.index;
        int symbolCount = 0;
        do {
            parser.next();
            ++symbolCount;
        } while (parser.hasNext() && !parser.test(QCss::SEMICOLON));

        QString value;
        for (int i = firstSymbol; i < firstSymbol + symbolCount; ++i)
            value += parser.symbols.at(i).lexem();

        parser.skipSpace();

        attributes.append(name, value);
    }

    return attributes;
}

// take the value of the "style" attribute, parse it and then
// merged the result with other XML attributes
static QXmlStreamAttributes mergedStyle(const QXmlStreamAttributes &attributes)
{
    if (!attributes.hasAttribute("style"))
        return attributes;

    QXmlStreamAttributes result;
    result.reserve(attributes.count());

    foreach (const QXmlStreamAttribute &attr, attributes)
        if (attr.name() != "style")
            result += attr;

    QXmlStreamAttributes styles = parseStyle(attributes.value("style"));
    foreach (const QXmlStreamAttribute &attr, styles)
        if (!attributes.hasAttribute(attr.value().toString()))
            result += attr;

    return result;
}

static bool isDrawingNode(const QStringRef &str)
{
    if (str == QLatin1String("linearGradient"))
        return false;
    if (str == QLatin1String("path"))
        return true;
    if (str == QLatin1String("text"))
        return true;
    if (str == QLatin1String("g"))
        return true;
    if (str == QLatin1String("rect"))
        return true;
    if (str == QLatin1String("circle"))
        return true;
    if (str == QLatin1String("polygon"))
        return true;
    if (str == QLatin1String("polyline"))
        return true;
    return false;
}

void SvgMinifier::run()
{
    QFile file;
    file.setFileName(d->inFile);
    if (!file.open(QFile::ReadOnly))
        return;

    QFile result;
    if (!d->outFile.isEmpty()) {
        result.setFileName(d->outFile);
        result.open(QFile::WriteOnly);
    } else {
        result.open(stdout, QFile::WriteOnly);
    }

    QXmlStreamReader *xml = new QXmlStreamReader(&file);
    xml->setNamespaceProcessing(false);
    QXmlStreamWriter *out = new QXmlStreamWriter(&result);
    out->setAutoFormatting(d->autoFormat);

    bool skip;
    QStack<bool> skipElement;
    skipElement.push(false);

    while (!xml->atEnd()) {
        switch (xml->readNext()) {

        case QXmlStreamReader::StartDocument:
            out->writeStartDocument(xml->documentVersion().toString(),
                                    xml->isStandaloneDocument());
            break;

        case QXmlStreamReader::EndDocument:
            out->writeEndDocument();
            break;

        case QXmlStreamReader::StartElement:
            if (skipElement.top()) {
                skipElement.push(true);
            } else {
                skip = listContains(d->excludedPrefixes, xml->prefix());
                skip = skip || d->excludedTags.contains(xml->name().toString());
                skipElement.push(skip);
                if (!skip) {
                    const QStringRef &tag = xml->qualifiedName();
                    out->writeStartElement(tag.toString());
                    QXmlStreamAttributes attr = mergedStyle(xml->attributes());
                    foreach (const QXmlStreamAttribute &a, attr) {
                        if (listContains(d->excludedPrefixes, a.prefix()))
                            continue;
                        if (a.qualifiedName() == "id" && isDrawingNode(tag))
                            if (listContains(d->excludedId, a.value()))
                                continue;
                        out->writeAttribute(a);
                    }
                }
            }
            break;

        case QXmlStreamReader::EndElement:
            skip = skipElement.pop();
            if (!skip)
                out->writeEndElement();
            break;

        case QXmlStreamReader::Characters:
            if (!skipElement.top())
                out->writeCharacters(xml->text().toString());
            break;

        case QXmlStreamReader::ProcessingInstruction:
            out->writeProcessingInstruction(xml->processingInstructionTarget().toString(),
                                            xml->processingInstructionData().toString());
            break;

        default:
            break;
        }
    }

    file.close();
    result.close();
}

<commit_msg>Handle CDATA differently than normal text.<commit_after>/*
  SVGMin - Aggressive SVG minifier

  Copyright (C) 2009 Ariya Hidayat (ariya.hidayat@gmail.com)

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

#include "svgminifier.h"

#include <QtCore>

#include "qcssparser_p.h"

class SvgMinifier::Private
{
public:
    QString inFile;
    QString outFile;
    bool autoFormat;
    QStringList excludedTags;
    QStringList excludedPrefixes;
    QStringList excludedId;
};

SvgMinifier::SvgMinifier()
{
    d = new Private;
    d->autoFormat = false;
}

SvgMinifier::~SvgMinifier()
{
    delete d;
}

void SvgMinifier::setInputFile(const QString &in)
{
    d->inFile = in;
}

void SvgMinifier::setOutputFile(const QString &out)
{
    d->outFile = out;
}

void SvgMinifier::setAutoFormat(bool format)
{
    d->autoFormat = format;
}

void SvgMinifier::addTagExclude(const QString &tag)
{
    d->excludedTags += tag;
}

void SvgMinifier::addPrefixExclude(const QString &prefix)
{
    d->excludedPrefixes += prefix;
}

void SvgMinifier::addIdExclude(const QString &id)
{
    d->excludedId += id;
}

static bool listContains(const QStringList &list, const QStringRef &str)
{
    if (str.isEmpty())
        return false;
    QString check = str.toString();
    foreach (const QString &s, list)
        if (check.startsWith(s))
            return true;
    return false;
}

static QXmlStreamAttributes parseStyle(const QStringRef &styleRef)
{
    QXmlStreamAttributes attributes;
    QCss::Parser parser;

    parser.init(styleRef.toString());
    QString key;

    while (parser.hasNext()) {
        parser.skipSpace();

        if (!parser.hasNext())
            break;
        parser.next();

        QString name = parser.lexem();

        parser.skipSpace();
        if (!parser.test(QCss::COLON))
            break;

        parser.skipSpace();
        if (!parser.hasNext())
            break;

        const int firstSymbol = parser.index;
        int symbolCount = 0;
        do {
            parser.next();
            ++symbolCount;
        } while (parser.hasNext() && !parser.test(QCss::SEMICOLON));

        QString value;
        for (int i = firstSymbol; i < firstSymbol + symbolCount; ++i)
            value += parser.symbols.at(i).lexem();

        parser.skipSpace();

        attributes.append(name, value);
    }

    return attributes;
}

// take the value of the "style" attribute, parse it and then
// merged the result with other XML attributes
static QXmlStreamAttributes mergedStyle(const QXmlStreamAttributes &attributes)
{
    if (!attributes.hasAttribute("style"))
        return attributes;

    QXmlStreamAttributes result;
    result.reserve(attributes.count());

    foreach (const QXmlStreamAttribute &attr, attributes)
        if (attr.name() != "style")
            result += attr;

    QXmlStreamAttributes styles = parseStyle(attributes.value("style"));
    foreach (const QXmlStreamAttribute &attr, styles)
        if (!attributes.hasAttribute(attr.value().toString()))
            result += attr;

    return result;
}

static bool isDrawingNode(const QStringRef &str)
{
    if (str == QLatin1String("linearGradient"))
        return false;
    if (str == QLatin1String("path"))
        return true;
    if (str == QLatin1String("text"))
        return true;
    if (str == QLatin1String("g"))
        return true;
    if (str == QLatin1String("rect"))
        return true;
    if (str == QLatin1String("circle"))
        return true;
    if (str == QLatin1String("polygon"))
        return true;
    if (str == QLatin1String("polyline"))
        return true;
    return false;
}

void SvgMinifier::run()
{
    QFile file;
    file.setFileName(d->inFile);
    if (!file.open(QFile::ReadOnly))
        return;

    QFile result;
    if (!d->outFile.isEmpty()) {
        result.setFileName(d->outFile);
        result.open(QFile::WriteOnly);
    } else {
        result.open(stdout, QFile::WriteOnly);
    }

    QXmlStreamReader *xml = new QXmlStreamReader(&file);
    xml->setNamespaceProcessing(false);
    QXmlStreamWriter *out = new QXmlStreamWriter(&result);
    out->setAutoFormatting(d->autoFormat);

    bool skip;
    QStack<bool> skipElement;
    skipElement.push(false);

    while (!xml->atEnd()) {
        switch (xml->readNext()) {

        case QXmlStreamReader::StartDocument:
            out->writeStartDocument(xml->documentVersion().toString(),
                                    xml->isStandaloneDocument());
            break;

        case QXmlStreamReader::EndDocument:
            out->writeEndDocument();
            break;

        case QXmlStreamReader::StartElement:
            if (skipElement.top()) {
                skipElement.push(true);
            } else {
                skip = listContains(d->excludedPrefixes, xml->prefix());
                skip = skip || d->excludedTags.contains(xml->name().toString());
                skipElement.push(skip);
                if (!skip) {
                    const QStringRef &tag = xml->qualifiedName();
                    out->writeStartElement(tag.toString());
                    QXmlStreamAttributes attr = mergedStyle(xml->attributes());
                    foreach (const QXmlStreamAttribute &a, attr) {
                        if (listContains(d->excludedPrefixes, a.prefix()))
                            continue;
                        if (a.qualifiedName() == "id" && isDrawingNode(tag))
                            if (listContains(d->excludedId, a.value()))
                                continue;
                        out->writeAttribute(a);
                    }
                }
            }
            break;

        case QXmlStreamReader::EndElement:
            skip = skipElement.pop();
            if (!skip)
                out->writeEndElement();
            break;

        case QXmlStreamReader::Characters:
            if (!skipElement.top()) {
                if (xml->isCDATA())
                    out->writeCDATA(xml->text().toString());
                else
                    out->writeCharacters(xml->text().toString());
            }
            break;

        case QXmlStreamReader::ProcessingInstruction:
            out->writeProcessingInstruction(xml->processingInstructionTarget().toString(),
                                            xml->processingInstructionData().toString());
            break;

        default:
            break;
        }
    }

    file.close();
    result.close();
}

<|endoftext|>