<commit_before>/*
 * @file opencog/embodiment/Control/OperationalAvatarController/PsiDemandUpdaterAgent.cc
 *
 * @author Jinhua Chua <JinhuaChua@gmail.com>
 * @date   2011-11-22
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include <boost/tokenizer.hpp>
#include <boost/lexical_cast.hpp>

#include <opencog/atomspace/SimpleTruthValue.h>
#include <opencog/spacetime/TimeServer.h>

#include <lib/json_spirit/json_spirit.h>

#include "OAC.h"
#include "PsiDemandUpdaterAgent.h"

#include "PsiRuleUtil.h"

using namespace opencog::oac;

bool PsiDemandUpdaterAgent::Demand::runUpdater(AtomSpace & atomSpace)
{
    std::string demandUpdater = this->demandName + "DemandUpdater";

#if HAVE_GUILE

    // Initialize scheme evaluator
    SchemeEval evaluator1(&atomSpace);
    std::string scheme_expression, scheme_return_value;

    scheme_expression = "( " + demandUpdater + " )";

    // Run the Procedure that update Demands and get the updated value
    scheme_return_value = evaluator1.eval(scheme_expression);

    if ( evaluator1.eval_error() ) {
        logger().error( "PsiDemandUpdaterAgent::Demand::%s - Failed to execute '%s'",
                         __FUNCTION__, scheme_expression.c_str());
        return false;
    }

    // Store the updated demand value (result)
    this->currentDemandValue = atof( scheme_return_value.c_str() );

    logger().debug("PsiDemandUpdaterAgent::Demand::%s - The level of demand '%s' will be set to '%f'",
                   __FUNCTION__, this->demandName.c_str(), this->currentDemandValue);

#endif // HAVE_GUILE

    return true;
}

bool PsiDemandUpdaterAgent::Demand::updateDemandGoal (AtomSpace & atomSpace, const unsigned long timeStamp)
{
    // Get the GroundedPredicateNode "fuzzy_within"
    Handle hGroundedPredicateNode = atomSpace.getOutgoing(hFuzzyWithin, 0);

    bool isNotPredicateNode = atomSpace.getType(hGroundedPredicateNode) != GROUNDED_PREDICATE_NODE;
    bool isOutgoingNotPredicateNode = atomSpace.getType(atomSpace.getOutgoing(hGroundedPredicateNode, 0)) != GROUNDED_PREDICATE_NODE;

    if ( hGroundedPredicateNode == opencog::Handle::UNDEFINED || (isNotPredicateNode && isOutgoingNotPredicateNode)) {

        logger().error("PsiDemandUpdaterAgent::Demand::%s - Expect a GroundedPredicateNode for demand '%s'. But got '%s'",
                       __FUNCTION__, this->demandName.c_str(), atomSpace.atomAsString(hGroundedPredicateNode).c_str());
        return false;
    }

    // Get ListLink containing ExecutionOutputLink and parameters of FuzzyWithin
    Handle hListLink = atomSpace.getOutgoing(hFuzzyWithin, 1);

    if ( hListLink == opencog::Handle::UNDEFINED ||
         atomSpace.getType(hListLink) != LIST_LINK ||
         atomSpace.getArity(hListLink) != 3 ) {

        logger().error("PsiDemandUpdaterAgent::Demand::%s - Expect a ListLink for demand '%s' with three arity (parameters of FuzzyWithin). But got '%s'",
                       __FUNCTION__, this->demandName.c_str(), atomSpace.atomAsString(hListLink).c_str());
        return false;
    }

    // Get the ExecutionOutputLink
    Handle hExecutionOutputLink = atomSpace.getOutgoing(hListLink, 2);

    if ( hExecutionOutputLink == opencog::Handle::UNDEFINED ||
         atomSpace.getType(hExecutionOutputLink) != EXECUTION_OUTPUT_LINK ||
         atomSpace.getArity(hExecutionOutputLink) != 1 ) {

        logger().error("PsiDemandUpdaterAgent::Demand::%s - Expect an ExecutionOutputLink (updater) for demand '%s' with only one arity. But got '%s'",
                       __FUNCTION__, this->demandName.c_str(), atomSpace.atomAsString(hExecutionOutputLink).c_str());
        return false;
    }

#if HAVE_GUILE

    // Initialize scheme evaluator
    SchemeEval evaluator1(&atomSpace);
    std::string scheme_expression, scheme_return_value;

    // Store the updated Demand levels to AtomSpace
    // set_modulator_or_demand_value would create a new NumberNode and SilarityLink
    //
    // Note: Since OpenCog would forget (remove) those Nodes and Links gradually,
    //       unless you create them to be permanent, don't worry about the overflow of memory.
    scheme_expression = "( set_modulator_or_demand_value \"" +
                               this->demandName + "Demand\" " +
                               boost::lexical_cast<std::string>(this->currentDemandValue) + " " +
                               boost::lexical_cast<std::string>(timeStamp) + " " +
                        ")";

    // Run the scheme procedure
    scheme_return_value = evaluator1.eval(scheme_expression);

    if ( evaluator1.eval_error() ) {
        logger().error( "PsiDemandUpdaterAgent::Demand::%s - Failed to execute '%s'",
                         __FUNCTION__, scheme_expression.c_str());

        return false;
    }

    logger().debug("PsiDemandUpdaterAgent::Demand::%s - Updated the value of '%s' demand to %f and store it to AtomSpace",
                   __FUNCTION__, this->demandName.c_str(), this->currentDemandValue);

    // Get the fuzzy_within scheme procedure name, which should be "fuzzy_within"
    std::string demandGoalEvaluator = atomSpace.getName(hGroundedPredicateNode);

    // Get min/ max acceptable values
    std::string minValueStr = atomSpace.getName( atomSpace.getOutgoing(hListLink, 0) );
    std::string maxValueStr = atomSpace.getName( atomSpace.getOutgoing(hListLink, 1) );

    scheme_expression = "( fuzzy_within " +
                               boost::lexical_cast<std::string>(this->currentDemandValue) + " " +
                               minValueStr + " " +
                               maxValueStr + " " +
                               "100"
                         ")";

    // Run the scheme procedure
    scheme_return_value = evaluator1.eval(scheme_expression);

    if ( evaluator1.eval_error() ) {
        logger().error( "PsiDemandUpdaterAgent::Demand::%s - Failed to execute '%s' for demand '%s'",
                         __FUNCTION__, scheme_expression.c_str(), this->demandName.c_str());

        return false;
    }

    // Store the result and update TruthValue of EvaluationLinkDemandGoal and EvaluationLinkFuzzyWithin
    // TODO: Use PLN forward chainer to handle this?
    TruthValuePtr demand_satisfaction = SimpleTruthValue::createTV(atof(scheme_return_value.c_str()), 1.0f);

    atomSpace.setTV(this->hDemandGoal, demand_satisfaction);

    // Add AtTimeLink around EvaluationLink of  DemandGoal, which is required by fishgram
    Handle atTimeLink = timeServer().addTimeInfo(this->hDemandGoal,
                                                              timeStamp,
                                                              demand_satisfaction
                                                             );

//    // Update the LatestLink
    std::string predicateName = this->demandName + "DemandGoal";
    Handle demandPredicateNode = atomSpace.addNode(PREDICATE_NODE, predicateName.c_str());

    std::vector <Handle> outgoings;
    Handle listLink = atomSpace.addLink(LIST_LINK, outgoings);
    outgoings.push_back(demandPredicateNode);
    outgoings.push_back(listLink);
    Handle evaluationLink = atomSpace.addLink(EVALUATION_LINK, outgoings);
    atomSpace.setTV(evaluationLink, demand_satisfaction);

    atTimeLink = timeServer().addTimeInfo(evaluationLink, timeStamp, demand_satisfaction);

    AtomSpaceUtil::updateLatestDemand(atomSpace, atTimeLink, demandPredicateNode);

    atomSpace.setTV( this->hFuzzyWithin, demand_satisfaction);

    this->currentDemandTruthValue = atof(scheme_return_value.c_str());

    logger().debug( "PsiDemandUpdaterAgent::Demand::%s - The level (truth value) of DemandGoal '%s' has been set to %s",
                     __FUNCTION__, this->demandName.c_str(), scheme_return_value.c_str());

    return true;

#else // HAVE_GUILE
    logger().error("PsiDemandUpdaterAgent::Demand::%s - guile is required",
                   __FUNCTION__);
    return false;
#endif // HAVE_GUILE

}

void PsiDemandUpdaterAgent::sendUpdatedValues()
{
    logger().debug( "PsiDemandUpdaterAgent::%s - Sending updated demand truth values to the virtual world [ cycle =%d ]",
                    __FUNCTION__, this->cycleCount);
    // Get OAC
    OAC * oac = dynamic_cast<OAC *>(&_cogserver);

    // Get AtomSpace
//    AtomSpace & atomSpace = * ( oac->getAtomSpace() );

    // Get petName
    const std::string & petName = oac->getPet().getName();

    // Prepare the data to be sent
    std::map <std::string, float> demandValueMap;

    for (Demand & demand : this->demandList) {
        if ( demand.getDemandName() != "Energy" &&   // these demand values are
             demand.getDemandName() != "Integrity")  // updated by virtual world
            demandValueMap[ demand.getDemandName() ] = demand.getDemandValue();
    }

    // Send updated feelings to the virtual world where the pet lives
    oac->getPAI().sendDemandSatisfactions(petName, demandValueMap);
}

PsiDemandUpdaterAgent::~PsiDemandUpdaterAgent()
{
#ifdef HAVE_ZMQ
    delete this->publisher;
#endif
}

PsiDemandUpdaterAgent::PsiDemandUpdaterAgent(CogServer& cs) : Agent(cs)
{
    this->cycleCount = 0;

#ifdef HAVE_ZMQ
    this->publisher = NULL;
#endif

    // Force the Agent initialize itself during its first cycle.
    this->forceInitNextCycle();
}

#ifdef HAVE_ZMQ
void PsiDemandUpdaterAgent::publishUpdatedValue(Plaza & plaza,
                                                zmq::socket_t & publisher,
                                                const unsigned long timeStamp)
{
    using namespace json_spirit;

    // Send the name of current mind agent which would be used as a filter key by subscribers
    std::string keyString = "PsiDemandUpdaterAgent";
    plaza.publishStringMore(publisher, keyString);

    // Pack time stamp and all the Demand values in json format
    Object jsonObj; // json_spirit::Object is of type std::vector< Pair >
    jsonObj.push_back( Pair("timestamp", (uint64_t) timeStamp) );

    for (Demand & demand : this->demandList) {
        jsonObj.push_back( Pair( demand.getDemandName()+"TruthValue", demand.getDemandTruthValue() ) );
    }

    // Publish the data packed in json format
    std::string dataString = write_formatted(jsonObj);
    plaza.publishString(publisher, dataString);
}
#endif // HAVE_ZMQ

void PsiDemandUpdaterAgent::init()
{
    logger().debug( "PsiDemandUpdaterAgent::%s - Initialize the Agent [cycle = %d]",
                    __FUNCTION__, this->cycleCount);

    // Get OAC
    OAC* oac = dynamic_cast<OAC*>(&_cogserver);
    OC_ASSERT(oac, "Did not get an OAC server");

    // Get AtomSpace
    AtomSpace& atomSpace = oac->getAtomSpace();

    // Clear old demandList
    this->demandList.clear();

    // Get demand names from the configuration file
    std::string demandNames = config()["PSI_DEMANDS"];

    // Process Demands one by one
    boost::char_separator<char> sep(", ");
    boost::tokenizer< boost::char_separator<char> > demandNamesTok (demandNames, sep);

    std::string demandName, demandUpdater;
    Handle hDemandGoal, hFuzzyWithin;

    // Process Demands one by one
    for ( boost::tokenizer< boost::char_separator<char> >::iterator iDemandName = demandNamesTok.begin();
          iDemandName != demandNamesTok.end();
          iDemandName ++ ) {

        demandName = (*iDemandName);
        demandUpdater = demandName + "DemandUpdater";

        // Search the corresponding SimultaneousEquivalenceLink
        if ( !AtomSpaceUtil::getDemandEvaluationLinks(atomSpace, demandName, hDemandGoal, hFuzzyWithin) )
        {
            logger().warn( "PsiDemandUpdaterAgent::%s - Failed to get EvaluationLinks for demand '%s' [cycle = %d]",
                           __FUNCTION__, demandName.c_str(), this->cycleCount);

            continue;
        }

        this->demandList.push_back(Demand(demandName, hDemandGoal, hFuzzyWithin));

        logger().debug("PsiDemandUpdaterAgent::%s - Store the meta data of demand '%s' successfully [cycle = %d]",
                        __FUNCTION__, demandName.c_str(), this->cycleCount);
    }// for

    // Initialize ZeroMQ publisher and add it to the plaza
#ifdef HAVE_ZMQ
    // Get petId
    const std::string & petId = oac->getPet().getPetId();

    Plaza & plaza = oac->getPlaza();
    this->publisher = new zmq::socket_t (plaza.getZmqContext(), ZMQ_PUB);
    this->publishEndPoint = "ipc://" + petId + ".PsiDemandUpdaterAgent.ipc";
    this->publisher->bind( this->publishEndPoint.c_str() );

    plaza.addPublisher(this->publishEndPoint);
#endif

    // Avoid initialize during next cycle
    this->bInitialized = true;

    hasPsiDemandUpdaterForTheFirstTime = false;
}

void PsiDemandUpdaterAgent::run()
{
    this->cycleCount = _cogserver.getCycleCount();

    logger().debug( "PsiDemandUpdaterAgent::%s - Executing run %d times",
                     __FUNCTION__, this->cycleCount);

    // Get OAC
    OAC* oac = dynamic_cast<OAC*>(&_cogserver);
    OC_ASSERT(oac, "Did not get an OAC server!");

    // Get AtomSpace
    AtomSpace& atomSpace = oac->getAtomSpace();

    // Get current time stamp
    unsigned long timeStamp = oac->getPAI().getLatestSimWorldTimestamp();

    // Initialize the Agent (demandList etc)
    if ( !this->bInitialized )
        this->init();

    // Update demand values
    for (Demand & demand : this->demandList) {
        logger().debug("PsiDemandUpdaterAgent::%s - Going to run updaters for demand '%s' [cycle = %d]",
                       __FUNCTION__, demand.getDemandName().c_str(), this->cycleCount);

        demand.runUpdater(atomSpace);
    }

    // Update Demand Goals
    for (Demand & demand : this->demandList) {
        logger().debug("PsiDemandUpdaterAgent::%s - Going to set the updated value to AtomSpace for demand '%s' [cycle = %d]",
                       __FUNCTION__, demand.getDemandName().c_str(), this->cycleCount);

        demand.updateDemandGoal(atomSpace, timeStamp);
    }

    // Send the truth values of demand goals to the virtual world
    this->sendUpdatedValues();

    hasPsiDemandUpdaterForTheFirstTime = true;

#ifdef HAVE_ZMQ
    // Publish updated Demand values via ZeroMQ
    Plaza & plaza = oac->getPlaza();
    this->publishUpdatedValue(plaza, *this->publisher, timeStamp);
#endif

}

double PsiDemandUpdaterAgent::getDemandValue(string demanName) const
{
    for (const Demand & demand : this->demandList) {
        if ( demand.getDemandName() == demanName)
            return demand.getDemandValue();
    }

    return 0.0000;
}
<commit_msg>Fix 80 col max<commit_after>/*
 * @file opencog/embodiment/Control/OperationalAvatarController/PsiDemandUpdaterAgent.cc
 *
 * @author Jinhua Chua <JinhuaChua@gmail.com>
 * @date   2011-11-22
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include <boost/tokenizer.hpp>
#include <boost/lexical_cast.hpp>

#include <opencog/atomspace/SimpleTruthValue.h>
#include <opencog/spacetime/TimeServer.h>

#include <lib/json_spirit/json_spirit.h>

#include "OAC.h"
#include "PsiDemandUpdaterAgent.h"

#include "PsiRuleUtil.h"

using namespace opencog::oac;

bool PsiDemandUpdaterAgent::Demand::runUpdater(AtomSpace & atomSpace)
{
    std::string demandUpdater = this->demandName + "DemandUpdater";

#if HAVE_GUILE

    // Initialize scheme evaluator
    SchemeEval evaluator1(&atomSpace);
    std::string scheme_expression, scheme_return_value;

    scheme_expression = "( " + demandUpdater + " )";

    // Run the Procedure that update Demands and get the updated value
    scheme_return_value = evaluator1.eval(scheme_expression);

    if ( evaluator1.eval_error() ) {
        logger().error("PsiDemandUpdaterAgent::Demand::%s - "
                       "Failed to execute '%s'",
                       __FUNCTION__, scheme_expression.c_str());
        return false;
    }

    // Store the updated demand value (result)
    this->currentDemandValue = atof( scheme_return_value.c_str() );

    logger().debug("PsiDemandUpdaterAgent::Demand::%s - "
                   "The level of demand '%s' will be set to '%f'",
                   __FUNCTION__, this->demandName.c_str(),
                   this->currentDemandValue);

#endif // HAVE_GUILE

    return true;
}

bool PsiDemandUpdaterAgent::Demand::updateDemandGoal (AtomSpace & atomSpace, const unsigned long timeStamp)
{
    // Get the GroundedPredicateNode "fuzzy_within"
    Handle hGroundedPredicateNode = atomSpace.getOutgoing(hFuzzyWithin, 0);

    bool isNotPredicateNode = atomSpace.getType(hGroundedPredicateNode) != GROUNDED_PREDICATE_NODE;
    bool isOutgoingNotPredicateNode = atomSpace.getType(atomSpace.getOutgoing(hGroundedPredicateNode, 0)) != GROUNDED_PREDICATE_NODE;

    if ( hGroundedPredicateNode == opencog::Handle::UNDEFINED || (isNotPredicateNode && isOutgoingNotPredicateNode)) {

        logger().error("PsiDemandUpdaterAgent::Demand::%s - Expect a GroundedPredicateNode for demand '%s'. But got '%s'",
                       __FUNCTION__, this->demandName.c_str(), atomSpace.atomAsString(hGroundedPredicateNode).c_str());
        return false;
    }

    // Get ListLink containing ExecutionOutputLink and parameters of FuzzyWithin
    Handle hListLink = atomSpace.getOutgoing(hFuzzyWithin, 1);

    if ( hListLink == opencog::Handle::UNDEFINED ||
         atomSpace.getType(hListLink) != LIST_LINK ||
         atomSpace.getArity(hListLink) != 3 ) {

        logger().error("PsiDemandUpdaterAgent::Demand::%s - Expect a ListLink for demand '%s' with three arity (parameters of FuzzyWithin). But got '%s'",
                       __FUNCTION__, this->demandName.c_str(), atomSpace.atomAsString(hListLink).c_str());
        return false;
    }

    // Get the ExecutionOutputLink
    Handle hExecutionOutputLink = atomSpace.getOutgoing(hListLink, 2);

    if ( hExecutionOutputLink == opencog::Handle::UNDEFINED ||
         atomSpace.getType(hExecutionOutputLink) != EXECUTION_OUTPUT_LINK ||
         atomSpace.getArity(hExecutionOutputLink) != 1 ) {

        logger().error("PsiDemandUpdaterAgent::Demand::%s - Expect an ExecutionOutputLink (updater) for demand '%s' with only one arity. But got '%s'",
                       __FUNCTION__, this->demandName.c_str(), atomSpace.atomAsString(hExecutionOutputLink).c_str());
        return false;
    }

#if HAVE_GUILE

    // Initialize scheme evaluator
    SchemeEval evaluator1(&atomSpace);
    std::string scheme_expression, scheme_return_value;

    // Store the updated Demand levels to AtomSpace
    // set_modulator_or_demand_value would create a new NumberNode and SilarityLink
    //
    // Note: Since OpenCog would forget (remove) those Nodes and Links gradually,
    //       unless you create them to be permanent, don't worry about the overflow of memory.
    scheme_expression = "( set_modulator_or_demand_value \"" +
                               this->demandName + "Demand\" " +
                               boost::lexical_cast<std::string>(this->currentDemandValue) + " " +
                               boost::lexical_cast<std::string>(timeStamp) + " " +
                        ")";

    // Run the scheme procedure
    scheme_return_value = evaluator1.eval(scheme_expression);

    if ( evaluator1.eval_error() ) {
        logger().error( "PsiDemandUpdaterAgent::Demand::%s - Failed to execute '%s'",
                         __FUNCTION__, scheme_expression.c_str());

        return false;
    }

    logger().debug("PsiDemandUpdaterAgent::Demand::%s - Updated the value of '%s' demand to %f and store it to AtomSpace",
                   __FUNCTION__, this->demandName.c_str(), this->currentDemandValue);

    // Get the fuzzy_within scheme procedure name, which should be "fuzzy_within"
    std::string demandGoalEvaluator = atomSpace.getName(hGroundedPredicateNode);

    // Get min/ max acceptable values
    std::string minValueStr = atomSpace.getName( atomSpace.getOutgoing(hListLink, 0) );
    std::string maxValueStr = atomSpace.getName( atomSpace.getOutgoing(hListLink, 1) );

    scheme_expression = "( fuzzy_within " +
                               boost::lexical_cast<std::string>(this->currentDemandValue) + " " +
                               minValueStr + " " +
                               maxValueStr + " " +
                               "100"
                         ")";

    // Run the scheme procedure
    scheme_return_value = evaluator1.eval(scheme_expression);

    if ( evaluator1.eval_error() ) {
        logger().error( "PsiDemandUpdaterAgent::Demand::%s - Failed to execute '%s' for demand '%s'",
                         __FUNCTION__, scheme_expression.c_str(), this->demandName.c_str());

        return false;
    }

    // Store the result and update TruthValue of EvaluationLinkDemandGoal and EvaluationLinkFuzzyWithin
    // TODO: Use PLN forward chainer to handle this?
    TruthValuePtr demand_satisfaction = SimpleTruthValue::createTV(atof(scheme_return_value.c_str()), 1.0f);

    atomSpace.setTV(this->hDemandGoal, demand_satisfaction);

    // Add AtTimeLink around EvaluationLink of  DemandGoal, which is required by fishgram
    Handle atTimeLink = timeServer().addTimeInfo(this->hDemandGoal,
                                                              timeStamp,
                                                              demand_satisfaction
                                                             );

//    // Update the LatestLink
    std::string predicateName = this->demandName + "DemandGoal";
    Handle demandPredicateNode = atomSpace.addNode(PREDICATE_NODE, predicateName.c_str());

    std::vector <Handle> outgoings;
    Handle listLink = atomSpace.addLink(LIST_LINK, outgoings);
    outgoings.push_back(demandPredicateNode);
    outgoings.push_back(listLink);
    Handle evaluationLink = atomSpace.addLink(EVALUATION_LINK, outgoings);
    atomSpace.setTV(evaluationLink, demand_satisfaction);

    atTimeLink = timeServer().addTimeInfo(evaluationLink, timeStamp, demand_satisfaction);

    AtomSpaceUtil::updateLatestDemand(atomSpace, atTimeLink, demandPredicateNode);

    atomSpace.setTV( this->hFuzzyWithin, demand_satisfaction);

    this->currentDemandTruthValue = atof(scheme_return_value.c_str());

    logger().debug( "PsiDemandUpdaterAgent::Demand::%s - The level (truth value) of DemandGoal '%s' has been set to %s",
                     __FUNCTION__, this->demandName.c_str(), scheme_return_value.c_str());

    return true;

#else // HAVE_GUILE
    logger().error("PsiDemandUpdaterAgent::Demand::%s - guile is required",
                   __FUNCTION__);
    return false;
#endif // HAVE_GUILE

}

void PsiDemandUpdaterAgent::sendUpdatedValues()
{
    logger().debug( "PsiDemandUpdaterAgent::%s - Sending updated demand truth values to the virtual world [ cycle =%d ]",
                    __FUNCTION__, this->cycleCount);
    // Get OAC
    OAC * oac = dynamic_cast<OAC *>(&_cogserver);

    // Get AtomSpace
//    AtomSpace & atomSpace = * ( oac->getAtomSpace() );

    // Get petName
    const std::string & petName = oac->getPet().getName();

    // Prepare the data to be sent
    std::map <std::string, float> demandValueMap;

    for (Demand & demand : this->demandList) {
        if ( demand.getDemandName() != "Energy" &&   // these demand values are
             demand.getDemandName() != "Integrity")  // updated by virtual world
            demandValueMap[ demand.getDemandName() ] = demand.getDemandValue();
    }

    // Send updated feelings to the virtual world where the pet lives
    oac->getPAI().sendDemandSatisfactions(petName, demandValueMap);
}

PsiDemandUpdaterAgent::~PsiDemandUpdaterAgent()
{
#ifdef HAVE_ZMQ
    delete this->publisher;
#endif
}

PsiDemandUpdaterAgent::PsiDemandUpdaterAgent(CogServer& cs) : Agent(cs)
{
    this->cycleCount = 0;

#ifdef HAVE_ZMQ
    this->publisher = NULL;
#endif

    // Force the Agent initialize itself during its first cycle.
    this->forceInitNextCycle();
}

#ifdef HAVE_ZMQ
void PsiDemandUpdaterAgent::publishUpdatedValue(Plaza & plaza,
                                                zmq::socket_t & publisher,
                                                const unsigned long timeStamp)
{
    using namespace json_spirit;

    // Send the name of current mind agent which would be used as a filter key by subscribers
    std::string keyString = "PsiDemandUpdaterAgent";
    plaza.publishStringMore(publisher, keyString);

    // Pack time stamp and all the Demand values in json format
    Object jsonObj; // json_spirit::Object is of type std::vector< Pair >
    jsonObj.push_back( Pair("timestamp", (uint64_t) timeStamp) );

    for (Demand & demand : this->demandList) {
        jsonObj.push_back( Pair( demand.getDemandName()+"TruthValue", demand.getDemandTruthValue() ) );
    }

    // Publish the data packed in json format
    std::string dataString = write_formatted(jsonObj);
    plaza.publishString(publisher, dataString);
}
#endif // HAVE_ZMQ

void PsiDemandUpdaterAgent::init()
{
    logger().debug( "PsiDemandUpdaterAgent::%s - Initialize the Agent [cycle = %d]",
                    __FUNCTION__, this->cycleCount);

    // Get OAC
    OAC* oac = dynamic_cast<OAC*>(&_cogserver);
    OC_ASSERT(oac, "Did not get an OAC server");

    // Get AtomSpace
    AtomSpace& atomSpace = oac->getAtomSpace();

    // Clear old demandList
    this->demandList.clear();

    // Get demand names from the configuration file
    std::string demandNames = config()["PSI_DEMANDS"];

    // Process Demands one by one
    boost::char_separator<char> sep(", ");
    boost::tokenizer< boost::char_separator<char> > demandNamesTok (demandNames, sep);

    std::string demandName, demandUpdater;
    Handle hDemandGoal, hFuzzyWithin;

    // Process Demands one by one
    for ( boost::tokenizer< boost::char_separator<char> >::iterator iDemandName = demandNamesTok.begin();
          iDemandName != demandNamesTok.end();
          iDemandName ++ ) {

        demandName = (*iDemandName);
        demandUpdater = demandName + "DemandUpdater";

        // Search the corresponding SimultaneousEquivalenceLink
        if ( !AtomSpaceUtil::getDemandEvaluationLinks(atomSpace, demandName, hDemandGoal, hFuzzyWithin) )
        {
            logger().warn( "PsiDemandUpdaterAgent::%s - Failed to get EvaluationLinks for demand '%s' [cycle = %d]",
                           __FUNCTION__, demandName.c_str(), this->cycleCount);

            continue;
        }

        this->demandList.push_back(Demand(demandName, hDemandGoal, hFuzzyWithin));

        logger().debug("PsiDemandUpdaterAgent::%s - Store the meta data of demand '%s' successfully [cycle = %d]",
                        __FUNCTION__, demandName.c_str(), this->cycleCount);
    }// for

    // Initialize ZeroMQ publisher and add it to the plaza
#ifdef HAVE_ZMQ
    // Get petId
    const std::string & petId = oac->getPet().getPetId();

    Plaza & plaza = oac->getPlaza();
    this->publisher = new zmq::socket_t (plaza.getZmqContext(), ZMQ_PUB);
    this->publishEndPoint = "ipc://" + petId + ".PsiDemandUpdaterAgent.ipc";
    this->publisher->bind( this->publishEndPoint.c_str() );

    plaza.addPublisher(this->publishEndPoint);
#endif

    // Avoid initialize during next cycle
    this->bInitialized = true;

    hasPsiDemandUpdaterForTheFirstTime = false;
}

void PsiDemandUpdaterAgent::run()
{
    this->cycleCount = _cogserver.getCycleCount();

    logger().debug( "PsiDemandUpdaterAgent::%s - Executing run %d times",
                     __FUNCTION__, this->cycleCount);

    // Get OAC
    OAC* oac = dynamic_cast<OAC*>(&_cogserver);
    OC_ASSERT(oac, "Did not get an OAC server!");

    // Get AtomSpace
    AtomSpace& atomSpace = oac->getAtomSpace();

    // Get current time stamp
    unsigned long timeStamp = oac->getPAI().getLatestSimWorldTimestamp();

    // Initialize the Agent (demandList etc)
    if ( !this->bInitialized )
        this->init();

    // Update demand values
    for (Demand & demand : this->demandList) {
        logger().debug("PsiDemandUpdaterAgent::%s - Going to run updaters for demand '%s' [cycle = %d]",
                       __FUNCTION__, demand.getDemandName().c_str(), this->cycleCount);

        demand.runUpdater(atomSpace);
    }

    // Update Demand Goals
    for (Demand & demand : this->demandList) {
        logger().debug("PsiDemandUpdaterAgent::%s - Going to set the updated value to AtomSpace for demand '%s' [cycle = %d]",
                       __FUNCTION__, demand.getDemandName().c_str(), this->cycleCount);

        demand.updateDemandGoal(atomSpace, timeStamp);
    }

    // Send the truth values of demand goals to the virtual world
    this->sendUpdatedValues();

    hasPsiDemandUpdaterForTheFirstTime = true;

#ifdef HAVE_ZMQ
    // Publish updated Demand values via ZeroMQ
    Plaza & plaza = oac->getPlaza();
    this->publishUpdatedValue(plaza, *this->publisher, timeStamp);
#endif

}

double PsiDemandUpdaterAgent::getDemandValue(string demanName) const
{
    for (const Demand & demand : this->demandList) {
        if ( demand.getDemandName() == demanName)
            return demand.getDemandValue();
    }

    return 0.0000;
}
<|endoftext|>


<commit_before>// ------------------------
// Windows specific example
// ------------------------
#include <windows.h>
#include "parallel_hashmap/phmap.h"
#include <cstring>
#include <vector>
#include <ppl.h>

class srwlock {
    SRWLOCK _lock;

public:
    srwlock()     { InitializeSRWLock(&_lock); }
    void lock()   { AcquireSRWLockExclusive(&_lock); }
    void unlock() { ReleaseSRWLockExclusive(&_lock); }
};

using Map =  phmap::parallel_flat_hash_map<std::string, int, phmap::priv::hash_default_hash<std::string>,
                                           phmap::priv::hash_default_eq<std::string>,
                                           std::allocator<std::pair<const std::string, int>>, 8, srwlock>;

class Dict
{
    Map m_stringsMap;

public:
    int addParallel(std::string&& str, volatile long* curIdx)
    {
        int newIndex = -1;
        m_stringsMap.lazy_emplace_l(std::move(str),
                                    [&](int& v) { newIndex = v; },    // called only when key was already present
                                    [&](const Map::constructor& ctor) // construct value_type in place when key not present
                                        { newIndex = InterlockedIncrement(curIdx); ctor(std::move(str), newIndex); });

        return newIndex;
    }
};

int main()
{
    size_t totalSize = 6000000;
    std::vector<int> values(totalSize);
    Dict dict;
    volatile long index = 0;
    concurrency::parallel_for(size_t(0), size_t(totalSize),
        [&](size_t i) {
            std::string s = "ab_uu_" + std::to_string(i % 1000000);
            values[i] = dict.addParallel(std::move(s), &index);
        });

    return 0;
}
<commit_msg>update comment with attribution<commit_after>// ------------------------
// Windows specific example
// curtesy of @kanonka
// ------------------------
#include <windows.h>
#include "parallel_hashmap/phmap.h"
#include <cstring>
#include <vector>
#include <ppl.h>

class srwlock {
    SRWLOCK _lock;

public:
    srwlock()     { InitializeSRWLock(&_lock); }
    void lock()   { AcquireSRWLockExclusive(&_lock); }
    void unlock() { ReleaseSRWLockExclusive(&_lock); }
};

using Map =  phmap::parallel_flat_hash_map<std::string, int, phmap::priv::hash_default_hash<std::string>,
                                           phmap::priv::hash_default_eq<std::string>,
                                           std::allocator<std::pair<const std::string, int>>, 8, srwlock>;

class Dict
{
    Map m_stringsMap;

public:
    int addParallel(std::string&& str, volatile long* curIdx)
    {
        int newIndex = -1;
        m_stringsMap.lazy_emplace_l(std::move(str),
                                    [&](int& v) { newIndex = v; },    // called only when key was already present
                                    [&](const Map::constructor& ctor) // construct value_type in place when key not present
                                        { newIndex = InterlockedIncrement(curIdx); ctor(std::move(str), newIndex); });

        return newIndex;
    }
};

int main()
{
    size_t totalSize = 6000000;
    std::vector<int> values(totalSize);
    Dict dict;
    volatile long index = 0;
    concurrency::parallel_for(size_t(0), size_t(totalSize),
        [&](size_t i) {
            std::string s = "ab_uu_" + std::to_string(i % 1000000);
            values[i] = dict.addParallel(std::move(s), &index);
        });

    return 0;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "player.h"

#include "playercontrols.h"
#include "playlistmodel.h"

#include <multimedia/qmediaservice.h>
#include <multimedia/qmediaplaylist.h>

#include <QtGui>

Player::Player(QWidget *parent)
    : QWidget(parent)
    , videoWidget(0)
    , coverLabel(0)
    , slider(0)
    , colorDialog(0)
{
    player = new QMediaPlayer;
    playlist = new QMediaPlaylist(player);

    connect(player, SIGNAL(durationChanged(qint64)), SLOT(durationChanged(qint64)));
    connect(player, SIGNAL(positionChanged(qint64)), SLOT(positionChanged(qint64)));
    connect(player, SIGNAL(metaDataChanged()), SLOT(metaDataChanged()));
    connect(playlist, SIGNAL(playlistPositionChanged(int)), SLOT(playlistPositionChanged(int)));
    connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
            this, SLOT(statusChanged(QMediaPlayer::MediaStatus)));
    connect(player, SIGNAL(bufferStatusChanged(int)), this, SLOT(bufferingProgress(int)));

    videoWidget = new QVideoWidget(player);

    connect(videoWidget, SIGNAL(displayModeChanged(QVideoWidget::DisplayMode)),
            this, SLOT(displayModeChanged(QVideoWidget::DisplayMode)));

    playlistModel = new PlaylistModel(this);
    playlistModel->setPlaylist(playlist);

    playlistView = new QTableView;
    playlistView->setModel(playlistModel);
    playlistView->setCurrentIndex(playlistModel->index(playlist->currentPosition(), 0));

    connect(playlistView, SIGNAL(activated(QModelIndex)), this, SLOT(jump(QModelIndex)));

    slider = new QSlider(Qt::Horizontal);
    slider->setRange(0, player->duration() / 1000);

    connect(slider, SIGNAL(sliderMoved(int)), this, SLOT(seek(int)));

    QPushButton *openButton = new QPushButton(tr("Open"));

    connect(openButton, SIGNAL(clicked()), this, SLOT(open()));

    PlayerControls *controls = new PlayerControls;
    controls->setState(player->state());
    controls->setVolume(player->volume());
    controls->setMuted(controls->isMuted());

    connect(controls, SIGNAL(play()), player, SLOT(play()));
    connect(controls, SIGNAL(pause()), player, SLOT(pause()));
    connect(controls, SIGNAL(stop()), player, SLOT(stop()));
    connect(controls, SIGNAL(next()), playlist, SLOT(advance()));
    connect(controls, SIGNAL(previous()), playlist, SLOT(back()));
    connect(controls, SIGNAL(changeVolume(int)), player, SLOT(setVolume(int)));
    connect(controls, SIGNAL(changeMuting(bool)), player, SLOT(setMuted(bool)));
    connect(controls, SIGNAL(changeRate(float)), player, SLOT(setPlaybackRate(float)));

    connect(player, SIGNAL(stateChanged(QMediaPlayer::State)),
            controls, SLOT(setState(QMediaPlayer::State)));
    connect(player, SIGNAL(volumeChanged(int)), controls, SLOT(setVolume(int)));
    connect(player, SIGNAL(mutingChanged(bool)), controls, SLOT(setMuted(bool)));

    QPushButton *fullscreenButton = new QPushButton(tr("Fullscreen"));
    fullscreenButton->setCheckable(true);

    connect(fullscreenButton, SIGNAL(clicked(bool)), this, SLOT(setFullscreen(bool)));
    connect(this, SIGNAL(fullscreenChanged(bool)), fullscreenButton, SLOT(setChecked(bool)));

    fullscreenButton->setEnabled(videoWidget != 0);

    QPushButton *colorButton = new QPushButton(tr("Color Options..."));
    if (videoWidget)
        connect(colorButton, SIGNAL(clicked()), this, SLOT(showColorDialog()));
    else
        colorButton->setEnabled(false);

    QBoxLayout *controlLayout = new QHBoxLayout;
    controlLayout->setMargin(0);
    controlLayout->addWidget(openButton);
    controlLayout->addStretch(1);
    controlLayout->addWidget(controls);
    controlLayout->addStretch(1);
    controlLayout->addWidget(fullscreenButton);
    controlLayout->addWidget(colorButton);

    QBoxLayout *layout = new QVBoxLayout;
    if (videoWidget) {
        QSplitter *splitter = new QSplitter(Qt::Vertical);

        splitter->addWidget(videoWidget);
        splitter->addWidget(playlistView);

        layout->addWidget(splitter);
    } else {
        layout->addWidget(coverLabel, 0, Qt::AlignCenter);
        layout->addWidget(playlistView);
    }
    layout->addWidget(slider);
    layout->addLayout(controlLayout);

    setLayout(layout);

    metaDataChanged();
}

Player::~Player()
{
    delete player;
}

void Player::open()
{
    QStringList fileNames = QFileDialog::getOpenFileNames();

    foreach (QString const &fileName, fileNames) {
#ifndef Q_OS_WIN
        playlist->appendItem(QMediaSource(QUrl(QLatin1String("file://") + fileName)));
#else
        playlist->appendItem(QMediaSource(QUrl(QLatin1String("file:///") + fileName)));
#endif
    }
}

void Player::durationChanged(qint64 duration)
{
    slider->setMaximum(duration / 1000);
}

void Player::positionChanged(qint64 progress)
{
    slider->setValue(progress / 1000);
}

void Player::metaDataChanged()
{
    //qDebug() << "update metadata" << player->metaData(QMediaObject::Title).toString();
    if (player->isMetaDataAvailable()) {
        setTrackInfo(QString("%1 - %2")
                .arg(player->metaData(QMediaObject::AlbumArtist).toString())
                .arg(player->metaData(QMediaObject::Title).toString()));

        if (coverLabel) {
            QUrl uri = player->metaData(QMediaObject::CoverArtUriLarge).value<QUrl>();

            coverLabel->setPixmap(!uri.isEmpty()
                    ? QPixmap(uri.toString())
                    : QPixmap());
        }
    }
}

void Player::jump(const QModelIndex &index)
{
    if (index.isValid()) {
        playlist->setCurrentPosition(index.row());
    }
}

void Player::playlistPositionChanged(int currentItem)
{
    playlistView->setCurrentIndex(playlistModel->index(currentItem, 0));
}

void Player::seek(int seconds)
{
    player->setPosition(seconds * 1000);
}

void Player::statusChanged(QMediaPlayer::MediaStatus status)
{
    switch (status) {
    case QMediaPlayer::UnknownMediaStatus:
    case QMediaPlayer::NoMedia:
    case QMediaPlayer::LoadedMedia:
    case QMediaPlayer::BufferingMedia:
    case QMediaPlayer::BufferedMedia:
#ifndef QT_NO_CURSOR
        unsetCursor();
#endif
        setStatusInfo(QString());
        break;
    case QMediaPlayer::LoadingMedia:
#ifndef QT_NO_CURSOR
        setCursor(QCursor(Qt::BusyCursor));
#endif
        setStatusInfo(tr("Loading..."));
        break;
    case QMediaPlayer::StalledMedia:
#ifndef QT_NO_CURSOR
        setCursor(QCursor(Qt::BusyCursor));
#endif
        break;
    case QMediaPlayer::EndOfMedia:
#ifndef QT_NO_CURSOR
        unsetCursor();
#endif
        setStatusInfo(QString());
        QApplication::alert(this);
        break;
    case QMediaPlayer::InvalidMedia:
#ifndef QT_NO_CURSOR
        unsetCursor();
#endif
        setStatusInfo(player->errorString());
        break;
    }
}

void Player::bufferingProgress(int progress)
{
    setStatusInfo(tr("Buffering %4%%").arg(progress));
}

void Player::setTrackInfo(const QString &info)
{
    trackInfo = info;

    if (!statusInfo.isEmpty())
        setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
    else
        setWindowTitle(trackInfo);

}

void Player::setStatusInfo(const QString &info)
{
    statusInfo = info;

    if (!statusInfo.isEmpty())
        setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
    else
        setWindowTitle(trackInfo);
}

void Player::setFullscreen(bool fullscreen)
{
    videoWidget->setDisplayMode(
            fullscreen ? QVideoWidget::FullscreenDisplay : QVideoWidget::WindowedDisplay);
}

void Player::displayModeChanged(QVideoWidget::DisplayMode mode)
{
    emit fullscreenChanged(mode == QVideoWidget::FullscreenDisplay);
}

void Player::showColorDialog()
{
    if (!colorDialog) {
        QSlider *brightnessSlider = new QSlider(Qt::Horizontal);
        brightnessSlider->setRange(-100, 100);
        brightnessSlider->setValue(videoWidget->brightness());
        connect(brightnessSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setBrightness(int)));
        connect(videoWidget, SIGNAL(brightnessChanged(int)), brightnessSlider, SLOT(setValue(int)));

        QSlider *contrastSlider = new QSlider(Qt::Horizontal);
        contrastSlider->setRange(-100, 100);
        contrastSlider->setValue(videoWidget->contrast());
        connect(contrastSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setContrast(int)));
        connect(videoWidget, SIGNAL(contrastChanged(int)), contrastSlider, SLOT(setValue(int)));

        QSlider *hueSlider = new QSlider(Qt::Horizontal);
        hueSlider->setRange(-100, 100);
        hueSlider->setValue(videoWidget->hue());
        connect(hueSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setHue(int)));
        connect(videoWidget, SIGNAL(hueChanged(int)), hueSlider, SLOT(setValue(int)));

        QSlider *saturationSlider = new QSlider(Qt::Horizontal);
        saturationSlider->setRange(-100, 100);
        saturationSlider->setValue(videoWidget->saturation());
        connect(saturationSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setSaturation(int)));
        connect(videoWidget, SIGNAL(saturationChanged(int)), saturationSlider, SLOT(setValue(int)));

        QFormLayout *layout = new QFormLayout;
        layout->addRow(tr("Brightness"), brightnessSlider);
        layout->addRow(tr("Contrast"), contrastSlider);
        layout->addRow(tr("Hue"), hueSlider);
        layout->addRow(tr("Saturation"), saturationSlider);

        colorDialog = new QDialog(this);
        colorDialog->setWindowTitle(tr("Color Options"));
        colorDialog->setLayout(layout);
    }
    colorDialog->show();
}
<commit_msg>Player; Use QUrl::fromLocalFile()<commit_after>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "player.h"

#include "playercontrols.h"
#include "playlistmodel.h"

#include <multimedia/qmediaservice.h>
#include <multimedia/qmediaplaylist.h>

#include <QtGui>

Player::Player(QWidget *parent)
    : QWidget(parent)
    , videoWidget(0)
    , coverLabel(0)
    , slider(0)
    , colorDialog(0)
{
    player = new QMediaPlayer;
    playlist = new QMediaPlaylist(player);

    connect(player, SIGNAL(durationChanged(qint64)), SLOT(durationChanged(qint64)));
    connect(player, SIGNAL(positionChanged(qint64)), SLOT(positionChanged(qint64)));
    connect(player, SIGNAL(metaDataChanged()), SLOT(metaDataChanged()));
    connect(playlist, SIGNAL(playlistPositionChanged(int)), SLOT(playlistPositionChanged(int)));
    connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
            this, SLOT(statusChanged(QMediaPlayer::MediaStatus)));
    connect(player, SIGNAL(bufferStatusChanged(int)), this, SLOT(bufferingProgress(int)));

    videoWidget = new QVideoWidget(player);

    connect(videoWidget, SIGNAL(displayModeChanged(QVideoWidget::DisplayMode)),
            this, SLOT(displayModeChanged(QVideoWidget::DisplayMode)));

    playlistModel = new PlaylistModel(this);
    playlistModel->setPlaylist(playlist);

    playlistView = new QTableView;
    playlistView->setModel(playlistModel);
    playlistView->setCurrentIndex(playlistModel->index(playlist->currentPosition(), 0));

    connect(playlistView, SIGNAL(activated(QModelIndex)), this, SLOT(jump(QModelIndex)));

    slider = new QSlider(Qt::Horizontal);
    slider->setRange(0, player->duration() / 1000);

    connect(slider, SIGNAL(sliderMoved(int)), this, SLOT(seek(int)));

    QPushButton *openButton = new QPushButton(tr("Open"));

    connect(openButton, SIGNAL(clicked()), this, SLOT(open()));

    PlayerControls *controls = new PlayerControls;
    controls->setState(player->state());
    controls->setVolume(player->volume());
    controls->setMuted(controls->isMuted());

    connect(controls, SIGNAL(play()), player, SLOT(play()));
    connect(controls, SIGNAL(pause()), player, SLOT(pause()));
    connect(controls, SIGNAL(stop()), player, SLOT(stop()));
    connect(controls, SIGNAL(next()), playlist, SLOT(advance()));
    connect(controls, SIGNAL(previous()), playlist, SLOT(back()));
    connect(controls, SIGNAL(changeVolume(int)), player, SLOT(setVolume(int)));
    connect(controls, SIGNAL(changeMuting(bool)), player, SLOT(setMuted(bool)));
    connect(controls, SIGNAL(changeRate(float)), player, SLOT(setPlaybackRate(float)));

    connect(player, SIGNAL(stateChanged(QMediaPlayer::State)),
            controls, SLOT(setState(QMediaPlayer::State)));
    connect(player, SIGNAL(volumeChanged(int)), controls, SLOT(setVolume(int)));
    connect(player, SIGNAL(mutingChanged(bool)), controls, SLOT(setMuted(bool)));

    QPushButton *fullscreenButton = new QPushButton(tr("Fullscreen"));
    fullscreenButton->setCheckable(true);

    connect(fullscreenButton, SIGNAL(clicked(bool)), this, SLOT(setFullscreen(bool)));
    connect(this, SIGNAL(fullscreenChanged(bool)), fullscreenButton, SLOT(setChecked(bool)));

    fullscreenButton->setEnabled(videoWidget != 0);

    QPushButton *colorButton = new QPushButton(tr("Color Options..."));
    if (videoWidget)
        connect(colorButton, SIGNAL(clicked()), this, SLOT(showColorDialog()));
    else
        colorButton->setEnabled(false);

    QBoxLayout *controlLayout = new QHBoxLayout;
    controlLayout->setMargin(0);
    controlLayout->addWidget(openButton);
    controlLayout->addStretch(1);
    controlLayout->addWidget(controls);
    controlLayout->addStretch(1);
    controlLayout->addWidget(fullscreenButton);
    controlLayout->addWidget(colorButton);

    QBoxLayout *layout = new QVBoxLayout;
    if (videoWidget) {
        QSplitter *splitter = new QSplitter(Qt::Vertical);

        splitter->addWidget(videoWidget);
        splitter->addWidget(playlistView);

        layout->addWidget(splitter);
    } else {
        layout->addWidget(coverLabel, 0, Qt::AlignCenter);
        layout->addWidget(playlistView);
    }
    layout->addWidget(slider);
    layout->addLayout(controlLayout);

    setLayout(layout);

    metaDataChanged();
}

Player::~Player()
{
    delete player;
}

void Player::open()
{
    QStringList fileNames = QFileDialog::getOpenFileNames();
    foreach (QString const &fileName, fileNames)
		playlist->appendItem(QMediaSource(QUrl::fromLocalFile(fileName)));
}

void Player::durationChanged(qint64 duration)
{
    slider->setMaximum(duration / 1000);
}

void Player::positionChanged(qint64 progress)
{
    slider->setValue(progress / 1000);
}

void Player::metaDataChanged()
{
    //qDebug() << "update metadata" << player->metaData(QMediaObject::Title).toString();
    if (player->isMetaDataAvailable()) {
        setTrackInfo(QString("%1 - %2")
                .arg(player->metaData(QMediaObject::AlbumArtist).toString())
                .arg(player->metaData(QMediaObject::Title).toString()));

        if (coverLabel) {
            QUrl uri = player->metaData(QMediaObject::CoverArtUriLarge).value<QUrl>();

            coverLabel->setPixmap(!uri.isEmpty()
                    ? QPixmap(uri.toString())
                    : QPixmap());
        }
    }
}

void Player::jump(const QModelIndex &index)
{
    if (index.isValid()) {
        playlist->setCurrentPosition(index.row());
    }
}

void Player::playlistPositionChanged(int currentItem)
{
    playlistView->setCurrentIndex(playlistModel->index(currentItem, 0));
}

void Player::seek(int seconds)
{
    player->setPosition(seconds * 1000);
}

void Player::statusChanged(QMediaPlayer::MediaStatus status)
{
    switch (status) {
    case QMediaPlayer::UnknownMediaStatus:
    case QMediaPlayer::NoMedia:
    case QMediaPlayer::LoadedMedia:
    case QMediaPlayer::BufferingMedia:
    case QMediaPlayer::BufferedMedia:
#ifndef QT_NO_CURSOR
        unsetCursor();
#endif
        setStatusInfo(QString());
        break;
    case QMediaPlayer::LoadingMedia:
#ifndef QT_NO_CURSOR
        setCursor(QCursor(Qt::BusyCursor));
#endif
        setStatusInfo(tr("Loading..."));
        break;
    case QMediaPlayer::StalledMedia:
#ifndef QT_NO_CURSOR
        setCursor(QCursor(Qt::BusyCursor));
#endif
        break;
    case QMediaPlayer::EndOfMedia:
#ifndef QT_NO_CURSOR
        unsetCursor();
#endif
        setStatusInfo(QString());
        QApplication::alert(this);
        break;
    case QMediaPlayer::InvalidMedia:
#ifndef QT_NO_CURSOR
        unsetCursor();
#endif
        setStatusInfo(player->errorString());
        break;
    }
}

void Player::bufferingProgress(int progress)
{
    setStatusInfo(tr("Buffering %4%%").arg(progress));
}

void Player::setTrackInfo(const QString &info)
{
    trackInfo = info;

    if (!statusInfo.isEmpty())
        setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
    else
        setWindowTitle(trackInfo);

}

void Player::setStatusInfo(const QString &info)
{
    statusInfo = info;

    if (!statusInfo.isEmpty())
        setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
    else
        setWindowTitle(trackInfo);
}

void Player::setFullscreen(bool fullscreen)
{
    videoWidget->setDisplayMode(
            fullscreen ? QVideoWidget::FullscreenDisplay : QVideoWidget::WindowedDisplay);
}

void Player::displayModeChanged(QVideoWidget::DisplayMode mode)
{
    emit fullscreenChanged(mode == QVideoWidget::FullscreenDisplay);
}

void Player::showColorDialog()
{
    if (!colorDialog) {
        QSlider *brightnessSlider = new QSlider(Qt::Horizontal);
        brightnessSlider->setRange(-100, 100);
        brightnessSlider->setValue(videoWidget->brightness());
        connect(brightnessSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setBrightness(int)));
        connect(videoWidget, SIGNAL(brightnessChanged(int)), brightnessSlider, SLOT(setValue(int)));

        QSlider *contrastSlider = new QSlider(Qt::Horizontal);
        contrastSlider->setRange(-100, 100);
        contrastSlider->setValue(videoWidget->contrast());
        connect(contrastSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setContrast(int)));
        connect(videoWidget, SIGNAL(contrastChanged(int)), contrastSlider, SLOT(setValue(int)));

        QSlider *hueSlider = new QSlider(Qt::Horizontal);
        hueSlider->setRange(-100, 100);
        hueSlider->setValue(videoWidget->hue());
        connect(hueSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setHue(int)));
        connect(videoWidget, SIGNAL(hueChanged(int)), hueSlider, SLOT(setValue(int)));

        QSlider *saturationSlider = new QSlider(Qt::Horizontal);
        saturationSlider->setRange(-100, 100);
        saturationSlider->setValue(videoWidget->saturation());
        connect(saturationSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setSaturation(int)));
        connect(videoWidget, SIGNAL(saturationChanged(int)), saturationSlider, SLOT(setValue(int)));

        QFormLayout *layout = new QFormLayout;
        layout->addRow(tr("Brightness"), brightnessSlider);
        layout->addRow(tr("Contrast"), contrastSlider);
        layout->addRow(tr("Hue"), hueSlider);
        layout->addRow(tr("Saturation"), saturationSlider);

        colorDialog = new QDialog(this);
        colorDialog->setWindowTitle(tr("Color Options"));
        colorDialog->setLayout(layout);
    }
    colorDialog->show();
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
//  Log.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#include <cstdio>
#include "Core/Log.h"
#include "Core/Assert.h"
#include "Core/Logger.h"
#include "Core/Threading/RWLock.h"
#include "Core/Containers/Array.h"

namespace Oryol {
namespace Core {

using namespace std;

Log::Level curLogLevel = Log::Level::Dbg;
RWLock lock;
Array<Ptr<Logger>> loggers;

//------------------------------------------------------------------------------
void
Log::AddLogger(const Ptr<Logger>& l) {
    if (l) {
        lock.LockWrite();
        loggers.AddBack(l);
        lock.UnlockWrite();
    }
}

//------------------------------------------------------------------------------
int32
Log::GetNumLoggers() {
    return loggers.Size();
}

//------------------------------------------------------------------------------
Ptr<Logger>
Log::GetLogger(int32 index) {
    return loggers[index];
}

//------------------------------------------------------------------------------
void
Log::SetLogLevel(Level l) {
    curLogLevel = l;
}

//------------------------------------------------------------------------------
Log::Level
Log::GetLogLevel() {
    return curLogLevel;
}

//------------------------------------------------------------------------------
void
Log::Dbg(const char* msg, ...) {
    if (curLogLevel >= Level::Dbg) {
        va_list args;
        va_start(args, msg);
        Log::vprint(Level::Dbg, msg, args);
        va_end(args);
    }
}

//------------------------------------------------------------------------------
void
Log::Info(const char* msg, ...) {
    if (curLogLevel >= Level::Info) {
        va_list args;
        va_start(args, msg);
        Log::vprint(Level::Info, msg, args);
        va_end(args);
    }
}

//------------------------------------------------------------------------------
void
Log::Warn(const char* msg, ...) {
    if (curLogLevel >= Level::Warn) {
        va_list args;
        va_start(args, msg);
        Log::vprint(Level::Warn, msg, args);
        va_end(args);
    }
}

//------------------------------------------------------------------------------
void
Log::Error(const char* msg, ...) {
    if (curLogLevel >= Level::Error) {
        va_list args;
        va_start(args, msg);
        Log::vprint(Level::Error, msg, args);
        va_end(args);
    }
}

//------------------------------------------------------------------------------
void
Log::vprint(Level lvl, const char* msg, va_list args) {
    lock.LockRead();
    if (loggers.Empty()) {
        std::vprintf(msg, args);
    }
    else {
        for (auto l : loggers) {
            l->VPrint(lvl, msg, args);
        }
    }
    lock.UnlockRead();
}

//------------------------------------------------------------------------------
void
Log::AssertMsg(const char* cond, const char* msg, const char* file, int32 line, const char* func) {
    lock.LockRead();
    if (loggers.Empty()) {
        std::printf("oryol assert: cond='%s' msg='%s', file='%s', line='%d', func='%s'\n",
                 cond, msg ? msg : "none", file, line, func);
    }
    else
    {
        for (const auto& l : loggers) {
            l->AssertMsg(cond, msg, file, line, func);
        }
    }
    lock.UnlockRead();
}

} // namespace Core
} // namespace Oryol
<commit_msg>Made o_assert console formatting more readable<commit_after>//------------------------------------------------------------------------------
//  Log.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#include <cstdio>
#include "Core/Log.h"
#include "Core/Assert.h"
#include "Core/Logger.h"
#include "Core/Threading/RWLock.h"
#include "Core/Containers/Array.h"

namespace Oryol {
namespace Core {

using namespace std;

Log::Level curLogLevel = Log::Level::Dbg;
RWLock lock;
Array<Ptr<Logger>> loggers;

//------------------------------------------------------------------------------
void
Log::AddLogger(const Ptr<Logger>& l) {
    if (l) {
        lock.LockWrite();
        loggers.AddBack(l);
        lock.UnlockWrite();
    }
}

//------------------------------------------------------------------------------
int32
Log::GetNumLoggers() {
    return loggers.Size();
}

//------------------------------------------------------------------------------
Ptr<Logger>
Log::GetLogger(int32 index) {
    return loggers[index];
}

//------------------------------------------------------------------------------
void
Log::SetLogLevel(Level l) {
    curLogLevel = l;
}

//------------------------------------------------------------------------------
Log::Level
Log::GetLogLevel() {
    return curLogLevel;
}

//------------------------------------------------------------------------------
void
Log::Dbg(const char* msg, ...) {
    if (curLogLevel >= Level::Dbg) {
        va_list args;
        va_start(args, msg);
        Log::vprint(Level::Dbg, msg, args);
        va_end(args);
    }
}

//------------------------------------------------------------------------------
void
Log::Info(const char* msg, ...) {
    if (curLogLevel >= Level::Info) {
        va_list args;
        va_start(args, msg);
        Log::vprint(Level::Info, msg, args);
        va_end(args);
    }
}

//------------------------------------------------------------------------------
void
Log::Warn(const char* msg, ...) {
    if (curLogLevel >= Level::Warn) {
        va_list args;
        va_start(args, msg);
        Log::vprint(Level::Warn, msg, args);
        va_end(args);
    }
}

//------------------------------------------------------------------------------
void
Log::Error(const char* msg, ...) {
    if (curLogLevel >= Level::Error) {
        va_list args;
        va_start(args, msg);
        Log::vprint(Level::Error, msg, args);
        va_end(args);
    }
}

//------------------------------------------------------------------------------
void
Log::vprint(Level lvl, const char* msg, va_list args) {
    lock.LockRead();
    if (loggers.Empty()) {
        std::vprintf(msg, args);
    }
    else {
        for (auto l : loggers) {
            l->VPrint(lvl, msg, args);
        }
    }
    lock.UnlockRead();
}

//------------------------------------------------------------------------------
void
Log::AssertMsg(const char* cond, const char* msg, const char* file, int32 line, const char* func) {
    lock.LockRead();
    if (loggers.Empty()) {
        std::printf("oryol assert: cond='%s'\nmsg='%s'\nfile='%s'\nline='%d'\nfunc='%s'\n",
                 cond, msg ? msg : "none", file, line, func);
    }
    else
    {
        for (const auto& l : loggers) {
            l->AssertMsg(cond, msg, file, line, func);
        }
    }
    lock.UnlockRead();
}

} // namespace Core
} // namespace Oryol
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////
// This file is part of Grappa, a system for scaling irregular
// applications on commodity clusters.

// Copyright (C) 2010-2014 University of Washington and Battelle
// Memorial Institute. University of Washington authorizes use of this
// Grappa software.

// Grappa is free software: you can redistribute it and/or modify it
// under the terms of the Affero General Public License as published
// by Affero, Inc., either version 1 of the License, or (at your
// option) any later version.

// Grappa is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// Affero General Public License for more details.

// You should have received a copy of the Affero General Public
// License along with this program. If not, you may obtain one from
// http://www.affero.org/oagpl.html.
////////////////////////////////////////////////////////////////////////
#pragma once

#include "Addressing.hpp"
#include "Communicator.hpp"
#include "Collective.hpp"
#include "Cache.hpp"
#include "GlobalCompletionEvent.hpp"
#include "ParallelLoop.hpp"
#include "GlobalAllocator.hpp"
#include <type_traits>
#include "Delegate.hpp"

namespace Grappa {
/// @addtogroup Containers
/// @{

/// Initialize an array of elements of generic type with a given value.
///
/// This version sends a large number of active messages, the same way as the Incoherent
/// releaser, to set each part of a global array. In theory, this version should be able
/// to be called from multiple locations at the same time (to initialize different regions of global memory).
///
/// @param base Base address of the array to be set.
/// @param value Value to set every element of array to (will be copied to all the nodes)
/// @param count Number of elements to set, starting at the base address.
template< typename T, typename S >
void memset(GlobalAddress<T> base, S value, size_t count) {
  call_on_all_cores([base,count,value]{
    T * local_base = base.localize();
    T * local_end = (base+count).localize();
    for (size_t i=0; i<local_end-local_base; i++) {
      local_base[i] = value;
    }
  });
}

/// Type-based memset for local arrays to match what is provided for distributed arrays.
template< typename T, typename S >
void memset(T* base, S value, size_t count) {
  for (size_t i=0; i < count; i++) {
    base[i] = value;
  }
}

namespace impl {
  /// Copy elements of array (src..src+nelem) that are local to corresponding locations in dst
  template< typename T >
  void do_memcpy_locally(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
    typedef typename Incoherent<T>::WO Writeback;
    auto src_end = src+nelem;
    // T * local_base = src.localize(), * local_end = (src+nelem).localize();
    int64_t nfirstcore = src.block_max() - src;
    int64_t nlastcore = src_end - src_end.block_min();
    int64_t nmiddle = nelem - nfirstcore - nlastcore;

    const size_t nblock = block_size / sizeof(T);

    CHECK_EQ(nmiddle % nblock, 0);

    auto src_start = src;
    if (src.core() == mycore()) {
      int64_t nfirstcore = src.block_max() - src;
      if (nfirstcore > 0 && nlastcore != nblock) {
        DVLOG(3) << "nfirstcore = " << nfirstcore;
        Writeback w(dst, nfirstcore, src.pointer());
        src_start += nfirstcore;
      }
    }
    if ((src_end-1).core() == mycore()) {
      int64_t nlastcore = src_end - src_end.block_min();
      int64_t index = nelem - nlastcore;
      if (nlastcore > 0 && nlastcore != nblock) {
        DVLOG(3) << "nlastcore = " << nlastcore << ", index = " << index;
        CHECK((src+index).core() == mycore());
        Writeback w(dst+index, nlastcore, (src+index).pointer());
        src_end -= nlastcore;
      }
    }

    auto * local_base = src_start.localize();
    size_t nlocal_trimmed = src_end.localize() - local_base;
    CHECK_EQ((nlocal_trimmed) % nblock, 0);
    size_t nlocalblocks = nlocal_trimmed/nblock;
    Writeback * ws = locale_alloc<Writeback>(nlocalblocks);
    for (size_t i=0; i<nlocalblocks; i++) {
      size_t j = make_linear(local_base+(i*nblock))-src;
      new (ws+i) Writeback(dst+j, nblock, local_base+(i*nblock));
      ws[i].start_release();
    }
    for (size_t i=0; i<nlocalblocks; i++) { ws[i].block_until_released(); }
    locale_free(ws);
  }
}

/// Memcpy over Grappa global arrays. Arguments `dst` and `src` must point into global arrays
/// (so must be linear addresses) and be non-overlapping, and both must have at least `nelem`
/// elements.
template< typename T >
void memcpy(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
  on_all_cores([dst,src,nelem]{
    impl::do_memcpy_locally(dst,src,nelem);
  });
}

/// Helper so we don't have to change the code if we change a Global pointer to a normal pointer (in theory).
template< typename T >
inline void memcpy(T* dst, T* src, size_t nelem) {
  ::memcpy(dst, src, nelem*sizeof(T));
}

template<>
inline void memcpy<void>(void* dst, void* src, size_t nelem) {
  ::memcpy(dst, src, nelem);
}

/// Asynchronous version of memcpy, spawns only on cores with array elements. Synchronizes
/// with given GlobalCompletionEvent, so memcpy's are known to be complete after GCE->wait().
/// Note: same restrictions on `dst` and `src` as Grappa::memcpy).
template< GlobalCompletionEvent * GCE = &impl::local_gce, typename T = void >
void memcpy_async(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
  on_cores_localized_async<GCE>(src, nelem, [dst,src,nelem](T* base, size_t nlocal){
    impl::do_memcpy_locally(dst,src,nelem);
  });
}

/// not implemented yet
template< typename T >
void prefix_sum(GlobalAddress<T> array, size_t nelem) {
  // not implemented
  CHECK(false) << "prefix_sum is currently unimplemented!";
}

namespace util {
  /// String representation of a local array, matches form of Grappa::array_str that takes a global array.
  template<typename T>
  inline std::string array_str(const char * name, T * base, size_t nelem, int width = 10) {
    std::stringstream ss;
    if (name) {
      ss << "\n" << name << ": ";
    }
    ss << "[";
    for (size_t i=0; i<nelem; i++) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << base[i];
    }
    ss << "\n]";
    return ss.str();
  }

  /// String representation of a global array.
  /// @example
  /// @code
  ///   GlobalAddress<int> xs;
  ///   DVLOG(2) << array_str("x", xs, 4);
  /// // (if DEBUG=1 and --v=2)
  /// //> x: [
  /// //>  7 4 2 3
  /// //> ]
  /// @endcode
  template<typename T>
  inline std::string array_str(const char * name, GlobalAddress<T> base, size_t nelem, int width = 10) {
    std::stringstream ss; ss << "\n" << name << ": [";
    for (size_t i=0; i<nelem; i++) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << delegate::read(base+i);
    }
    ss << "\n]";
    return ss.str();
  }

  template< typename ArrayT, class = typename std::enable_if<std::is_array<ArrayT>::value>::type >
  inline std::string array_str(const char * name, ArrayT array, int width = 10) {
    std::stringstream ss;
    if (name) {
      ss << "\n" << name << ": ";
    }
    ss << "[";
    long i=0;
    for (auto e : array) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << e;
      i++;
    }
    ss << "\n]";
    return ss.str();
  }

  template<typename T>
  struct SimpleIterator {
    T * base;
    size_t nelem;
    T * begin() { return base; }
    T * end()   { return base+nelem; }
  };

  /// Easier C++11 iteration over local array. Similar idea to Addressing::iterate_local().
  ///
  /// @code
  ///   auto array = new long[N];
  ///   for (auto& v : util::iterate(array,N)) {
  ///     v++;
  ///   }
  /// @endcode
  template<typename T>
  SimpleIterator<T> iterate(T* base = nullptr, size_t nelem = 0) { return SimpleIterator<T>{base, nelem}; }

} // namespace util

/// @}
} // namespace Grappa

template< typename T >
std::ostream& operator<<(std::ostream& o, std::vector<T> v) {
  o << Grappa::util::array_str(nullptr, &v[0], v.size());
  return o;
}
<commit_msg>allow array_str() on anything that supports range-based for<commit_after>////////////////////////////////////////////////////////////////////////
// This file is part of Grappa, a system for scaling irregular
// applications on commodity clusters.

// Copyright (C) 2010-2014 University of Washington and Battelle
// Memorial Institute. University of Washington authorizes use of this
// Grappa software.

// Grappa is free software: you can redistribute it and/or modify it
// under the terms of the Affero General Public License as published
// by Affero, Inc., either version 1 of the License, or (at your
// option) any later version.

// Grappa is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// Affero General Public License for more details.

// You should have received a copy of the Affero General Public
// License along with this program. If not, you may obtain one from
// http://www.affero.org/oagpl.html.
////////////////////////////////////////////////////////////////////////
#pragma once

#include "Addressing.hpp"
#include "Communicator.hpp"
#include "Collective.hpp"
#include "Cache.hpp"
#include "GlobalCompletionEvent.hpp"
#include "ParallelLoop.hpp"
#include "GlobalAllocator.hpp"
#include <type_traits>
#include "Delegate.hpp"

namespace Grappa {
/// @addtogroup Containers
/// @{

/// Initialize an array of elements of generic type with a given value.
///
/// This version sends a large number of active messages, the same way as the Incoherent
/// releaser, to set each part of a global array. In theory, this version should be able
/// to be called from multiple locations at the same time (to initialize different regions of global memory).
///
/// @param base Base address of the array to be set.
/// @param value Value to set every element of array to (will be copied to all the nodes)
/// @param count Number of elements to set, starting at the base address.
template< typename T, typename S >
void memset(GlobalAddress<T> base, S value, size_t count) {
  call_on_all_cores([base,count,value]{
    T * local_base = base.localize();
    T * local_end = (base+count).localize();
    for (size_t i=0; i<local_end-local_base; i++) {
      local_base[i] = value;
    }
  });
}

/// Type-based memset for local arrays to match what is provided for distributed arrays.
template< typename T, typename S >
void memset(T* base, S value, size_t count) {
  for (size_t i=0; i < count; i++) {
    base[i] = value;
  }
}

namespace impl {
  /// Copy elements of array (src..src+nelem) that are local to corresponding locations in dst
  template< typename T >
  void do_memcpy_locally(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
    typedef typename Incoherent<T>::WO Writeback;
    auto src_end = src+nelem;
    // T * local_base = src.localize(), * local_end = (src+nelem).localize();
    int64_t nfirstcore = src.block_max() - src;
    int64_t nlastcore = src_end - src_end.block_min();
    int64_t nmiddle = nelem - nfirstcore - nlastcore;

    const size_t nblock = block_size / sizeof(T);

    CHECK_EQ(nmiddle % nblock, 0);

    auto src_start = src;
    if (src.core() == mycore()) {
      int64_t nfirstcore = src.block_max() - src;
      if (nfirstcore > 0 && nlastcore != nblock) {
        DVLOG(3) << "nfirstcore = " << nfirstcore;
        Writeback w(dst, nfirstcore, src.pointer());
        src_start += nfirstcore;
      }
    }
    if ((src_end-1).core() == mycore()) {
      int64_t nlastcore = src_end - src_end.block_min();
      int64_t index = nelem - nlastcore;
      if (nlastcore > 0 && nlastcore != nblock) {
        DVLOG(3) << "nlastcore = " << nlastcore << ", index = " << index;
        CHECK((src+index).core() == mycore());
        Writeback w(dst+index, nlastcore, (src+index).pointer());
        src_end -= nlastcore;
      }
    }

    auto * local_base = src_start.localize();
    size_t nlocal_trimmed = src_end.localize() - local_base;
    CHECK_EQ((nlocal_trimmed) % nblock, 0);
    size_t nlocalblocks = nlocal_trimmed/nblock;
    Writeback * ws = locale_alloc<Writeback>(nlocalblocks);
    for (size_t i=0; i<nlocalblocks; i++) {
      size_t j = make_linear(local_base+(i*nblock))-src;
      new (ws+i) Writeback(dst+j, nblock, local_base+(i*nblock));
      ws[i].start_release();
    }
    for (size_t i=0; i<nlocalblocks; i++) { ws[i].block_until_released(); }
    locale_free(ws);
  }
}

/// Memcpy over Grappa global arrays. Arguments `dst` and `src` must point into global arrays
/// (so must be linear addresses) and be non-overlapping, and both must have at least `nelem`
/// elements.
template< typename T >
void memcpy(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
  on_all_cores([dst,src,nelem]{
    impl::do_memcpy_locally(dst,src,nelem);
  });
}

/// Helper so we don't have to change the code if we change a Global pointer to a normal pointer (in theory).
template< typename T >
inline void memcpy(T* dst, T* src, size_t nelem) {
  ::memcpy(dst, src, nelem*sizeof(T));
}

template<>
inline void memcpy<void>(void* dst, void* src, size_t nelem) {
  ::memcpy(dst, src, nelem);
}

/// Asynchronous version of memcpy, spawns only on cores with array elements. Synchronizes
/// with given GlobalCompletionEvent, so memcpy's are known to be complete after GCE->wait().
/// Note: same restrictions on `dst` and `src` as Grappa::memcpy).
template< GlobalCompletionEvent * GCE = &impl::local_gce, typename T = void >
void memcpy_async(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
  on_cores_localized_async<GCE>(src, nelem, [dst,src,nelem](T* base, size_t nlocal){
    impl::do_memcpy_locally(dst,src,nelem);
  });
}

/// not implemented yet
template< typename T >
void prefix_sum(GlobalAddress<T> array, size_t nelem) {
  // not implemented
  CHECK(false) << "prefix_sum is currently unimplemented!";
}

namespace util {
  /// String representation of a local array, matches form of Grappa::array_str that takes a global array.
  template<typename T>
  inline std::string array_str(const char * name, T * base, size_t nelem, int width = 10) {
    std::stringstream ss;
    if (name) {
      ss << "\n" << name << ": ";
    }
    ss << "[";
    for (size_t i=0; i<nelem; i++) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << base[i];
    }
    ss << "\n]";
    return ss.str();
  }

  /// String representation of a global array.
  /// @example
  /// @code
  ///   GlobalAddress<int> xs;
  ///   DVLOG(2) << array_str("x", xs, 4);
  /// // (if DEBUG=1 and --v=2)
  /// //> x: [
  /// //>  7 4 2 3
  /// //> ]
  /// @endcode
  template<typename T>
  inline std::string array_str(const char * name, GlobalAddress<T> base, size_t nelem, int width = 10) {
    std::stringstream ss; ss << "\n" << name << ": [";
    for (size_t i=0; i<nelem; i++) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << delegate::read(base+i);
    }
    ss << "\n]";
    return ss.str();
  }

  // template< typename ArrayT, class = typename std::enable_if<std::is_array<ArrayT>::value>::type >
  template< typename ArrayT, int width = 10 >
  inline std::string array_str(const char * name, const ArrayT& array) {
    std::stringstream ss;
    if (name) {
      ss << "\n" << name << ": ";
    }
    ss << "[";
    long i=0;
    for (auto e : array) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << e;
      i++;
    }
    ss << "\n]";
    return ss.str();
  }

  template<typename T>
  struct SimpleIterator {
    T * base;
    size_t nelem;
    T * begin() { return base; }
    T * end()   { return base+nelem; }
  };

  /// Easier C++11 iteration over local array. Similar idea to Addressing::iterate_local().
  ///
  /// @code
  ///   auto array = new long[N];
  ///   for (auto& v : util::iterate(array,N)) {
  ///     v++;
  ///   }
  /// @endcode
  template<typename T>
  SimpleIterator<T> iterate(T* base = nullptr, size_t nelem = 0) { return SimpleIterator<T>{base, nelem}; }

} // namespace util

/// @}
} // namespace Grappa

template< typename T >
std::ostream& operator<<(std::ostream& o, std::vector<T> v) {
  o << Grappa::util::array_str(nullptr, &v[0], v.size());
  return o;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/env_var.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "base/test/test_file_util.h"
#include "base/time.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
#include "chrome/test/ui/ui_test.h"
#include "chrome/test/ui_test_utils.h"

using base::TimeDelta;
using base::TimeTicks;

namespace {

class StartupTest : public UITest {
 public:
  StartupTest() {
    show_window_ = true;
  }
  void SetUp() {}
  void TearDown() {}

  // Load a file on startup rather than about:blank.  This tests a longer
  // startup path, including resource loading and the loading of gears.dll.
  void SetUpWithFileURL() {
    const FilePath file_url = ui_test_utils::GetTestFilePath(
        FilePath(FilePath::kCurrentDirectory),
        FilePath(FILE_PATH_LITERAL("simple.html")));
    ASSERT_TRUE(file_util::PathExists(file_url));
    launch_arguments_.AppendLooseValue(file_url.ToWStringHack());
  }

  // Use the given profile in the test data extensions/profiles dir.  This tests
  // startup with extensions installed.
  void SetUpWithExtensionsProfile(const char* profile) {
    FilePath data_dir;
    PathService::Get(chrome::DIR_TEST_DATA, &data_dir);
    data_dir = data_dir.AppendASCII("extensions").AppendASCII("profiles").
        AppendASCII(profile);
    set_template_user_data(data_dir);

    // For now, these tests still depend on toolstrips.
    launch_arguments_.AppendSwitch(switches::kEnableExtensionToolstrips);
  }

  void RunStartupTest(const char* graph, const char* trace,
      bool test_cold, bool important, UITest::ProfileType profile_type) {
    profile_type_ = profile_type;

    // Sets the profile data for the run.  For now, this is only used for
    // the non-default themes test.
    if (profile_type != UITest::DEFAULT_THEME) {
      set_template_user_data(UITest::ComputeTypicalUserDataSource(
          profile_type));
    }

    const int kNumCyclesMax = 20;
    int numCycles = kNumCyclesMax;
    scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
    std::string numCyclesEnv;
    if (env->GetEnv(env_vars::kStartupTestsNumCycles, &numCyclesEnv) &&
        StringToInt(numCyclesEnv, &numCycles)) {
      if (numCycles <= kNumCyclesMax) {
        LOG(INFO) << env_vars::kStartupTestsNumCycles
                  << " set in environment, so setting numCycles to "
                  << numCycles;
      } else {
        LOG(INFO) << env_vars::kStartupTestsNumCycles
                  << " is higher than the max, setting numCycles to "
                  << kNumCyclesMax;
        numCycles = kNumCyclesMax;
      }
    }

    TimeDelta timings[kNumCyclesMax];
    for (int i = 0; i < numCycles; ++i) {
      if (test_cold) {
        FilePath dir_app;
        ASSERT_TRUE(PathService::Get(chrome::DIR_APP, &dir_app));

        FilePath chrome_exe(dir_app.Append(
            FilePath::FromWStringHack(chrome::kBrowserProcessExecutablePath)));
        ASSERT_TRUE(EvictFileFromSystemCacheWrapper(chrome_exe));
#if defined(OS_WIN)
        // chrome.dll is windows specific.
        FilePath chrome_dll(dir_app.Append(FILE_PATH_LITERAL("chrome.dll")));
        ASSERT_TRUE(EvictFileFromSystemCacheWrapper(chrome_dll));
#endif

#if defined(OS_WIN)
        // TODO(port): Re-enable once gears is working on mac/linux.
        FilePath gears_dll;
        ASSERT_TRUE(PathService::Get(chrome::FILE_GEARS_PLUGIN, &gears_dll));
        ASSERT_TRUE(EvictFileFromSystemCacheWrapper(gears_dll));
#else
        NOTIMPLEMENTED() << "gears not enabled yet";
#endif
      }
      UITest::SetUp();
      TimeTicks end_time = TimeTicks::Now();
      timings[i] = end_time - browser_launch_time_;
      UITest::TearDown();

      if (i == 0) {
        // Re-use the profile data after first run so that the noise from
        // creating databases doesn't impact all the runs.
        clear_profile_ = false;
        // Clear template_user_data_ so we don't try to copy it over each time
        // through.
        set_template_user_data(FilePath());
      }
    }

    std::string times;
    for (int i = 0; i < numCycles; ++i)
      StringAppendF(&times, "%.2f,", timings[i].InMillisecondsF());
    PrintResultList(graph, "", trace, times, "ms", important);
  }
};

TEST_F(StartupTest, PerfWarm) {
  RunStartupTest("warm", "t", false /* not cold */, true /* important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfReferenceWarm) {
  UseReferenceBuild();
  RunStartupTest("warm", "t_ref", false /* not cold */,
                 true /* important */, UITest::DEFAULT_THEME);
}

