<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

// MOOSE includes
#include "MaterialPropertyInterface.h"
#include "MooseApp.h"
#include "Material.h"

template <>
InputParameters
validParams<MaterialPropertyInterface>()
{
  InputParameters params = emptyInputParameters();
  params.addPrivateParam<Moose::MaterialDataType>(
      "_material_data_type"); // optionally force the type of MaterialData to utilize
  return params;
}

MaterialPropertyInterface::MaterialPropertyInterface(const MooseObject * moose_object,
                                                     const std::set<SubdomainID> & block_ids,
                                                     const std::set<BoundaryID> & boundary_ids)
  : _mi_params(moose_object->parameters()),
    _mi_name(_mi_params.get<std::string>("_object_name")),
    _mi_feproblem(*_mi_params.getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")),
    _mi_tid(_mi_params.get<THREAD_ID>("_tid")),
    _stateful_allowed(true),
    _get_material_property_called(false),
    _mi_boundary_restricted(!boundary_ids.empty() &&
                            BoundaryRestrictable::restricted(boundary_ids)),
    _mi_block_ids(block_ids),
    _mi_boundary_ids(boundary_ids)
{

  // Set the MaterialDataType flag
  if (_mi_params.isParamValid("_material_data_type"))
    _material_data_type = _mi_params.get<Moose::MaterialDataType>("_material_data_type");

  else if (_mi_boundary_restricted)
    _material_data_type = Moose::BOUNDARY_MATERIAL_DATA;

  else
    _material_data_type = Moose::BLOCK_MATERIAL_DATA;

  _material_data =
      _mi_feproblem.getMaterialData(_material_data_type, _mi_params.get<THREAD_ID>("_tid"));
}

std::string
MaterialPropertyInterface::deducePropertyName(const std::string & name)
{
  if (_mi_params.have_parameter<MaterialPropertyName>(name))
    return _mi_params.get<MaterialPropertyName>(name);
  else
    return name;
}

template <>
const MaterialProperty<Real> *
MaterialPropertyInterface::defaultMaterialProperty(const std::string & name)
{
  std::istringstream ss(name);
  Real real_value;

  // check if the string parsed cleanly into a Real number
  if (ss >> real_value && ss.eof())
  {
    _default_real_properties.emplace_back(libmesh_make_unique<MaterialProperty<Real>>());
    auto & default_property = _default_real_properties.back();

    // resize to accomodate maximum number obf qpoints
    auto nqp = _mi_feproblem.getMaxQps();
    default_property->resize(nqp);

    // set values for all qpoints to the given default
    for (decltype(nqp) qp = 0; qp < nqp; ++qp)
      (*default_property)[qp] = real_value;

    // return the raw pointer inside the shared pointer
    return default_property.get();
  }

  return nullptr;
}

template <>
const ADMaterialPropertyObject<Real> *
MaterialPropertyInterface::defaultADMaterialProperty(const std::string & name)
{
  std::istringstream ss(name);
  Real real_value;

  // check if the string parsed cleanly into a Real number
  if (ss >> real_value && ss.eof())
  {
    _default_ad_real_properties.emplace_back(
        libmesh_make_unique<ADMaterialPropertyObject<Real>>(true));
    auto & default_property = _default_ad_real_properties.back();

    // resize to accomodate maximum number obf qpoints
    auto nqp = _mi_feproblem.getMaxQps();
    default_property->resize(nqp);

    // set values for all qpoints to the given default
    for (decltype(nqp) qp = 0; qp < nqp; ++qp)
      (*default_property)[qp] = real_value;

    // return the raw pointer inside the shared pointer
    return default_property.get();
  }

  return nullptr;
}

template <>
const ADMaterialPropertyObject<RealVectorValue> *
MaterialPropertyInterface::defaultADMaterialProperty(const std::string & name)
{
  std::istringstream ss(name);
  Real real_value;

  // check if the string parsed cleanly into a Real number
  if (ss >> real_value && ss.eof())
  {
    _default_ad_real_vector_properties.emplace_back(
        libmesh_make_unique<ADMaterialPropertyObject<RealVectorValue>>());
    auto & default_property = _default_ad_real_vector_properties.back();

    // resize to accomodate maximum number obf qpoints
    auto nqp = _mi_feproblem.getMaxQps();
    default_property->resize(nqp);

    // set values for all qpoints to the given default
    for (decltype(nqp) qp = 0; qp < nqp; ++qp)
      (*default_property)[qp] = real_value;

    // return the raw pointer inside the shared pointer
    return default_property.get();
  }

  return nullptr;
}

std::set<SubdomainID>
MaterialPropertyInterface::getMaterialPropertyBlocks(const std::string & name)
{
  return _mi_feproblem.getMaterialPropertyBlocks(name);
}

std::vector<SubdomainName>
MaterialPropertyInterface::getMaterialPropertyBlockNames(const std::string & name)
{
  return _mi_feproblem.getMaterialPropertyBlockNames(name);
}

std::set<BoundaryID>
MaterialPropertyInterface::getMaterialPropertyBoundaryIDs(const std::string & name)
{
  return _mi_feproblem.getMaterialPropertyBoundaryIDs(name);
}

std::vector<BoundaryName>
MaterialPropertyInterface::getMaterialPropertyBoundaryNames(const std::string & name)
{
  return _mi_feproblem.getMaterialPropertyBoundaryNames(name);
}

void
MaterialPropertyInterface::checkMaterialProperty(const std::string & name)
{
  // If the material property is boundary restrictable, add to the list of materials to check
  if (_mi_boundary_restricted)
    for (const auto & bnd_id : _mi_boundary_ids)
      _mi_feproblem.storeBoundaryDelayedCheckMatProp(_mi_name, bnd_id, name);

  // The default is to assume block restrictions
  else
    for (const auto & blk_ids : _mi_block_ids)
      _mi_feproblem.storeSubdomainDelayedCheckMatProp(_mi_name, blk_ids, name);
}

void
MaterialPropertyInterface::markMatPropRequested(const std::string & name)
{
  _mi_feproblem.markMatPropRequested(name);
}

void
MaterialPropertyInterface::statefulPropertiesAllowed(bool stateful_allowed)
{
  _stateful_allowed = stateful_allowed;
}

Material &
MaterialPropertyInterface::getMaterial(const std::string & name)
{
  return getMaterialByName(_mi_params.get<MaterialName>(name));
}

void
MaterialPropertyInterface::checkBlockAndBoundaryCompatibility(std::shared_ptr<Material> discrete)
{
  // Check block compatibility
  if (!discrete->hasBlocks(_mi_block_ids))
  {
    std::ostringstream oss;
    oss << "The Material object '" << discrete->name()
        << "' is defined on blocks that are incompatible with the retrieving object '" << _mi_name
        << "':\n";
    oss << "  " << discrete->name();
    for (const auto & sbd_id : discrete->blockIDs())
      oss << " " << sbd_id;
    oss << "\n";
    oss << "  " << _mi_name;
    for (const auto & block_id : _mi_block_ids)
      oss << " " << block_id;
    oss << "\n";
    mooseError(oss.str());
  }

  // Check boundary compatibility
  if (!discrete->hasBoundary(_mi_boundary_ids))
  {
    std::ostringstream oss;
    oss << "The Material object '" << discrete->name()
        << "' is defined on boundaries that are incompatible with the retrieving object '"
        << _mi_name << "':\n";
    oss << "  " << discrete->name();
    for (const auto & bnd_id : discrete->boundaryIDs())
      oss << " " << bnd_id;
    oss << "\n";
    oss << "  " << _mi_name;
    for (const auto & bnd_id : _mi_boundary_ids)
      oss << " " << bnd_id;
    oss << "\n";
    mooseError(oss.str());
  }
}

Material &
MaterialPropertyInterface::getMaterialByName(const std::string & name, bool no_warn)
{
  std::shared_ptr<Material> discrete =
      _mi_feproblem.getMaterial(name, _material_data_type, _mi_tid, no_warn);
  checkBlockAndBoundaryCompatibility(discrete);
  return *discrete;
}

template <ComputeStage compute_stage>
Material &
MaterialPropertyInterface::getMaterial(const std::string & name)
{
  return getMaterialByName<compute_stage>(_mi_params.get<MaterialName>(name));
}

template <>
Material &
MaterialPropertyInterface::getMaterialByName<RESIDUAL>(const std::string & name, bool no_warn)
{
  return getMaterialByName(name, no_warn);
}

template <>
Material &
MaterialPropertyInterface::getMaterialByName<JACOBIAN>(const std::string & name, bool no_warn)
{
  std::shared_ptr<Material> discrete =
      _mi_feproblem.getMaterial(name + "_jacobian", _material_data_type, _mi_tid, no_warn);
  checkBlockAndBoundaryCompatibility(discrete);
  return *discrete;
}

template Material & MaterialPropertyInterface::getMaterial<RESIDUAL>(const std::string &);
template Material & MaterialPropertyInterface::getMaterial<JACOBIAN>(const std::string &);

void
MaterialPropertyInterface::checkExecutionStage()
{
  if (_mi_feproblem.startedInitialSetup())
    mooseError("Material properties must be retrieved during object construction to ensure correct "
               "problem integrity validation.");
}
<commit_msg>We renamed ADMaterial residual objects<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

// MOOSE includes
#include "MaterialPropertyInterface.h"
#include "MooseApp.h"
#include "Material.h"

template <>
InputParameters
validParams<MaterialPropertyInterface>()
{
  InputParameters params = emptyInputParameters();
  params.addPrivateParam<Moose::MaterialDataType>(
      "_material_data_type"); // optionally force the type of MaterialData to utilize
  return params;
}

MaterialPropertyInterface::MaterialPropertyInterface(const MooseObject * moose_object,
                                                     const std::set<SubdomainID> & block_ids,
                                                     const std::set<BoundaryID> & boundary_ids)
  : _mi_params(moose_object->parameters()),
    _mi_name(_mi_params.get<std::string>("_object_name")),
    _mi_feproblem(*_mi_params.getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")),
    _mi_tid(_mi_params.get<THREAD_ID>("_tid")),
    _stateful_allowed(true),
    _get_material_property_called(false),
    _mi_boundary_restricted(!boundary_ids.empty() &&
                            BoundaryRestrictable::restricted(boundary_ids)),
    _mi_block_ids(block_ids),
    _mi_boundary_ids(boundary_ids)
{

  // Set the MaterialDataType flag
  if (_mi_params.isParamValid("_material_data_type"))
    _material_data_type = _mi_params.get<Moose::MaterialDataType>("_material_data_type");

  else if (_mi_boundary_restricted)
    _material_data_type = Moose::BOUNDARY_MATERIAL_DATA;

  else
    _material_data_type = Moose::BLOCK_MATERIAL_DATA;

  _material_data =
      _mi_feproblem.getMaterialData(_material_data_type, _mi_params.get<THREAD_ID>("_tid"));
}

std::string
MaterialPropertyInterface::deducePropertyName(const std::string & name)
{
  if (_mi_params.have_parameter<MaterialPropertyName>(name))
    return _mi_params.get<MaterialPropertyName>(name);
  else
    return name;
}

template <>
const MaterialProperty<Real> *
MaterialPropertyInterface::defaultMaterialProperty(const std::string & name)
{
  std::istringstream ss(name);
  Real real_value;

  // check if the string parsed cleanly into a Real number
  if (ss >> real_value && ss.eof())
  {
    _default_real_properties.emplace_back(libmesh_make_unique<MaterialProperty<Real>>());
    auto & default_property = _default_real_properties.back();

    // resize to accomodate maximum number obf qpoints
    auto nqp = _mi_feproblem.getMaxQps();
    default_property->resize(nqp);

    // set values for all qpoints to the given default
    for (decltype(nqp) qp = 0; qp < nqp; ++qp)
      (*default_property)[qp] = real_value;

    // return the raw pointer inside the shared pointer
    return default_property.get();
  }

  return nullptr;
}

template <>
const ADMaterialPropertyObject<Real> *
MaterialPropertyInterface::defaultADMaterialProperty(const std::string & name)
{
  std::istringstream ss(name);
  Real real_value;

  // check if the string parsed cleanly into a Real number
  if (ss >> real_value && ss.eof())
  {
    _default_ad_real_properties.emplace_back(
        libmesh_make_unique<ADMaterialPropertyObject<Real>>(true));
    auto & default_property = _default_ad_real_properties.back();

    // resize to accomodate maximum number obf qpoints
    auto nqp = _mi_feproblem.getMaxQps();
    default_property->resize(nqp);

    // set values for all qpoints to the given default
    for (decltype(nqp) qp = 0; qp < nqp; ++qp)
      (*default_property)[qp] = real_value;

    // return the raw pointer inside the shared pointer
    return default_property.get();
  }

  return nullptr;
}

template <>
const ADMaterialPropertyObject<RealVectorValue> *
MaterialPropertyInterface::defaultADMaterialProperty(const std::string & name)
{
  std::istringstream ss(name);
  Real real_value;

  // check if the string parsed cleanly into a Real number
  if (ss >> real_value && ss.eof())
  {
    _default_ad_real_vector_properties.emplace_back(
        libmesh_make_unique<ADMaterialPropertyObject<RealVectorValue>>());
    auto & default_property = _default_ad_real_vector_properties.back();

    // resize to accomodate maximum number obf qpoints
    auto nqp = _mi_feproblem.getMaxQps();
    default_property->resize(nqp);

    // set values for all qpoints to the given default
    for (decltype(nqp) qp = 0; qp < nqp; ++qp)
      (*default_property)[qp] = real_value;

    // return the raw pointer inside the shared pointer
    return default_property.get();
  }

  return nullptr;
}

std::set<SubdomainID>
MaterialPropertyInterface::getMaterialPropertyBlocks(const std::string & name)
{
  return _mi_feproblem.getMaterialPropertyBlocks(name);
}

std::vector<SubdomainName>
MaterialPropertyInterface::getMaterialPropertyBlockNames(const std::string & name)
{
  return _mi_feproblem.getMaterialPropertyBlockNames(name);
}

std::set<BoundaryID>
MaterialPropertyInterface::getMaterialPropertyBoundaryIDs(const std::string & name)
{
  return _mi_feproblem.getMaterialPropertyBoundaryIDs(name);
}

std::vector<BoundaryName>
MaterialPropertyInterface::getMaterialPropertyBoundaryNames(const std::string & name)
{
  return _mi_feproblem.getMaterialPropertyBoundaryNames(name);
}

void
MaterialPropertyInterface::checkMaterialProperty(const std::string & name)
{
  // If the material property is boundary restrictable, add to the list of materials to check
  if (_mi_boundary_restricted)
    for (const auto & bnd_id : _mi_boundary_ids)
      _mi_feproblem.storeBoundaryDelayedCheckMatProp(_mi_name, bnd_id, name);

  // The default is to assume block restrictions
  else
    for (const auto & blk_ids : _mi_block_ids)
      _mi_feproblem.storeSubdomainDelayedCheckMatProp(_mi_name, blk_ids, name);
}

void
MaterialPropertyInterface::markMatPropRequested(const std::string & name)
{
  _mi_feproblem.markMatPropRequested(name);
}

void
MaterialPropertyInterface::statefulPropertiesAllowed(bool stateful_allowed)
{
  _stateful_allowed = stateful_allowed;
}

Material &
MaterialPropertyInterface::getMaterial(const std::string & name)
{
  return getMaterialByName(_mi_params.get<MaterialName>(name));
}

void
MaterialPropertyInterface::checkBlockAndBoundaryCompatibility(std::shared_ptr<Material> discrete)
{
  // Check block compatibility
  if (!discrete->hasBlocks(_mi_block_ids))
  {
    std::ostringstream oss;
    oss << "The Material object '" << discrete->name()
        << "' is defined on blocks that are incompatible with the retrieving object '" << _mi_name
        << "':\n";
    oss << "  " << discrete->name();
    for (const auto & sbd_id : discrete->blockIDs())
      oss << " " << sbd_id;
    oss << "\n";
    oss << "  " << _mi_name;
    for (const auto & block_id : _mi_block_ids)
      oss << " " << block_id;
    oss << "\n";
    mooseError(oss.str());
  }

  // Check boundary compatibility
  if (!discrete->hasBoundary(_mi_boundary_ids))
  {
    std::ostringstream oss;
    oss << "The Material object '" << discrete->name()
        << "' is defined on boundaries that are incompatible with the retrieving object '"
        << _mi_name << "':\n";
    oss << "  " << discrete->name();
    for (const auto & bnd_id : discrete->boundaryIDs())
      oss << " " << bnd_id;
    oss << "\n";
    oss << "  " << _mi_name;
    for (const auto & bnd_id : _mi_boundary_ids)
      oss << " " << bnd_id;
    oss << "\n";
    mooseError(oss.str());
  }
}

Material &
MaterialPropertyInterface::getMaterialByName(const std::string & name, bool no_warn)
{
  std::shared_ptr<Material> discrete =
      _mi_feproblem.getMaterial(name, _material_data_type, _mi_tid, no_warn);
  checkBlockAndBoundaryCompatibility(discrete);
  return *discrete;
}

template <ComputeStage compute_stage>
Material &
MaterialPropertyInterface::getMaterial(const std::string & name)
{
  return getMaterialByName<compute_stage>(_mi_params.get<MaterialName>(name));
}

template <>
Material &
MaterialPropertyInterface::getMaterialByName<RESIDUAL>(const std::string & name, bool no_warn)
{
  const std::string new_name = name + "_residual";
  return getMaterialByName(new_name, no_warn);
}

template <>
Material &
MaterialPropertyInterface::getMaterialByName<JACOBIAN>(const std::string & name, bool no_warn)
{
  const std::string new_name = name + "_jacobian";
  return getMaterialByName(new_name, no_warn);
}

template Material & MaterialPropertyInterface::getMaterial<RESIDUAL>(const std::string &);
template Material & MaterialPropertyInterface::getMaterial<JACOBIAN>(const std::string &);

void
MaterialPropertyInterface::checkExecutionStage()
{
  if (_mi_feproblem.startedInitialSetup())
    mooseError("Material properties must be retrieved during object construction to ensure correct "
               "problem integrity validation.");
}
<|endoftext|>


<commit_before>#include <iostream>
#include <boost/asio.hpp>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/service.h>

#include "vtrc-common/vtrc-pool-pair.h"

#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-call-context.h"
#include "vtrc-common/vtrc-exception.h"
#include "vtrc-common/vtrc-protocol-layer.h"

#include "vtrc-client-base/vtrc-client.h"
#include "protocol/vtrc-rpc-lowlevel.pb.h"
#include "protocol/vtrc-service.pb.h"
#include "protocol/vtrc-errors.pb.h"

#include <boost/random.hpp>
#include <boost/random/random_device.hpp>

#include "vtrc-thread.h"
#include "vtrc-ref.h"
#include "vtrc-bind.h"
#include "vtrc-condition-variable.h"
#include "vtrc-chrono.h"

using namespace vtrc;

void on_connect( const boost::system::error_code &err )
{
    std::cout << "connected "
              << err.value( ) << " "
              << err.message( ) << "\n";
}

struct work_time {
    typedef vtrc::chrono::high_resolution_clock::time_point time_point;
    time_point start_;
    work_time( )
        :start_(vtrc::chrono::high_resolution_clock::now( ))
    {}
    ~work_time( )
    {
        time_point::duration stop(
                    vtrc::chrono::high_resolution_clock::now( ) - start_);
        std::cout << "call time: " << stop << "\n";
    }
};

class ping_impl: public vtrc_service::internal {

    client::vtrc_client *c_;

public:

    ping_impl( client::vtrc_client *c )
        :c_( c )
    {}

    void ping(::google::protobuf::RpcController* controller,
                         const ::vtrc_service::ping_req* request,
                         ::vtrc_service::pong_res* response,
                         ::google::protobuf::Closure* done)
    {
        common::closure_holder chold(done);
        std::cout << "ping event rcvd "
                  << c_->connection( )
                     ->get_call_context( )
                     ->get_lowlevel_message( )->id( )
                  << " " << vtrc::this_thread::get_id( ) << " "
                  //<< vtrc::chrono::high_resolution_clock::now( )
                  << "\n";

        return;

        const vtrc::common::call_context *cc =
                    vtrc::common::call_context::get( c_->connection( ) );

        vtrc::shared_ptr<google::protobuf::RpcChannel>
                ch(c_->create_channel( common::rpc_channel::USE_CONTEXT_CALL ));

        vtrc_service::test_message      mi;
        vtrc_service::test_rpc::Stub s( ch.get( ) );

        s.test2( NULL, &mi, &mi, NULL );

        //if( done ) done->Run( );
    }
};

class test_ev: public vtrc_service::test_events
{
    vtrc::common::connection_iface *c_;
public:
    test_ev( vtrc::common::connection_iface *c )
        :c_( c )
    {}

    void test(::google::protobuf::RpcController* controller,
                         const ::vtrc_service::test_message* request,
                         ::vtrc_service::test_message* response,
                         ::google::protobuf::Closure* done)
    {
        common::closure_holder ch(done);
        std::cout << "test event rcvd "
                  << c_->get_call_context( )->get_lowlevel_message( )->id( )
                  << " " << vtrc::this_thread::get_id( ) << " "
                  << "\n";
    }

};

void run_client( vtrc::shared_ptr<client::vtrc_client> cl, bool wait)
{
    vtrc::shared_ptr<google::protobuf::RpcChannel>
            ch(cl->create_channel( wait ? common::rpc_channel::DISABLE_WAIT
                                        : common::rpc_channel::DEFAULT ));
    vtrc_service::test_rpc::Stub s( ch.get( ) );

    vtrc_service::test_message mi;
    vtrc_service::test_message mir;

    size_t last = 0;

    std::string ts(1024 * 800, 0);

    std::cout << "this thread: "
              << vtrc::this_thread::get_id( ) << " "
              << "\n";

    for( int i=0; i<29999999999; ++i ) {
        try {

            if( wait )
                vtrc::this_thread::sleep_for(
                            vtrc::chrono::microseconds(500) );
            work_time wt;
            //mi.set_b( ts );
            s.test( NULL, &mi, &mir, NULL );
            last = i; //mir.id( );
            std::cout << "response: " << last << "\n";
            //cl.reset( );
        } catch( const vtrc::common::exception &ex ) {
            std::cout << "call error: "
                      << " code (" << ex.code( ) << ")"
                      << " category (" << ex.category( ) << ")"
                      << " what: " << ex.what( )
                      << " (" << ex.additional( ) << ")"
                      << "\n";
            //if( i % 100 == 0 )
            std::cout << i << "\n";
            if( ex.category( ) == vtrc_errors::CATEGORY_SYSTEM ) break;
            if( ex.code( ) == vtrc_errors::ERR_COMM ) break;
        } catch( const std::exception &ex ) {
            //std::cout << "call error: " << ex.what( ) << "\n";
        }
    }
}

void on_connect( )
{
    std::cout << "on_connect\n";
}

void on_ready( vtrc::condition_variable &cond )
{
    std::cout << "on_ready\n";
    cond.notify_all( );
}

void on_disconnect( vtrc::condition_variable &cond )
{
    std::cout << "on_disconnect\n";
    cond.notify_all( );
}

int main( )
{
    common::pool_pair pp(2, 2);
    vtrc::shared_ptr<client::vtrc_client> cl(client::vtrc_client::create(pp));

    cl->set_session_key( "1234" );

    vtrc::mutex              mut;
    vtrc::condition_variable cond;

    cl->get_on_connect( ).connect( boost::bind( on_connect ) );
    cl->get_on_ready( ).connect( boost::bind( on_ready,
                                              vtrc::ref(cond) ));
    cl->get_on_disconnect( ).connect( boost::bind( on_disconnect,
                                                   vtrc::ref(cond) ));

    //cl->connect( "/tmp/test.socket" );
    //cl->connect( "192.168.56.101", "44667" );
    //cl->connect( "\\\\.\\pipe\\test_pipe");
    cl->connect( "127.0.0.1", "44667" );
    //cl->connect( "::1", "44668" );
    ///cl->async_connect( "127.0.0.1", "44667", on_connect );

    cl->assign_rpc_handler( vtrc::shared_ptr<test_ev>(new test_ev(cl->connection( ).get( ))) );
    cl->assign_rpc_handler( vtrc::shared_ptr<ping_impl>(new ping_impl(cl.get( ))) );

    vtrc::unique_lock<vtrc::mutex>  lck(mut);
    cond.wait( lck, vtrc::bind( &client::vtrc_client::ready, cl ) );

    std::cout << "start program\n";

    //vtrc::thread( run_client, cl, true ).detach( );
    //vtrc::thread( run_client, cl, false ).detach( );

    vtrc::thread r( run_client, cl, false );

    //cond.wait( lck );
    r.join( );

    pp.stop_all( );
    pp.join_all( );

    return 0;

}
<commit_msg>proto<commit_after>#include <iostream>
#include <boost/asio.hpp>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/service.h>

#include "vtrc-common/vtrc-pool-pair.h"

#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-call-context.h"
#include "vtrc-common/vtrc-exception.h"
#include "vtrc-common/vtrc-protocol-layer.h"

#include "vtrc-client-base/vtrc-client.h"
#include "protocol/vtrc-rpc-lowlevel.pb.h"
#include "protocol/vtrc-service.pb.h"
#include "protocol/vtrc-errors.pb.h"

#include <boost/random.hpp>
#include <boost/random/random_device.hpp>

#include "vtrc-thread.h"
#include "vtrc-ref.h"
#include "vtrc-bind.h"
#include "vtrc-condition-variable.h"
#include "vtrc-chrono.h"

using namespace vtrc;

void on_connect( const boost::system::error_code &err )
{
    std::cout << "connected "
              << err.value( ) << " "
              << err.message( ) << "\n";
}

struct work_time {
    typedef vtrc::chrono::high_resolution_clock::time_point time_point;
    time_point start_;
    work_time( )
        :start_(vtrc::chrono::high_resolution_clock::now( ))
    {}
    ~work_time( )
    {
        time_point::duration stop(
                    vtrc::chrono::high_resolution_clock::now( ) - start_);
        std::cout << "call time: " << stop << "\n";
    }
};

class ping_impl: public vtrc_service::internal {

    client::vtrc_client *c_;

public:

    ping_impl( client::vtrc_client *c )
        :c_( c )
    {}

    void ping(::google::protobuf::RpcController* controller,
                         const ::vtrc_service::ping_req* request,
                         ::vtrc_service::pong_res* response,
                         ::google::protobuf::Closure* done)
    {
        common::closure_holder chold(done);
        std::cout << "ping event rcvd "
                  << c_->connection( )
                     ->get_call_context( )
                     ->get_lowlevel_message( )->id( )
                  << " " << vtrc::this_thread::get_id( ) << " "
                  //<< vtrc::chrono::high_resolution_clock::now( )
                  << "\n";

        return;

        const vtrc::common::call_context *cc =
                    vtrc::common::call_context::get( c_->connection( ) );

        vtrc::shared_ptr<google::protobuf::RpcChannel>
                ch(c_->create_channel( common::rpc_channel::USE_CONTEXT_CALL ));

        vtrc_service::test_message      mi;
        vtrc_service::test_rpc::Stub s( ch.get( ) );

        s.test2( NULL, &mi, &mi, NULL );

        //if( done ) done->Run( );
    }
};

class test_ev: public vtrc_service::test_events
{
    vtrc::common::connection_iface *c_;
public:
    test_ev( vtrc::common::connection_iface *c )
        :c_( c )
    {}

    void test(::google::protobuf::RpcController* controller,
                         const ::vtrc_service::test_message* request,
                         ::vtrc_service::test_message* response,
                         ::google::protobuf::Closure* done)
    {
        common::closure_holder ch(done);
        std::cout << "test event rcvd "
                  << c_->get_call_context( )->get_lowlevel_message( )->id( )
                  << " " << vtrc::this_thread::get_id( ) << " "
                  << "\n";
    }

};

void run_client( vtrc::shared_ptr<client::vtrc_client> cl, bool wait)
{
    vtrc::shared_ptr<google::protobuf::RpcChannel>
            ch(cl->create_channel( wait ? common::rpc_channel::DISABLE_WAIT
                                        : common::rpc_channel::DEFAULT ));
    vtrc_service::test_rpc::Stub s( ch.get( ) );

    vtrc_service::test_message mi;
    vtrc_service::test_message mir;

    size_t last = 0;

    std::string ts(1024 * 800, 0);

    std::cout << "this thread: "
              << vtrc::this_thread::get_id( ) << " "
              << "\n";

    for( int i=0; i<29999999999; ++i ) {
        try {

            if( wait )
                vtrc::this_thread::sleep_for(
                            vtrc::chrono::microseconds(500) );
            work_time wt;
            //mi.set_b( ts );
            s.test( NULL, &mi, &mir, NULL );
            last = i; //mir.id( );
            std::cout << "response: " << last << "\n";
            //cl.reset( );
        } catch( const vtrc::common::exception &ex ) {
            std::cout << "call error: "
                      << " code (" << ex.code( ) << ")"
                      << " category (" << ex.category( ) << ")"
                      << " what: " << ex.what( )
                      << " (" << ex.additional( ) << ")"
                      << "\n";
            //if( i % 100 == 0 )
            std::cout << i << "\n";
            if( ex.category( ) == vtrc_errors::CATEGORY_SYSTEM ) break;
            if( ex.code( ) == vtrc_errors::ERR_COMM ) break;
        } catch( const std::exception &ex ) {
            //std::cout << "call error: " << ex.what( ) << "\n";
        }
    }
}

void on_connect( )
{
    std::cout << "on_connect\n";
}

void on_ready( vtrc::condition_variable &cond )
{
    std::cout << "on_ready\n";
    cond.notify_all( );
}

void on_disconnect( vtrc::condition_variable &cond )
{
    std::cout << "on_disconnect\n";
    cond.notify_all( );
}

int main( )
{
    common::pool_pair pp(2, 2);
    vtrc::shared_ptr<client::vtrc_client> cl(client::vtrc_client::create(pp));

    //cl->set_session_key( "1234" );

    vtrc::mutex              mut;
    vtrc::condition_variable cond;

    cl->get_on_connect( ).connect( boost::bind( on_connect ) );
    cl->get_on_ready( ).connect( boost::bind( on_ready, vtrc::ref(cond) ));
    cl->get_on_disconnect( ).connect( boost::bind( on_disconnect, vtrc::ref(cond) ));

    //cl->connect( "/tmp/test.socket" );
    //cl->connect( "192.168.56.101", "44667" );
    //cl->connect( "\\\\.\\pipe\\test_pipe");
    cl->connect( "127.0.0.1", "44667" );
    //cl->connect( "::1", "44668" );
    ///cl->async_connect( "127.0.0.1", "44667", on_connect );

    cl->assign_rpc_handler( vtrc::shared_ptr<test_ev>(new test_ev(cl->connection( ).get( ))) );
    cl->assign_rpc_handler( vtrc::shared_ptr<ping_impl>(new ping_impl(cl.get( ))) );

    vtrc::unique_lock<vtrc::mutex>  lck(mut);
    cond.wait( lck, vtrc::bind( &client::vtrc_client::ready, cl ) );

    std::cout << "start program\n";

    //vtrc::thread( run_client, cl, true ).detach( );
    //vtrc::thread( run_client, cl, false ).detach( );

    vtrc::thread r( run_client, cl, false );

    //cond.wait( lck );
    r.join( );

    pp.stop_all( );
    pp.join_all( );

    return 0;

}
<|endoftext|>


<commit_before>/* Copyright (c) 2017-2020 Hans-Kristian Arntzen
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "descriptor_set.hpp"
#include "device.hpp"
#include <vector>

using namespace std;
using namespace Util;

namespace Vulkan
{
DescriptorSetAllocator::DescriptorSetAllocator(Hash hash, Device *device_, const DescriptorSetLayout &layout, const uint32_t *stages_for_binds)
	: IntrusiveHashMapEnabled<DescriptorSetAllocator>(hash)
	, device(device_)
	, table(device_->get_device_table())
{
	bindless = layout.array_size[0] == DescriptorSetLayout::UNSIZED_ARRAY;

	if (!bindless)
	{
		unsigned count = device_->num_thread_indices;
		for (unsigned i = 0; i < count; i++)
			per_thread.emplace_back(new PerThread);
	}

	if (bindless && !device->get_device_features().supports_descriptor_indexing)
	{
		LOGE("Cannot support descriptor indexing on this device.\n");
		return;
	}

	VkDescriptorSetLayoutCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
	VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flags = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT };
	vector<VkDescriptorSetLayoutBinding> bindings;
	VkDescriptorBindingFlagsEXT binding_flags = 0;

	if (bindless)
	{
		info.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT;
		info.pNext = &flags;

		flags.bindingCount = 1;
		flags.pBindingFlags = &binding_flags;
		binding_flags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT |
		                VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT;

		if (device->get_device_features().descriptor_indexing_features.descriptorBindingVariableDescriptorCount)
			binding_flags |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT;
	}

	for (unsigned i = 0; i < VULKAN_NUM_BINDINGS; i++)
	{
		auto stages = stages_for_binds[i];
		if (stages == 0)
			continue;

		unsigned array_size = layout.array_size[i];
		unsigned pool_array_size;
		if (array_size == DescriptorSetLayout::UNSIZED_ARRAY)
		{
			if (device->get_device_features().descriptor_indexing_features.descriptorBindingVariableDescriptorCount)
				array_size = VULKAN_NUM_BINDINGS_BINDLESS_VARYING;
			else
				array_size = VULKAN_NUM_BINDINGS_BINDLESS;
			pool_array_size = array_size;
		}
		else
			pool_array_size = array_size * VULKAN_NUM_SETS_PER_POOL;

		unsigned types = 0;
		if (layout.sampled_image_mask & (1u << i))
		{
			VkSampler sampler = VK_NULL_HANDLE;
			if (has_immutable_sampler(layout, i))
				sampler = device->get_stock_sampler(get_immutable_sampler(layout, i)).get_sampler();

			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, array_size, stages, sampler != VK_NULL_HANDLE ? &sampler : nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, pool_array_size });
			types++;
		}

		if (layout.sampled_buffer_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, pool_array_size });
			types++;
		}

		if (layout.storage_image_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, pool_array_size });
			types++;
		}

		if (layout.uniform_buffer_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, pool_array_size });
			types++;
		}

		if (layout.storage_buffer_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, pool_array_size });
			types++;
		}

		if (layout.input_attachment_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, pool_array_size });
			types++;
		}

		if (layout.separate_image_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, pool_array_size });
			types++;
		}

		if (layout.sampler_mask & (1u << i))
		{
			VkSampler sampler = VK_NULL_HANDLE;
			if (has_immutable_sampler(layout, i))
				sampler = device->get_stock_sampler(get_immutable_sampler(layout, i)).get_sampler();

			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_SAMPLER, array_size, stages, sampler != VK_NULL_HANDLE ? &sampler : nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_SAMPLER, pool_array_size });
			types++;
		}

		(void)types;
		VK_ASSERT(types <= 1 && "Descriptor set aliasing!");
	}

	if (!bindings.empty())
	{
		info.bindingCount = bindings.size();
		info.pBindings = bindings.data();

		if (bindless && bindings.size() != 1)
		{
			LOGE("Using bindless but have bindingCount != 1.\n");
			return;
		}
	}

	LOGI("Creating descriptor set layout.\n");
	if (table.vkCreateDescriptorSetLayout(device->get_device(), &info, nullptr, &set_layout) != VK_SUCCESS)
		LOGE("Failed to create descriptor set layout.");
#ifdef GRANITE_VULKAN_FOSSILIZE
	device->register_descriptor_set_layout(set_layout, get_hash(), info);
#endif
}

VkDescriptorSet DescriptorSetAllocator::allocate_bindless_set(VkDescriptorPool pool, unsigned num_descriptors)
{
	if (!pool || !bindless)
		return VK_NULL_HANDLE;

	VkDescriptorSetAllocateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
	info.descriptorPool = pool;
	info.descriptorSetCount = 1;
	info.pSetLayouts = &set_layout;

	VkDescriptorSetVariableDescriptorCountAllocateInfoEXT count_info =
			{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT };

	if (device->get_device_features().descriptor_indexing_features.descriptorBindingVariableDescriptorCount)
	{
		count_info.descriptorSetCount = 1;
		uint32_t num_desc = num_descriptors;
		count_info.pDescriptorCounts = &num_desc;
		info.pNext = &count_info;
	}

	VkDescriptorSet desc_set = VK_NULL_HANDLE;
	if (table.vkAllocateDescriptorSets(device->get_device(), &info, &desc_set) != VK_SUCCESS)
		return VK_NULL_HANDLE;

	return desc_set;
}

VkDescriptorPool DescriptorSetAllocator::allocate_bindless_pool(unsigned num_sets, unsigned num_descriptors)
{
	if (!bindless)
		return VK_NULL_HANDLE;

	VkDescriptorPool pool = VK_NULL_HANDLE;
	VkDescriptorPoolCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
	info.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT;
	info.maxSets = num_sets;
	info.poolSizeCount = 1;

	VkDescriptorPoolSize size = pool_size[0];
	if (num_descriptors > size.descriptorCount)
	{
		LOGE("Trying to allocate more than max bindless descriptors for descriptor layout.\n");
		return VK_NULL_HANDLE;
	}

	// If implementation does not support variable descriptor count, allocate maximum.
	if (device->get_device_features().descriptor_indexing_features.descriptorBindingVariableDescriptorCount)
		size.descriptorCount = num_descriptors;
	else
		info.maxSets = 1;

	info.pPoolSizes = &size;

	if (table.vkCreateDescriptorPool(device->get_device(), &info, nullptr, &pool) != VK_SUCCESS)
	{
		LOGE("Failed to create descriptor pool.\n");
		return VK_NULL_HANDLE;
	}

	return pool;
}

void DescriptorSetAllocator::begin_frame()
{
	if (!bindless)
	{
		for (auto &thr : per_thread)
			thr->should_begin = true;
	}
}

pair<VkDescriptorSet, bool> DescriptorSetAllocator::find(unsigned thread_index, Hash hash)
{
	VK_ASSERT(!bindless);

	auto &state = *per_thread[thread_index];
	if (state.should_begin)
	{
		state.set_nodes.begin_frame();
		state.should_begin = false;
	}

	auto *node = state.set_nodes.request(hash);
	if (node)
		return { node->set, true };

	node = state.set_nodes.request_vacant(hash);
	if (node)
		return { node->set, false };

	VkDescriptorPool pool;
	VkDescriptorPoolCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
	info.maxSets = VULKAN_NUM_SETS_PER_POOL;
	if (!pool_size.empty())
	{
		info.poolSizeCount = pool_size.size();
		info.pPoolSizes = pool_size.data();
	}

	if (table.vkCreateDescriptorPool(device->get_device(), &info, nullptr, &pool) != VK_SUCCESS)
	{
		LOGE("Failed to create descriptor pool.\n");
		return { VK_NULL_HANDLE, false };
	}

	VkDescriptorSet sets[VULKAN_NUM_SETS_PER_POOL];
	VkDescriptorSetLayout layouts[VULKAN_NUM_SETS_PER_POOL];
	fill(begin(layouts), end(layouts), set_layout);

	VkDescriptorSetAllocateInfo alloc = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
	alloc.descriptorPool = pool;
	alloc.descriptorSetCount = VULKAN_NUM_SETS_PER_POOL;
	alloc.pSetLayouts = layouts;

	if (table.vkAllocateDescriptorSets(device->get_device(), &alloc, sets) != VK_SUCCESS)
		LOGE("Failed to allocate descriptor sets.\n");
	state.pools.push_back(pool);

	for (auto set : sets)
		state.set_nodes.make_vacant(set);

	return { state.set_nodes.request_vacant(hash)->set, false };
}

void DescriptorSetAllocator::clear()
{
	for (auto &thr : per_thread)
	{
		thr->set_nodes.clear();
		for (auto &pool : thr->pools)
		{
			table.vkResetDescriptorPool(device->get_device(), pool, 0);
			table.vkDestroyDescriptorPool(device->get_device(), pool, nullptr);
		}
		thr->pools.clear();
	}
}

DescriptorSetAllocator::~DescriptorSetAllocator()
{
	if (set_layout != VK_NULL_HANDLE)
		table.vkDestroyDescriptorSetLayout(device->get_device(), set_layout, nullptr);
	clear();
}

BindlessDescriptorPool::BindlessDescriptorPool(Device *device_, DescriptorSetAllocator *allocator_, VkDescriptorPool pool)
	: device(device_), allocator(allocator_), desc_pool(pool)
{
}

BindlessDescriptorPool::~BindlessDescriptorPool()
{
	if (desc_pool)
	{
		if (internal_sync)
			device->destroy_descriptor_pool_nolock(desc_pool);
		else
			device->destroy_descriptor_pool(desc_pool);
	}
}

VkDescriptorSet BindlessDescriptorPool::get_descriptor_set() const
{
	return desc_set;
}

bool BindlessDescriptorPool::allocate_descriptors(unsigned count)
{
	desc_set = allocator->allocate_bindless_set(desc_pool, count);
	return desc_set != VK_NULL_HANDLE;
}

void BindlessDescriptorPool::set_texture(unsigned binding, const ImageView &view)
{
	// TODO: Deal with integer view for depth-stencil images?
	set_texture(binding, view.get_float_view(), view.get_image().get_layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
}

void BindlessDescriptorPool::set_texture_unorm(unsigned binding, const ImageView &view)
{
	set_texture(binding, view.get_unorm_view(), view.get_image().get_layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
}

void BindlessDescriptorPool::set_texture_srgb(unsigned binding, const ImageView &view)
{
	set_texture(binding, view.get_srgb_view(), view.get_image().get_layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
}

void BindlessDescriptorPool::set_texture(unsigned binding, VkImageView view, VkImageLayout layout)
{
	VkWriteDescriptorSet write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
	write.descriptorCount = 1;
	write.dstArrayElement = binding;
	write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
	write.dstSet = desc_set;

	const VkDescriptorImageInfo info = {
		VK_NULL_HANDLE,
		view,
		layout,
	};
	write.pImageInfo = &info;

	auto &table = device->get_device_table();
	table.vkUpdateDescriptorSets(device->get_device(), 1, &write, 0, nullptr);
}

void BindlessDescriptorPoolDeleter::operator()(BindlessDescriptorPool *pool)
{
	pool->device->handle_pool.bindless_descriptor_pool.free(pool);
}
}
<commit_msg>Fix stack corruption with variable bindless count.<commit_after>/* Copyright (c) 2017-2020 Hans-Kristian Arntzen
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "descriptor_set.hpp"
#include "device.hpp"
#include <vector>

using namespace std;
using namespace Util;

namespace Vulkan
{
DescriptorSetAllocator::DescriptorSetAllocator(Hash hash, Device *device_, const DescriptorSetLayout &layout, const uint32_t *stages_for_binds)
	: IntrusiveHashMapEnabled<DescriptorSetAllocator>(hash)
	, device(device_)
	, table(device_->get_device_table())
{
	bindless = layout.array_size[0] == DescriptorSetLayout::UNSIZED_ARRAY;

	if (!bindless)
	{
		unsigned count = device_->num_thread_indices;
		for (unsigned i = 0; i < count; i++)
			per_thread.emplace_back(new PerThread);
	}

	if (bindless && !device->get_device_features().supports_descriptor_indexing)
	{
		LOGE("Cannot support descriptor indexing on this device.\n");
		return;
	}

	VkDescriptorSetLayoutCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
	VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flags = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT };
	vector<VkDescriptorSetLayoutBinding> bindings;
	VkDescriptorBindingFlagsEXT binding_flags = 0;

	if (bindless)
	{
		info.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT;
		info.pNext = &flags;

		flags.bindingCount = 1;
		flags.pBindingFlags = &binding_flags;
		binding_flags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT |
		                VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT;

		if (device->get_device_features().descriptor_indexing_features.descriptorBindingVariableDescriptorCount)
			binding_flags |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT;
	}

	for (unsigned i = 0; i < VULKAN_NUM_BINDINGS; i++)
	{
		auto stages = stages_for_binds[i];
		if (stages == 0)
			continue;

		unsigned array_size = layout.array_size[i];
		unsigned pool_array_size;
		if (array_size == DescriptorSetLayout::UNSIZED_ARRAY)
		{
			if (device->get_device_features().descriptor_indexing_features.descriptorBindingVariableDescriptorCount)
				array_size = VULKAN_NUM_BINDINGS_BINDLESS_VARYING;
			else
				array_size = VULKAN_NUM_BINDINGS_BINDLESS;
			pool_array_size = array_size;
		}
		else
			pool_array_size = array_size * VULKAN_NUM_SETS_PER_POOL;

		unsigned types = 0;
		if (layout.sampled_image_mask & (1u << i))
		{
			VkSampler sampler = VK_NULL_HANDLE;
			if (has_immutable_sampler(layout, i))
				sampler = device->get_stock_sampler(get_immutable_sampler(layout, i)).get_sampler();

			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, array_size, stages, sampler != VK_NULL_HANDLE ? &sampler : nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, pool_array_size });
			types++;
		}

		if (layout.sampled_buffer_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, pool_array_size });
			types++;
		}

		if (layout.storage_image_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, pool_array_size });
			types++;
		}

		if (layout.uniform_buffer_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, pool_array_size });
			types++;
		}

		if (layout.storage_buffer_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, pool_array_size });
			types++;
		}

		if (layout.input_attachment_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, pool_array_size });
			types++;
		}

		if (layout.separate_image_mask & (1u << i))
		{
			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, array_size, stages, nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, pool_array_size });
			types++;
		}

		if (layout.sampler_mask & (1u << i))
		{
			VkSampler sampler = VK_NULL_HANDLE;
			if (has_immutable_sampler(layout, i))
				sampler = device->get_stock_sampler(get_immutable_sampler(layout, i)).get_sampler();

			bindings.push_back({ i, VK_DESCRIPTOR_TYPE_SAMPLER, array_size, stages, sampler != VK_NULL_HANDLE ? &sampler : nullptr });
			pool_size.push_back({ VK_DESCRIPTOR_TYPE_SAMPLER, pool_array_size });
			types++;
		}

		(void)types;
		VK_ASSERT(types <= 1 && "Descriptor set aliasing!");
	}

	if (!bindings.empty())
	{
		info.bindingCount = bindings.size();
		info.pBindings = bindings.data();

		if (bindless && bindings.size() != 1)
		{
			LOGE("Using bindless but have bindingCount != 1.\n");
			return;
		}
	}

	LOGI("Creating descriptor set layout.\n");
	if (table.vkCreateDescriptorSetLayout(device->get_device(), &info, nullptr, &set_layout) != VK_SUCCESS)
		LOGE("Failed to create descriptor set layout.");
#ifdef GRANITE_VULKAN_FOSSILIZE
	device->register_descriptor_set_layout(set_layout, get_hash(), info);
#endif
}

VkDescriptorSet DescriptorSetAllocator::allocate_bindless_set(VkDescriptorPool pool, unsigned num_descriptors)
{
	if (!pool || !bindless)
		return VK_NULL_HANDLE;

	VkDescriptorSetAllocateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
	info.descriptorPool = pool;
	info.descriptorSetCount = 1;
	info.pSetLayouts = &set_layout;

	VkDescriptorSetVariableDescriptorCountAllocateInfoEXT count_info =
			{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT };

	uint32_t num_desc = num_descriptors;
	if (device->get_device_features().descriptor_indexing_features.descriptorBindingVariableDescriptorCount)
	{
		count_info.descriptorSetCount = 1;
		count_info.pDescriptorCounts = &num_desc;
		info.pNext = &count_info;
	}

	VkDescriptorSet desc_set = VK_NULL_HANDLE;
	if (table.vkAllocateDescriptorSets(device->get_device(), &info, &desc_set) != VK_SUCCESS)
		return VK_NULL_HANDLE;

	return desc_set;
}

VkDescriptorPool DescriptorSetAllocator::allocate_bindless_pool(unsigned num_sets, unsigned num_descriptors)
{
	if (!bindless)
		return VK_NULL_HANDLE;

	VkDescriptorPool pool = VK_NULL_HANDLE;
	VkDescriptorPoolCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
	info.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT;
	info.maxSets = num_sets;
	info.poolSizeCount = 1;

	VkDescriptorPoolSize size = pool_size[0];
	if (num_descriptors > size.descriptorCount)
	{
		LOGE("Trying to allocate more than max bindless descriptors for descriptor layout.\n");
		return VK_NULL_HANDLE;
	}

	// If implementation does not support variable descriptor count, allocate maximum.
	if (device->get_device_features().descriptor_indexing_features.descriptorBindingVariableDescriptorCount)
		size.descriptorCount = num_descriptors;
	else
		info.maxSets = 1;

	info.pPoolSizes = &size;

	if (table.vkCreateDescriptorPool(device->get_device(), &info, nullptr, &pool) != VK_SUCCESS)
	{
		LOGE("Failed to create descriptor pool.\n");
		return VK_NULL_HANDLE;
	}

	return pool;
}

void DescriptorSetAllocator::begin_frame()
{
	if (!bindless)
	{
		for (auto &thr : per_thread)
			thr->should_begin = true;
	}
}

pair<VkDescriptorSet, bool> DescriptorSetAllocator::find(unsigned thread_index, Hash hash)
{
	VK_ASSERT(!bindless);

	auto &state = *per_thread[thread_index];
	if (state.should_begin)
	{
		state.set_nodes.begin_frame();
		state.should_begin = false;
	}

	auto *node = state.set_nodes.request(hash);
	if (node)
		return { node->set, true };

	node = state.set_nodes.request_vacant(hash);
	if (node)
		return { node->set, false };

	VkDescriptorPool pool;
	VkDescriptorPoolCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
	info.maxSets = VULKAN_NUM_SETS_PER_POOL;
	if (!pool_size.empty())
	{
		info.poolSizeCount = pool_size.size();
		info.pPoolSizes = pool_size.data();
	}

	if (table.vkCreateDescriptorPool(device->get_device(), &info, nullptr, &pool) != VK_SUCCESS)
	{
		LOGE("Failed to create descriptor pool.\n");
		return { VK_NULL_HANDLE, false };
	}

	VkDescriptorSet sets[VULKAN_NUM_SETS_PER_POOL];
	VkDescriptorSetLayout layouts[VULKAN_NUM_SETS_PER_POOL];
	fill(begin(layouts), end(layouts), set_layout);

	VkDescriptorSetAllocateInfo alloc = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
	alloc.descriptorPool = pool;
	alloc.descriptorSetCount = VULKAN_NUM_SETS_PER_POOL;
	alloc.pSetLayouts = layouts;

	if (table.vkAllocateDescriptorSets(device->get_device(), &alloc, sets) != VK_SUCCESS)
		LOGE("Failed to allocate descriptor sets.\n");
	state.pools.push_back(pool);

	for (auto set : sets)
		state.set_nodes.make_vacant(set);

	return { state.set_nodes.request_vacant(hash)->set, false };
}

void DescriptorSetAllocator::clear()
{
	for (auto &thr : per_thread)
	{
		thr->set_nodes.clear();
		for (auto &pool : thr->pools)
		{
			table.vkResetDescriptorPool(device->get_device(), pool, 0);
			table.vkDestroyDescriptorPool(device->get_device(), pool, nullptr);
		}
		thr->pools.clear();
	}
}

DescriptorSetAllocator::~DescriptorSetAllocator()
{
	if (set_layout != VK_NULL_HANDLE)
		table.vkDestroyDescriptorSetLayout(device->get_device(), set_layout, nullptr);
	clear();
}

BindlessDescriptorPool::BindlessDescriptorPool(Device *device_, DescriptorSetAllocator *allocator_, VkDescriptorPool pool)
	: device(device_), allocator(allocator_), desc_pool(pool)
{
}

BindlessDescriptorPool::~BindlessDescriptorPool()
{
	if (desc_pool)
	{
		if (internal_sync)
			device->destroy_descriptor_pool_nolock(desc_pool);
		else
			device->destroy_descriptor_pool(desc_pool);
	}
}

VkDescriptorSet BindlessDescriptorPool::get_descriptor_set() const
{
	return desc_set;
}

bool BindlessDescriptorPool::allocate_descriptors(unsigned count)
{
	desc_set = allocator->allocate_bindless_set(desc_pool, count);
	return desc_set != VK_NULL_HANDLE;
}

void BindlessDescriptorPool::set_texture(unsigned binding, const ImageView &view)
{
	// TODO: Deal with integer view for depth-stencil images?
	set_texture(binding, view.get_float_view(), view.get_image().get_layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
}

void BindlessDescriptorPool::set_texture_unorm(unsigned binding, const ImageView &view)
{
	set_texture(binding, view.get_unorm_view(), view.get_image().get_layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
}

void BindlessDescriptorPool::set_texture_srgb(unsigned binding, const ImageView &view)
{
	set_texture(binding, view.get_srgb_view(), view.get_image().get_layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
}

void BindlessDescriptorPool::set_texture(unsigned binding, VkImageView view, VkImageLayout layout)
{
	VkWriteDescriptorSet write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
	write.descriptorCount = 1;
	write.dstArrayElement = binding;
	write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
	write.dstSet = desc_set;

	const VkDescriptorImageInfo info = {
		VK_NULL_HANDLE,
		view,
		layout,
	};
	write.pImageInfo = &info;

	auto &table = device->get_device_table();
	table.vkUpdateDescriptorSets(device->get_device(), 1, &write, 0, nullptr);
}

void BindlessDescriptorPoolDeleter::operator()(BindlessDescriptorPool *pool)
{
	pool->device->handle_pool.bindless_descriptor_pool.free(pool);
}
}
<|endoftext|>


<commit_before>#include <iostream>

using std::cin;
using std::cout;
using std::endl;

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

	return 0;
}<commit_msg>ejercicio1 sin poder jugar 2 veces<commit_after>#include <iostream>
#include <ctime>
#include <cstdlib>

using std::cin;
using std::cout;
using std::endl;

void Arreglar_Score(int[], int, int);
void llenar_arreglo(int[], int);

int main(int argc, char*argv[]){
	srand(time(NULL));
	int Intento_User;
	int acum_intentos = 0;
	const int SIZE = 10;
	int Score[SIZE];

	int Azar = (-501 + rand()% 501);
	cout << Azar << endl;

	cout << "Ingrese un numero: " << endl;
	cin >> Intento_User;
	acum_intentos++;

	while(Azar != Intento_User){
		if (Intento_User < Azar){
			cout << "El numero que ingresaste es menor" << endl;
			cout << "Ingrese un numero: " << endl;
			cin >> Intento_User;
		} else if (Intento_User > Azar){
			cout << "El numero que ingresaste es mayor" << endl;
			cout << "Ingrese un numero: " << endl;
			cin >> Intento_User;
		}
		acum_intentos++;
	}

	cout << "Felicidades, has adivinado el numero en: " << acum_intentos << " intentos" << endl;
	llenar_arreglo(Score, SIZE);
	Arreglar_Score(Score, SIZE, acum_intentos);
	for (int i = 0; i < SIZE; i++){
		cout << Score[i] << endl;
	}

	return 0;
}

void llenar_arreglo(int Score[], int SIZE){
	for (int i = 0; i < SIZE; i++){
		Score[i] = 0;
	}
}

void Arreglar_Score(int Score[], int SIZE, int acum_intentos){
	for (int i = 0; i < SIZE; i++){
		if (acum_intentos > Score[i]){
			int mayor = acum_intentos;
			acum_intentos = Score[i + 1];
			Score[i] = mayor;
		}
	}
}<|endoftext|>


<commit_before>#include "KickEvaluator.hpp"
#include <Geometry2d/Util.hpp>

#include <algorithm>
#include <array>
#include <math.h>
#include <cmath>
#include <tuple>

REGISTER_CONFIGURABLE(KickEvaluator)

// 1 / sqrt(2*pi)
#define M_1_SQRT_2_PI 0.3989422

using namespace std;
using namespace Geometry2d;

ConfigDouble* KickEvaluator::robot_angle_filter_limit;
ConfigDouble* KickEvaluator::kick_std_dev;
ConfigDouble* KickEvaluator::num_rays;

ConfigDouble* KickEvaluator::kernal_width_coefficient;
ConfigDouble* KickEvaluator::distance_coefficient;

void KickEvaluator::createConfiguration(Configuration* cfg) {
    robot_angle_filter_limit = new ConfigDouble(
        cfg, "KickEvaluator/robot_angle_filter_limit", 0.35 * M_PI);
    kick_std_dev = new ConfigDouble(cfg, "KickEvaluator/kick_std_dev", 0.08);
    num_rays = new ConfigDouble(cfg, "KickEvaluator/num_rays", 16);

    kernal_width_coefficient =
        new ConfigDouble(cfg, "KickEvaluator/kernal_width_coefficient", 2.0);
    distance_coefficient =
        new ConfigDouble(cfg, "KickEvaluator/distance_coefficient", -1.0 / 7.0);
}

KickEvaluator::KickEvaluator(SystemState* systemState) : system(systemState) {}

float KickEvaluator::eval_pt_to_pt(Point origin, Point target,
                                   float targetWidth) {
    vector<Robot*> bots(system->self.size() + system->opp.size());

    auto filter_predicate = [&](const Robot* bot) -> bool {
        return bot != nullptr && bot->visible &&
               find(excluded_robots.begin(), excluded_robots.end(), bot) ==
                   excluded_robots.end();
    };

    auto end_it = copy_if(system->self.begin(), system->self.end(),
                          bots.begin(), filter_predicate);

    end_it = copy_if(system->opp.begin(), system->opp.end(), end_it,
                     filter_predicate);

    bots.resize(distance(bots.begin(), end_it));

    // < Dist, Angle >
    vector<tuple<float, float> > bot_locations;

    // Add robots as obstacles
    for_each(bots.begin(), bots.end(),
             [&bot_locations, target, origin, this](Robot* bot) {

                 tuple<float, float> polar_coords =
                     rect_to_polar(origin, target, bot->pos);

                 if (good_robot_check(polar_coords, target, origin)) {
                     bot_locations.push_back(polar_coords);
                 }
             });

    // Add imaginary obstacles
    for_each(hypothetical_robot_locations.begin(),
             hypothetical_robot_locations.end(),
             [&bot_locations, target, origin, this](Point obstacle) {

                 tuple<float, float> polar_coords =
                     rect_to_polar(origin, target, obstacle);

                 if (good_robot_check(polar_coords, target, origin)) {
                     bot_locations.push_back(polar_coords);
                 }
             });

    // Use rays between -3 * std_dev and 3 * std_dev
    float half_std_dev = 1.5f * *kick_std_dev;
    float half_target_width = targetWidth;

    // No bots in the way
    if (bot_locations.size() == 0) {
        // CDF Estimation
        // The ray estimations are linearlly related to the true CDF probability
        // These are found through testing the points and using the best fit
        // line
        // with R^2 = 0.998458
        float score =
            1.1219 * erf(half_target_width / (*kick_std_dev * sqrt(2))) +
            0.0125;
        return min(score, 1.0f);
    }

    float total = 0.0f;
    float max_total = 0.0f;

    float cur_ray_angle = -1 * half_std_dev;
    float ray_angle_inc = 2 * half_std_dev / number_of_rays;

    // For each ray
    while (cur_ray_angle < half_std_dev ||
           nearlyEqual(cur_ray_angle, half_std_dev)) {
        vector<float> scores;

        // For each robot
        for (tuple<float, float> bot_location : bot_locations) {
            float angle_off_ray = get<1>(bot_location) - cur_ray_angle;

            // Distance from ray
            float u = sin(angle_off_ray) * get<0>(bot_location);
            // Overal kernal scale
            u *= *kernal_width_coefficient;
            // Distance from kick point
            u *= exp(get<0>(bot_location) * *distance_coefficient);

            u = min(1.0f, u);
            u = max(-1.0f, u);

            // Triweight kernal function
            scores.push_back(1 - (float)max(pow((1 - pow(u, 2)), 3), 0.0));
        }

        // Gets -1, 0, 1 depending on whether abs(cur_ray_angle) is >
        // half_target_width
        float in_range = copysign(1.0, half_target_width - fabs(cur_ray_angle));
        // Moves in_range to 0 if outside, 1 if inside the range, 0.5 if on the
        // edge
        in_range = in_range * 0.5 + 0.5;

        // PDF for Gaussian Distribution, Assume mean = 0
        float ray_offset_scale = M_1_SQRT_2_PI / *kick_std_dev;
        ray_offset_scale *=
            fast_exp(-0.5 * pow(cur_ray_angle / *kick_std_dev, 2));

        float min_score = *min_element(begin(scores), end(scores));

        // Only add to the total if it's within the target range
        total += in_range * min_score * ray_offset_scale;

        max_total += ray_offset_scale;
        cur_ray_angle += ray_angle_inc;
    }

    return total / max_total;
}

float KickEvaluator::eval_pt_to_robot(Geometry2d::Point origin,
                                      Geometry2d::Point target) {
    return eval_pt_to_pt(origin, target, 2 * Robot_Radius);
}

float KickEvaluator::eval_pt_to_opp_goal(Geometry2d::Point origin) {
    Segment their_goal{
        Point{-Field_Dimensions::Current_Dimensions.GoalWidth() / 2,
              Field_Dimensions::Current_Dimensions.Length()},
        Point{Field_Dimensions::Current_Dimensions.GoalWidth() / 2,
              Field_Dimensions::Current_Dimensions.Length()}};

    return eval_pt_to_seg(origin, their_goal);
}

float KickEvaluator::eval_pt_to_our_goal(Geometry2d::Point origin) {
    Segment our_goal{
        Point{-Field_Dimensions::Current_Dimensions.GoalWidth() / 2, 0},
        Point{Field_Dimensions::Current_Dimensions.GoalWidth() / 2, 0}};

    return eval_pt_to_seg(origin, our_goal);
}

float KickEvaluator::eval_pt_to_seg(Geometry2d::Point origin,
                                    Geometry2d::Segment target) {
    Point pt1 = target.pt[0] - origin;
    Point pt2 = target.pt[1] - origin;
    double angle = abs(atan2(pt1.y(), pt1.x()) - atan2(pt2.y(), pt2.x()));

    return eval_pt_to_pt(origin, target.center(), angle);
}

tuple<float, float> KickEvaluator::rect_to_polar(Point origin, Point target,
                                                 Point obstacle) {
    Point dir = obstacle - origin;

    return make_tuple(dir.mag(), dir.angleBetween(target - origin));
}

float KickEvaluator::fast_exp(float x) {
    return (24 + x * (24 + x * (12 + x * (4 + x)))) * 0.041666666f;
}

bool KickEvaluator::good_robot_check(std::tuple<float, float> polar,
                                     Geometry2d::Point target,
                                     Geometry2d::Point origin) {
    float delta_dist = get<0>(polar) - (target - origin).mag();

    // Checks that the robot is within the angle range in front
    // and not too far behind the target position
    return fabs(get<1>(polar)) < *robot_angle_filter_limit &&
           delta_dist * *kernal_width_coefficient < 1;
}<commit_msg>Cleaner way to deal with 0 blocking robots<commit_after>#include "KickEvaluator.hpp"
#include <Geometry2d/Util.hpp>

#include <algorithm>
#include <array>
#include <math.h>
#include <cmath>
#include <tuple>

REGISTER_CONFIGURABLE(KickEvaluator)

// 1 / sqrt(2*pi)
#define M_1_SQRT_2_PI 0.3989422

using namespace std;
using namespace Geometry2d;

ConfigDouble* KickEvaluator::robot_angle_filter_limit;
ConfigDouble* KickEvaluator::kick_std_dev;
ConfigDouble* KickEvaluator::num_rays;

ConfigDouble* KickEvaluator::kernal_width_coefficient;
ConfigDouble* KickEvaluator::distance_coefficient;

void KickEvaluator::createConfiguration(Configuration* cfg) {
    robot_angle_filter_limit = new ConfigDouble(
        cfg, "KickEvaluator/robot_angle_filter_limit", 0.35 * M_PI);
    kick_std_dev = new ConfigDouble(cfg, "KickEvaluator/kick_std_dev", 0.08);
    num_rays = new ConfigDouble(cfg, "KickEvaluator/num_rays", 16);

    kernal_width_coefficient =
        new ConfigDouble(cfg, "KickEvaluator/kernal_width_coefficient", 2.0);
    distance_coefficient =
        new ConfigDouble(cfg, "KickEvaluator/distance_coefficient", -1.0 / 7.0);
}

KickEvaluator::KickEvaluator(SystemState* systemState) : system(systemState) {}

float KickEvaluator::eval_pt_to_pt(Point origin, Point target,
                                   float targetWidth) {
    vector<Robot*> bots(system->self.size() + system->opp.size());

    auto filter_predicate = [&](const Robot* bot) -> bool {
        return bot != nullptr && bot->visible &&
               find(excluded_robots.begin(), excluded_robots.end(), bot) ==
                   excluded_robots.end();
    };

    auto end_it = copy_if(system->self.begin(), system->self.end(),
                          bots.begin(), filter_predicate);

    end_it = copy_if(system->opp.begin(), system->opp.end(), end_it,
                     filter_predicate);

    bots.resize(distance(bots.begin(), end_it));

    // < Dist, Angle >
    vector<tuple<float, float> > bot_locations;

    // Add robots as obstacles
    for_each(bots.begin(), bots.end(),
             [&bot_locations, target, origin, this](Robot* bot) {

                 tuple<float, float> polar_coords =
                     rect_to_polar(origin, target, bot->pos);

                 if (good_robot_check(polar_coords, target, origin)) {
                     bot_locations.push_back(polar_coords);
                 }
             });

    // Add imaginary obstacles
    for_each(hypothetical_robot_locations.begin(),
             hypothetical_robot_locations.end(),
             [&bot_locations, target, origin, this](Point obstacle) {

                 tuple<float, float> polar_coords =
                     rect_to_polar(origin, target, obstacle);

                 if (good_robot_check(polar_coords, target, origin)) {
                     bot_locations.push_back(polar_coords);
                 }
             });

    // Use rays between -3 * std_dev and 3 * std_dev
    float half_std_dev = 1.5f * *kick_std_dev;
    float half_target_width = targetWidth;

    float total = 0.0f;
    float max_total = 0.0f;

    float cur_ray_angle = -1 * half_std_dev;
    float ray_angle_inc = 2 * half_std_dev / number_of_rays;

    // For each ray
    while (cur_ray_angle < half_std_dev ||
           nearlyEqual(cur_ray_angle, half_std_dev)) {
        vector<float> scores;
        // Default to perfect score
        scores.push_back(1);

        // For each robot
        for (tuple<float, float> bot_location : bot_locations) {
            float angle_off_ray = get<1>(bot_location) - cur_ray_angle;

            // Distance from ray
            float u = sin(angle_off_ray) * get<0>(bot_location);
            // Overal kernal scale
            u *= *kernal_width_coefficient;
            // Distance from kick point
            u *= exp(get<0>(bot_location) * *distance_coefficient);

            u = min(1.0f, u);
            u = max(-1.0f, u);

            // Triweight kernal function
            scores.push_back(1 - (float)max(pow((1 - pow(u, 2)), 3), 0.0));
        }

        // Gets -1, 0, 1 depending on whether abs(cur_ray_angle) is >
        // half_target_width
        float in_range = copysign(1.0, half_target_width - fabs(cur_ray_angle));
        // Moves in_range to 0 if outside, 1 if inside the range, 0.5 if on the
        // edge
        in_range = in_range * 0.5 + 0.5;

        // PDF for Gaussian Distribution, Assume mean = 0
        float ray_offset_scale = M_1_SQRT_2_PI / *kick_std_dev;
        ray_offset_scale *=
            fast_exp(-0.5 * pow(cur_ray_angle / *kick_std_dev, 2));

        float min_score = *min_element(begin(scores), end(scores));

        // Only add to the total if it's within the target range
        total += in_range * min_score * ray_offset_scale;

        max_total += ray_offset_scale;
        cur_ray_angle += ray_angle_inc;
    }

    return total / max_total;
}

float KickEvaluator::eval_pt_to_robot(Geometry2d::Point origin,
                                      Geometry2d::Point target) {
    return eval_pt_to_pt(origin, target, 2 * Robot_Radius);
}

float KickEvaluator::eval_pt_to_opp_goal(Geometry2d::Point origin) {
    Segment their_goal{
        Point{-Field_Dimensions::Current_Dimensions.GoalWidth() / 2,
              Field_Dimensions::Current_Dimensions.Length()},
        Point{Field_Dimensions::Current_Dimensions.GoalWidth() / 2,
              Field_Dimensions::Current_Dimensions.Length()}};

    return eval_pt_to_seg(origin, their_goal);
}

float KickEvaluator::eval_pt_to_our_goal(Geometry2d::Point origin) {
    Segment our_goal{
        Point{-Field_Dimensions::Current_Dimensions.GoalWidth() / 2, 0},
        Point{Field_Dimensions::Current_Dimensions.GoalWidth() / 2, 0}};

    return eval_pt_to_seg(origin, our_goal);
}

float KickEvaluator::eval_pt_to_seg(Geometry2d::Point origin,
                                    Geometry2d::Segment target) {
    Point pt1 = target.pt[0] - origin;
    Point pt2 = target.pt[1] - origin;
    double angle = abs(atan2(pt1.y(), pt1.x()) - atan2(pt2.y(), pt2.x()));

    return eval_pt_to_pt(origin, target.center(), angle);
}

tuple<float, float> KickEvaluator::rect_to_polar(Point origin, Point target,
                                                 Point obstacle) {
    Point dir = obstacle - origin;

    return make_tuple(dir.mag(), dir.angleBetween(target - origin));
}

float KickEvaluator::fast_exp(float x) {
    return (24 + x * (24 + x * (12 + x * (4 + x)))) * 0.041666666f;
}

bool KickEvaluator::good_robot_check(std::tuple<float, float> polar,
                                     Geometry2d::Point target,
                                     Geometry2d::Point origin) {
    float delta_dist = get<0>(polar) - (target - origin).mag();

    // Checks that the robot is within the angle range in front
    // and not too far behind the target position
    return fabs(get<1>(polar)) < *robot_angle_filter_limit &&
           delta_dist * *kernal_width_coefficient < 1;
}<|endoftext|>


<commit_before>#include <Common/HighQueuePch.h>
#include "Producer.h"
#include <HighQueue/details/HQReservePosition.h>
using namespace HighQueue;

Producer::Producer(ConnectionPtr & connection, bool solo)
: solo_(solo)
, connection_(connection)
, header_(connection_->getHeader())
, entryCount_(header_->entryCount_)
, waitStrategy_(header_->producerWaitStrategy_)
, consumerUsesMutex_(header_->consumerWaitStrategy_.mutexUsed_)
, resolver_(header_)
, readPosition_(*resolver_.resolve<volatile Position>(header_->readPosition_))
, publishPosition_(*resolver_.resolve<volatile Position>(header_->publishPosition_))
, reservePosition_(resolver_.resolve<volatile HighQReservePosition>(header_->reservePosition_)->reservePosition_)
, reserveSoloPosition_(reinterpret_cast<volatile Position &>(resolver_.resolve<volatile HighQReservePosition>(header_->reservePosition_)->reservePosition_))
, entryAccessor_(resolver_, header_->entries_, header_->entryCount_)
, publishable_(0)
, statFulls_(0)
, statSkips_(0)
, statPublishWaits_(0)
, statPublishes_(0)
, statSpins_(0)
, statYields_(0)
, statSleeps_(0)
, statWaits_(0)
{
    ++header_->producersPresent_;
}

Producer::~Producer()
{
    --header_->producersPresent_;
}

inline
uint64_t Producer::reserve()
{
    if(solo_)
    {
        return reserveSoloPosition_++;
    }
    return reservePosition_++;
}

void Producer::publish(Message & message)
{
    bool published = false;
    while(!published)
    {
        auto reserved = reserve();
        if(publishable_ <= reserved)
        {
            publishable_ = readPosition_ + entryCount_;
            if(publishable_ <= reserved)
            {
                ++statFulls_;
                if(header_->discardMessagesIfNoConsumer_ && !header_->consumerPresent_)
                {
                    readPosition_ = publishPosition_;
                    publishable_ = readPosition_ + entryCount_;
                }
                size_t remainingSpins = waitStrategy_.spinCount_;
                size_t remainingYields = waitStrategy_.yieldCount_;
                size_t remainingSleeps = waitStrategy_.sleepCount_;
                while(publishable_ <= reserved)
                {
                    if(remainingSpins > 0)
                    {
                        ++statSpins_;
                        if(remainingSpins != WaitStrategy::FOREVER)
                        {
                            --remainingSpins;
                        }
                        std::atomic_thread_fence(std::memory_order::memory_order_consume);
                    }
                    else if(remainingYields > 0)
                    {
                        ++statYields_;
                        if(remainingYields != WaitStrategy::FOREVER)
                        {
                            --remainingYields;
                        }
                        std::this_thread::yield();
                    }
                    else if(remainingSleeps > 0)
                    {
                        ++statSleeps_;
                        if(remainingSleeps != WaitStrategy::FOREVER)
                        {
                            --remainingSleeps;
                        }
                        std::this_thread::sleep_for(waitStrategy_.sleepPeriod_);
                    }
                    else
                    {
                        ++statWaits_;
                        std::unique_lock<std::mutex> guard(header_->waitMutex_);
                        publishable_ = readPosition_ + entryCount_;
                        if(publishable_ > reserved)
                        {
                            header_->producerWaiting_ = true;
                            if(header_->producerWaitConditionVariable_.wait_for(guard, waitStrategy_.mutexWaitTimeout_)
                                == std::cv_status::timeout)
                            {
                                publishable_ = readPosition_ + entryCount_;
                                if(publishable_ <= reserved)
                                {
                                    // todo: define a better exception
                                    throw std::runtime_error("Producer wait timeout.");
                                }
                            }
                        }
                    }
                    publishable_ = readPosition_ + header_->entryCount_;
                }

            }
        }
        HighQEntry & entry = entryAccessor_[reserved];
        if(entry.status_ != HighQEntry::Status::SKIP)
        {
            message.moveTo(entry.message_);
            entry.status_ = HighQEntry::Status::OK;
            published = true;
        }
        else
        {
            ++statSkips_;
        }
        while(publishPosition_ < reserved)
        {
            ++statPublishWaits_;
            std::this_thread::yield();
            std::atomic_thread_fence(std::memory_order::memory_order_acquire);
        }
        if(publishPosition_ == reserved)
        {
            ++publishPosition_;
            std::atomic_thread_fence(std::memory_order::memory_order_release);
            if(consumerUsesMutex_)
            {
                std::unique_lock<std::mutex> guard(header_->waitMutex_);
                if(header_->consumerWaiting_)
                {
                    header_->consumerWaiting_ = false;
                    header_->consumerWaitConditionVariable_.notify_all();
                }
            }
            ++statPublishes_;
        }
    }
}

std::ostream & Producer::writeStats(std::ostream & out) const
{
    return out << "Published " << statPublishes_
               << " Full: " << statFulls_
               << " Skip: " << statSkips_
               << " WaitOtherPublishers: " << statPublishWaits_
               << " Spin: " << statSpins_
               << " Yield: " << statYields_
               << " Sleep: " << statSleeps_
               << " Wait: " << statWaits_
               << " OK: " << statPublishes_
               << std::endl;

}

<commit_msg>Producer: no fence is needed when waiting via mutex.<commit_after>#include <Common/HighQueuePch.h>
#include "Producer.h"
#include <HighQueue/details/HQReservePosition.h>
using namespace HighQueue;

Producer::Producer(ConnectionPtr & connection, bool solo)
: solo_(solo)
, connection_(connection)
, header_(connection_->getHeader())
, entryCount_(header_->entryCount_)
, waitStrategy_(header_->producerWaitStrategy_)
, consumerUsesMutex_(header_->consumerWaitStrategy_.mutexUsed_)
, resolver_(header_)
, readPosition_(*resolver_.resolve<volatile Position>(header_->readPosition_))
, publishPosition_(*resolver_.resolve<volatile Position>(header_->publishPosition_))
, reservePosition_(resolver_.resolve<volatile HighQReservePosition>(header_->reservePosition_)->reservePosition_)
, reserveSoloPosition_(reinterpret_cast<volatile Position &>(resolver_.resolve<volatile HighQReservePosition>(header_->reservePosition_)->reservePosition_))
, entryAccessor_(resolver_, header_->entries_, header_->entryCount_)
, publishable_(0)
, statFulls_(0)
, statSkips_(0)
, statPublishWaits_(0)
, statPublishes_(0)
, statSpins_(0)
, statYields_(0)
, statSleeps_(0)
, statWaits_(0)
{
    ++header_->producersPresent_;
}

Producer::~Producer()
{
    --header_->producersPresent_;
}

inline
uint64_t Producer::reserve()
{
    if(solo_)
    {
        return reserveSoloPosition_++;
    }
    return reservePosition_++;
}

void Producer::publish(Message & message)
{
    bool published = false;
    while(!published)
    {
        auto reserved = reserve();
        if(publishable_ <= reserved)
        {
            publishable_ = readPosition_ + entryCount_;
            if(publishable_ <= reserved)
            {
                ++statFulls_;
                if(header_->discardMessagesIfNoConsumer_ && !header_->consumerPresent_)
                {
                    readPosition_ = publishPosition_;
                    publishable_ = readPosition_ + entryCount_;
                }
                size_t remainingSpins = waitStrategy_.spinCount_;
                size_t remainingYields = waitStrategy_.yieldCount_;
                size_t remainingSleeps = waitStrategy_.sleepCount_;
                while(publishable_ <= reserved)
                {
                    if(remainingSpins > 0)
                    {
                        ++statSpins_;
                        if(remainingSpins != WaitStrategy::FOREVER)
                        {
                            --remainingSpins;
                        }
                        std::atomic_thread_fence(std::memory_order::memory_order_consume);
                    }
                    else if(remainingYields > 0)
                    {
                        ++statYields_;
                        if(remainingYields != WaitStrategy::FOREVER)
                        {
                            --remainingYields;
                        }
                        std::this_thread::yield();
                    }
                    else if(remainingSleeps > 0)
                    {
                        ++statSleeps_;
                        if(remainingSleeps != WaitStrategy::FOREVER)
                        {
                            --remainingSleeps;
                        }
                        std::this_thread::sleep_for(waitStrategy_.sleepPeriod_);
                    }
                    else
                    {
                        ++statWaits_;
                        std::unique_lock<std::mutex> guard(header_->waitMutex_);
                        publishable_ = readPosition_ + entryCount_;
                        if(publishable_ > reserved)
                        {
                            header_->producerWaiting_ = true;
                            if(header_->producerWaitConditionVariable_.wait_for(guard, waitStrategy_.mutexWaitTimeout_)
                                == std::cv_status::timeout)
                            {
                                publishable_ = readPosition_ + entryCount_;
                                if(publishable_ <= reserved)
                                {
                                    // todo: define a better exception
                                    throw std::runtime_error("Producer wait timeout.");
                                }
                            }
                        }
                    }
                    publishable_ = readPosition_ + header_->entryCount_;
                }

            }
        }
        HighQEntry & entry = entryAccessor_[reserved];
        if(entry.status_ != HighQEntry::Status::SKIP)
        {
            message.moveTo(entry.message_);
            entry.status_ = HighQEntry::Status::OK;
            published = true;
        }
        else
        {
            ++statSkips_;
        }
        while(publishPosition_ < reserved)
        {
            ++statPublishWaits_;
            std::this_thread::yield();
            std::atomic_thread_fence(std::memory_order::memory_order_acquire);
        }
        if(publishPosition_ == reserved)
        {
            ++publishPosition_;
            ++statPublishes_;
            if(!consumerUsesMutex_)
            {
                std::atomic_thread_fence(std::memory_order::memory_order_release);
                return;
            }

            std::unique_lock<std::mutex> guard(header_->waitMutex_);
            if(header_->consumerWaiting_)
            {
                header_->consumerWaiting_ = false;
                header_->consumerWaitConditionVariable_.notify_all();
            }
        }
    }
}

std::ostream & Producer::writeStats(std::ostream & out) const
{
    return out << "Published " << statPublishes_
               << " Full: " << statFulls_
               << " Skip: " << statSkips_
               << " WaitOtherPublishers: " << statPublishWaits_
               << " Spin: " << statSpins_
               << " Yield: " << statYields_
               << " Sleep: " << statSleeps_
               << " Wait: " << statWaits_
               << " OK: " << statPublishes_
               << std::endl;

}

<|endoftext|>