// TODO(mpcomplete): Should we have reference timings for all these?

TEST_F(StartupTest, PerfCold) {
  RunStartupTest("cold", "t", true /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfExtensionEmpty) {
  SetUpWithFileURL();
  SetUpWithExtensionsProfile("empty");
  RunStartupTest("warm", "extension_empty",
                 false /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfExtensionToolstrips1) {
  SetUpWithFileURL();
  SetUpWithExtensionsProfile("toolstrips1");
  RunStartupTest("warm", "extension_toolstrip1",
                 false /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfExtensionToolstrips50) {
  SetUpWithFileURL();
  SetUpWithExtensionsProfile("toolstrips50");
  RunStartupTest("warm", "extension_toolstrip50",
                 false /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfExtensionContentScript1) {
  SetUpWithFileURL();
  SetUpWithExtensionsProfile("content_scripts1");
  RunStartupTest("warm", "extension_content_scripts1",
                 false /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfExtensionContentScript50) {
  SetUpWithFileURL();
  SetUpWithExtensionsProfile("content_scripts50");
  RunStartupTest("warm", "extension_content_scripts50",
                 false /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

#if defined(OS_WIN)
// TODO(port): Enable gears tests on linux/mac once gears is working.
TEST_F(StartupTest, PerfGears) {
  SetUpWithFileURL();
  RunStartupTest("warm", "gears", false /* not cold */,
                 false /* not important */, UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfColdGears) {
  SetUpWithFileURL();
  RunStartupTest("cold", "gears", true /* cold */,
                 false /* not important */, UITest::DEFAULT_THEME);
}
#endif

TEST_F(StartupTest, PerfColdComplexTheme) {
  RunStartupTest("warm", "t-theme", false /* warm */,
                 false /* not important */, UITest::COMPLEX_THEME);
}

#if defined(OS_LINUX)
TEST_F(StartupTest, PerfColdGtkTheme) {
  RunStartupTest("warm", "gtk-theme", false /* warm */,
                 false /* not important */, UITest::NATIVE_THEME);
}

TEST_F(StartupTest, PrefColdNativeFrame) {
  RunStartupTest("warm", "custom-frame", false /* warm */,
                 false /* not important */, UITest::CUSTOM_FRAME);
}

TEST_F(StartupTest, PerfColdNativeFrameGtkTheme) {
  RunStartupTest("warm", "custom-frame-gtk-theme", false /* warm */,
                 false /* not important */, UITest::CUSTOM_FRAME_NATIVE_THEME);
}
#endif

}  // namespace
<commit_msg>Test end-to-end startup performance of loading several tabs.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/env_var.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "base/test/test_file_util.h"
#include "base/time.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
#include "chrome/test/ui/ui_test.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/net_util.h"

using base::TimeDelta;
using base::TimeTicks;

namespace {

class StartupTest : public UITest {
 public:
  StartupTest() {
    show_window_ = true;
  }
  void SetUp() {}
  void TearDown() {}

  // Load a file on startup rather than about:blank.  This tests a longer
  // startup path, including resource loading and the loading of gears.dll.
  void SetUpWithFileURL() {
    const FilePath file_url = ui_test_utils::GetTestFilePath(
        FilePath(FilePath::kCurrentDirectory),
        FilePath(FILE_PATH_LITERAL("simple.html")));
    ASSERT_TRUE(file_util::PathExists(file_url));
    launch_arguments_.AppendLooseValue(file_url.ToWStringHack());
  }

  // Load a complex html file on startup represented by |which_tab|.
  void SetUpWithComplexFileURL(unsigned int which_tab) {
    const char* const kTestPageCyclerDomains[] = {
        "www.google.com", "www.nytimes.com",
        "www.yahoo.com", "espn.go.com", "www.amazon.com"
    };
    unsigned int which_el = which_tab % arraysize(kTestPageCyclerDomains);
    const char* this_domain = kTestPageCyclerDomains[which_el];

    FilePath page_cycler_path;
    PathService::Get(base::DIR_SOURCE_ROOT, &page_cycler_path);
    page_cycler_path = page_cycler_path.AppendASCII("data")
        .AppendASCII("page_cycler").AppendASCII("moz")
        .AppendASCII(this_domain).AppendASCII("index.html");
    GURL file_url = net::FilePathToFileURL(page_cycler_path).Resolve("?skip");
    launch_arguments_.AppendLooseValue(ASCIIToWide(file_url.spec()));
  }

  // Use the given profile in the test data extensions/profiles dir.  This tests
  // startup with extensions installed.
  void SetUpWithExtensionsProfile(const char* profile) {
    FilePath data_dir;
    PathService::Get(chrome::DIR_TEST_DATA, &data_dir);
    data_dir = data_dir.AppendASCII("extensions").AppendASCII("profiles").
        AppendASCII(profile);
    set_template_user_data(data_dir);

    // For now, these tests still depend on toolstrips.
    launch_arguments_.AppendSwitch(switches::kEnableExtensionToolstrips);
  }

  void RunPerfTestWithManyTabs(const char *test_name,
      int tab_count, bool restore_session);

  void RunStartupTest(const char* graph, const char* trace,
      bool test_cold, bool important, UITest::ProfileType profile_type) {
    profile_type_ = profile_type;

    // Sets the profile data for the run.  For now, this is only used for
    // the non-default themes test.
    if (profile_type != UITest::DEFAULT_THEME) {
      set_template_user_data(UITest::ComputeTypicalUserDataSource(
          profile_type));
    }

    const int kNumCyclesMax = 20;
    int numCycles = kNumCyclesMax;
    scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
    std::string numCyclesEnv;
    if (env->GetEnv(env_vars::kStartupTestsNumCycles, &numCyclesEnv) &&
        StringToInt(numCyclesEnv, &numCycles)) {
      if (numCycles <= kNumCyclesMax) {
        LOG(INFO) << env_vars::kStartupTestsNumCycles
                  << " set in environment, so setting numCycles to "
                  << numCycles;
      } else {
        LOG(INFO) << env_vars::kStartupTestsNumCycles
                  << " is higher than the max, setting numCycles to "
                  << kNumCyclesMax;
        numCycles = kNumCyclesMax;
      }
    }

    TimeDelta timings[kNumCyclesMax];
    for (int i = 0; i < numCycles; ++i) {
      if (test_cold) {
        FilePath dir_app;
        ASSERT_TRUE(PathService::Get(chrome::DIR_APP, &dir_app));

        FilePath chrome_exe(dir_app.Append(
            FilePath::FromWStringHack(chrome::kBrowserProcessExecutablePath)));
        ASSERT_TRUE(EvictFileFromSystemCacheWrapper(chrome_exe));
#if defined(OS_WIN)
        // chrome.dll is windows specific.
        FilePath chrome_dll(dir_app.Append(FILE_PATH_LITERAL("chrome.dll")));
        ASSERT_TRUE(EvictFileFromSystemCacheWrapper(chrome_dll));
#endif

#if defined(OS_WIN)
        // TODO(port): Re-enable once gears is working on mac/linux.
        FilePath gears_dll;
        ASSERT_TRUE(PathService::Get(chrome::FILE_GEARS_PLUGIN, &gears_dll));
        ASSERT_TRUE(EvictFileFromSystemCacheWrapper(gears_dll));
#else
        NOTIMPLEMENTED() << "gears not enabled yet";
#endif
      }
      UITest::SetUp();
      TimeTicks end_time = TimeTicks::Now();
      timings[i] = end_time - browser_launch_time_;
      UITest::TearDown();

      if (i == 0) {
        // Re-use the profile data after first run so that the noise from
        // creating databases doesn't impact all the runs.
        clear_profile_ = false;
        // Clear template_user_data_ so we don't try to copy it over each time
        // through.
        set_template_user_data(FilePath());
      }
    }

    std::string times;
    for (int i = 0; i < numCycles; ++i)
      StringAppendF(&times, "%.2f,", timings[i].InMillisecondsF());
    PrintResultList(graph, "", trace, times, "ms", important);
  }
};

TEST_F(StartupTest, PerfWarm) {
  RunStartupTest("warm", "t", false /* not cold */, true /* important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfReferenceWarm) {
  UseReferenceBuild();
  RunStartupTest("warm", "t_ref", false /* not cold */,
                 true /* important */, UITest::DEFAULT_THEME);
}

// TODO(mpcomplete): Should we have reference timings for all these?

TEST_F(StartupTest, PerfCold) {
  RunStartupTest("cold", "t", true /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

void StartupTest::RunPerfTestWithManyTabs(const char *test_name,
    int tab_count, bool restore_session) {
  // Initialize session with |tab_count| tabs.
  for (int i = 0; i < tab_count; ++i)
    SetUpWithComplexFileURL(i);

  if (restore_session) {
    // Start the browser with these urls so we can save the session and exit.
    UITest::SetUp();
    // Set flags to ensure profile is saved and can be restored.
#if defined(OS_MACOSX)
    shutdown_type_ = UITestBase::USER_QUIT;
#endif
    clear_profile_ = false;
    // Quit and set flags to restore session.
    UITest::TearDown();
    // Clear all arguments for session restore, or the number of open tabs
    // will grow with each restore.
    launch_arguments_ = CommandLine(CommandLine::ARGUMENTS_ONLY);
    // The session will be restored once per cycle for numCycles test cycles,
    // and each time, UITest::SetUp will wait for |tab_count| tabs to
    // finish loading.
    launch_arguments_.AppendSwitchWithValue(switches::kRestoreLastSession,
                                            IntToWString(tab_count));
  }
  RunStartupTest("warm", test_name,
                 false, false,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfFewTabs) {
  RunPerfTestWithManyTabs("few_tabs", 5, false);
}

TEST_F(StartupTest, PerfSeveralTabs) {
  RunPerfTestWithManyTabs("several_tabs", 20, false);
}

TEST_F(StartupTest, PerfRestoreFewTabs) {
  RunPerfTestWithManyTabs("restore_few_tabs", 5, true);
}

TEST_F(StartupTest, PerfRestoreSeveralTabs) {
  RunPerfTestWithManyTabs("restore_several_tabs", 20, true);
}

TEST_F(StartupTest, PerfExtensionEmpty) {
  SetUpWithFileURL();
  SetUpWithExtensionsProfile("empty");
  RunStartupTest("warm", "extension_empty",
                 false /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfExtensionToolstrips1) {
  SetUpWithFileURL();
  SetUpWithExtensionsProfile("toolstrips1");
  RunStartupTest("warm", "extension_toolstrip1",
                 false /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfExtensionToolstrips50) {
  SetUpWithFileURL();
  SetUpWithExtensionsProfile("toolstrips50");
  RunStartupTest("warm", "extension_toolstrip50",
                 false /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfExtensionContentScript1) {
  SetUpWithFileURL();
  SetUpWithExtensionsProfile("content_scripts1");
  RunStartupTest("warm", "extension_content_scripts1",
                 false /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfExtensionContentScript50) {
  SetUpWithFileURL();
  SetUpWithExtensionsProfile("content_scripts50");
  RunStartupTest("warm", "extension_content_scripts50",
                 false /* cold */, false /* not important */,
                 UITest::DEFAULT_THEME);
}

#if defined(OS_WIN)
// TODO(port): Enable gears tests on linux/mac once gears is working.
TEST_F(StartupTest, PerfGears) {
  SetUpWithFileURL();
  RunStartupTest("warm", "gears", false /* not cold */,
                 false /* not important */, UITest::DEFAULT_THEME);
}

TEST_F(StartupTest, PerfColdGears) {
  SetUpWithFileURL();
  RunStartupTest("cold", "gears", true /* cold */,
                 false /* not important */, UITest::DEFAULT_THEME);
}
#endif

TEST_F(StartupTest, PerfColdComplexTheme) {
  RunStartupTest("warm", "t-theme", false /* warm */,
                 false /* not important */, UITest::COMPLEX_THEME);
}

#if defined(OS_LINUX)
TEST_F(StartupTest, PerfColdGtkTheme) {
  RunStartupTest("warm", "gtk-theme", false /* warm */,
                 false /* not important */, UITest::NATIVE_THEME);
}

TEST_F(StartupTest, PrefColdNativeFrame) {
  RunStartupTest("warm", "custom-frame", false /* warm */,
                 false /* not important */, UITest::CUSTOM_FRAME);
}

TEST_F(StartupTest, PerfColdNativeFrameGtkTheme) {
  RunStartupTest("warm", "custom-frame-gtk-theme", false /* warm */,
                 false /* not important */, UITest::CUSTOM_FRAME_NATIVE_THEME);
}
#endif

}  // namespace
<|endoftext|>