<commit_before>#ifndef __STAN__PROB__DIST__UNI__CONTINUOUS__INV_CHI_SQUARE_HPP__
#define __STAN__PROB__DIST__UNI__CONTINUOUS__INV_CHI_SQUARE_HPP__

#include <stan/agrad.hpp>
#include <stan/math/error_handling.hpp>
#include <stan/math/special_functions.hpp>
#include <stan/meta/traits.hpp>
#include <stan/prob/constants.hpp>
#include <stan/prob/traits.hpp>
#include <stan/prob/internal_math.hpp>

namespace stan {

  namespace prob {

    /**
     * The log of an inverse chi-squared density for y with the specified
     * degrees of freedom parameter.
     * The degrees of freedom prarameter must be greater than 0.
     * y must be greater than 0.
     *
     \f{eqnarray*}{
     y &\sim& \mbox{\sf{Inv-}}\chi^2_\nu \\
     \log (p (y \,|\, \nu)) &=& \log \left( \frac{2^{-\nu / 2}}{\Gamma (\nu / 2)} y^{- (\nu / 2 + 1)} \exp^{-1 / (2y)} \right) \\
     &=& - \frac{\nu}{2} \log(2) - \log (\Gamma (\nu / 2)) - (\frac{\nu}{2} + 1) \log(y) - \frac{1}{2y} \\
     & & \mathrm{ where } \; y > 0
     \f}
     * @param y A scalar variable.
     * @param nu Degrees of freedom.
     * @throw std::domain_error if nu is not greater than or equal to 0
     * @throw std::domain_error if y is not greater than or equal to 0.
     * @tparam T_y Type of scalar.
     * @tparam T_dof Type of degrees of freedom.
     */
    template <bool propto,
              typename T_y, typename T_dof,
              class Policy>
    typename return_type<T_y,T_dof>::type
    inv_chi_square_log(const T_y& y, const T_dof& nu,
                       const Policy&) {
      static const char* function = "stan::prob::inv_chi_square_log(%1%)";

      // check if any vectors are zero length
      if (!(stan::length(y)
            && stan::length(nu)))
	return 0.0;

      using stan::math::check_finite;
      using stan::math::check_positive;
      using stan::math::check_not_nan;
      using stan::math::value_of;
      using stan::math::check_consistent_sizes;

      typename return_type<T_y,T_dof>::type logp(0.0);
      if (!check_finite(function, nu, "Degrees of freedom parameter", &logp, Policy()))
        return logp;
      if (!check_positive(function, nu, "Degrees of freedom parameter", &logp, Policy()))
        return logp;
      if (!check_not_nan(function, y, "Random variable", &logp, Policy()))
        return logp;

      if (!(check_consistent_sizes(function,
                                   y,nu,
				   "Random variable","Degrees of freedom parameter",
                                   &logp, Policy())))
        return logp;

      // set up template expressions wrapping scalars into vector views
      VectorView<const T_y> y_vec(y);
      VectorView<const T_dof> nu_vec(nu);
      size_t N = max_size(y, nu);

      for (size_t n = 0; n < length(y); n++)
	if (value_of(y_vec[n]) <= 0)
	  return LOG_ZERO;

      using boost::math::lgamma;
      using stan::math::multiply_log;
      for (size_t n = 0; n < N; n++) {
	if (include_summand<propto,T_dof>::value)
	  logp += nu_vec[n] * NEG_LOG_TWO_OVER_TWO - lgamma(0.5 * nu_vec[n]);
	if (include_summand<propto,T_y,T_dof>::value)
	  logp -= multiply_log(0.5*nu_vec[n]+1.0, y_vec[n]);
	if (include_summand<propto,T_y>::value)
	  logp -= 0.5 / y_vec[n];
      }
      return logp;
    }

    template <bool propto,
              typename T_y, typename T_dof>
    inline
    typename return_type<T_y,T_dof>::type
    inv_chi_square_log(const T_y& y, const T_dof& nu) {
      return inv_chi_square_log<propto>(y,nu,stan::math::default_policy());
    }

    template <typename T_y, typename T_dof,
              class Policy>
    inline
    typename return_type<T_y,T_dof>::type
    inv_chi_square_log(const T_y& y, const T_dof& nu,
                       const Policy&) {
      return inv_chi_square_log<false>(y,nu,Policy());
    }

    template <typename T_y, typename T_dof>
    inline
    typename return_type<T_y,T_dof>::type
    inv_chi_square_log(const T_y& y, const T_dof& nu) {
      return inv_chi_square_log<false>(y,nu,stan::math::default_policy());
    }

      template <typename T_y, typename T_dof, class Policy>
      typename return_type<T_y,T_dof>::type
      inv_chi_square_cdf(const T_y& y, const T_dof& nu, const Policy&) {

          // Size checks
          if ( !( stan::length(y) && stan::length(nu) ) ) return 0.0;

          // Error checks
          static const char* function = "stan::prob::inv_chi_square_cdf(%1%)";

          using stan::math::check_finite;
          using stan::math::check_positive;
          using stan::math::check_not_nan;
          using stan::math::check_consistent_sizes;

          using boost::math::tools::promote_args;

          double P(1.0);

          if (!check_finite(function, nu, "Degrees of freedom parameter", &P, Policy()))
              return P;

          if (!check_positive(function, nu, "Degrees of freedom parameter", &P, Policy()))
              return P;

          if (!check_not_nan(function, y, "Random variable", &P, Policy()))
              return P;

          if (!check_positive(function, y, "Random variable", &P, Policy()))
              return P;

          if (!(check_consistent_sizes(function, y, nu,
                                       "Random variable", "Degrees of freedom parameter",
                                       &P, Policy())))
              return P;

          // Wrap arguments in vectors
          VectorView<const T_y> y_vec(y);
          VectorView<const T_dof> nu_vec(nu);
          size_t N = max_size(y, nu);

          agrad::OperandsAndPartials<T_y, T_dof> operands_and_partials(y, nu);

          std::fill(operands_and_partials.all_partials,
                    operands_and_partials.all_partials + operands_and_partials.nvaris, 0.0);

          // Compute CDF and its gradients
          using stan::math::value_of;
          using boost::math::gamma_p_derivative;
          using boost::math::gamma_q;
          using boost::math::tgamma;
          using boost::math::digamma;

          // Cache a few expensive function calls if nu is a parameter
          DoubleVectorView<!is_constant_struct<T_dof>::value, T_dof> gamma_vec(stan::length(nu));
          DoubleVectorView<!is_constant_struct<T_dof>::value, T_dof> digamma_vec(stan::length(nu));

          if (!is_constant_struct<T_dof>::value)  {

              for (size_t i = 0; i < stan::length(nu); i++) {
                  const double nu_dbl = value_of(nu_vec[i]);
                  gamma_vec[i] = tgamma(nu_dbl);
                  digamma_vec[i] = digamma(nu_dbl);
              }

          }

          // Compute vectorized CDF and gradient
          for (size_t n = 0; n < N; n++) {

              // Pull out values
              const double y_dbl = value_of(y_vec[n]);
              const double y_inv_dbl = 1.0 / y_dbl;
              const double nu_dbl = value_of(nu_vec[n]);

              // Compute
              const double Pn = gamma_q(0.5 * nu_dbl, 0.5 * y_inv_dbl);

              P *= Pn;

              if (!is_constant_struct<T_y>::value)
                  operands_and_partials.d_x1[n]
                  += 0.5 * y_inv_dbl * y_inv_dbl * gamma_p_derivative(0.5 * nu_dbl, 0.5 * y_inv_dbl) / Pn;

              if (!is_constant_struct<T_dof>::value)
                  operands_and_partials.d_x2[n]
                  += 0.5 * stan::math::gradRegIncGamma(0.5 * nu_dbl, 0.5 * y_inv_dbl, gamma_vec[n], digamma_vec[n]) / Pn;

          }

          for (size_t n = 0; n < N; n++) {

              if (!is_constant_struct<T_y>::value)
                  operands_and_partials.d_x1[n] *= P;

              if (!is_constant_struct<T_dof>::value)
                  operands_and_partials.d_x2[n] *= P;

          }

          return operands_and_partials.to_var(P);

      }

      template <typename T_y, typename T_dof>
      inline typename return_type<T_y,T_dof>::type
      inv_chi_square_cdf(const T_y& y, const T_dof& nu) {
          return inv_chi_square_cdf(y, nu, stan::math::default_policy());
      }

  }
}

#endif

<commit_msg>refactoring inv_chi_square distribution<commit_after>#ifndef __STAN__PROB__DIST__UNI__CONTINUOUS__INV_CHI_SQUARE_HPP__
#define __STAN__PROB__DIST__UNI__CONTINUOUS__INV_CHI_SQUARE_HPP__

#include <stan/agrad.hpp>
#include <stan/math/error_handling.hpp>
#include <stan/math/special_functions.hpp>
#include <stan/meta/traits.hpp>
#include <stan/prob/constants.hpp>
#include <stan/prob/traits.hpp>
#include <stan/prob/internal_math.hpp>

namespace stan {

  namespace prob {

    /**
     * The log of an inverse chi-squared density for y with the specified
     * degrees of freedom parameter.
     * The degrees of freedom prarameter must be greater than 0.
     * y must be greater than 0.
     *
     \f{eqnarray*}{
     y &\sim& \mbox{\sf{Inv-}}\chi^2_\nu \\
     \log (p (y \,|\, \nu)) &=& \log \left( \frac{2^{-\nu / 2}}{\Gamma (\nu / 2)} y^{- (\nu / 2 + 1)} \exp^{-1 / (2y)} \right) \\
     &=& - \frac{\nu}{2} \log(2) - \log (\Gamma (\nu / 2)) - (\frac{\nu}{2} + 1) \log(y) - \frac{1}{2y} \\
     & & \mathrm{ where } \; y > 0
     \f}
     * @param y A scalar variable.
     * @param nu Degrees of freedom.
     * @throw std::domain_error if nu is not greater than or equal to 0
     * @throw std::domain_error if y is not greater than or equal to 0.
     * @tparam T_y Type of scalar.
     * @tparam T_dof Type of degrees of freedom.
     */
    template <bool propto,
              typename T_y, typename T_dof,
              class Policy>
    typename return_type<T_y,T_dof>::type
    inv_chi_square_log(const T_y& y, const T_dof& nu,
                       const Policy&) {
      static const char* function = "stan::prob::inv_chi_square_log(%1%)";

      // check if any vectors are zero length
      if (!(stan::length(y)
            && stan::length(nu)))
	return 0.0;

      using stan::math::check_finite;
      using stan::math::check_positive;
      using stan::math::check_not_nan;
      using stan::math::value_of;
      using stan::math::check_consistent_sizes;

      typename return_type<T_y,T_dof>::type logp(0.0);
      if (!check_finite(function, nu, "Degrees of freedom parameter", &logp, Policy()))
        return logp;
      if (!check_positive(function, nu, "Degrees of freedom parameter", &logp, Policy()))
        return logp;
      if (!check_not_nan(function, y, "Random variable", &logp, Policy()))
        return logp;

      if (!(check_consistent_sizes(function,
                                   y,nu,
				   "Random variable","Degrees of freedom parameter",
                                   &logp, Policy())))
        return logp;

      // set up template expressions wrapping scalars into vector views
      VectorView<const T_y> y_vec(y);
      VectorView<const T_dof> nu_vec(nu);
      size_t N = max_size(y, nu);

      for (size_t n = 0; n < length(y); n++)
	if (value_of(y_vec[n]) <= 0)
	  return LOG_ZERO;

      using boost::math::lgamma;
      using stan::math::multiply_log;
      for (size_t n = 0; n < N; n++) {
	if (include_summand<propto,T_dof>::value)
	  logp += nu_vec[n] * NEG_LOG_TWO_OVER_TWO - lgamma(0.5 * nu_vec[n]);
	if (include_summand<propto,T_y,T_dof>::value)
	  logp -= multiply_log(0.5*nu_vec[n]+1.0, y_vec[n]);
	if (include_summand<propto,T_y>::value)
	  logp -= 0.5 / y_vec[n];
      }
      return logp;
    }

    template <bool propto,
              typename T_y, typename T_dof>
    inline
    typename return_type<T_y,T_dof>::type
    inv_chi_square_log(const T_y& y, const T_dof& nu) {
      return inv_chi_square_log<propto>(y,nu,stan::math::default_policy());
    }

    template <typename T_y, typename T_dof,
              class Policy>
    inline
    typename return_type<T_y,T_dof>::type
    inv_chi_square_log(const T_y& y, const T_dof& nu,
                       const Policy&) {
      return inv_chi_square_log<false>(y,nu,Policy());
    }

    template <typename T_y, typename T_dof>
    inline
    typename return_type<T_y,T_dof>::type
    inv_chi_square_log(const T_y& y, const T_dof& nu) {
      return inv_chi_square_log<false>(y,nu,stan::math::default_policy());
    }

    template <typename T_y, typename T_dof, class Policy>
    typename return_type<T_y,T_dof>::type
    inv_chi_square_cdf(const T_y& y, const T_dof& nu, const Policy&) {

      // Size checks
      if ( !( stan::length(y) && stan::length(nu) ) ) return 0.0;

      // Error checks
      static const char* function = "stan::prob::inv_chi_square_cdf(%1%)";

      using stan::math::check_finite;
      using stan::math::check_positive;
      using stan::math::check_not_nan;
      using stan::math::check_consistent_sizes;

      using boost::math::tools::promote_args;

      double P(1.0);

      if (!check_finite(function, nu, "Degrees of freedom parameter", &P, Policy()))
	return P;

      if (!check_positive(function, nu, "Degrees of freedom parameter", &P, Policy()))
	return P;

      if (!check_not_nan(function, y, "Random variable", &P, Policy()))
	return P;

      if (!check_positive(function, y, "Random variable", &P, Policy()))
	return P;

      if (!(check_consistent_sizes(function, y, nu,
				   "Random variable", "Degrees of freedom parameter",
				   &P, Policy())))
	return P;

      // Wrap arguments in vectors
      VectorView<const T_y> y_vec(y);
      VectorView<const T_dof> nu_vec(nu);
      size_t N = max_size(y, nu);

      agrad::OperandsAndPartials<T_y, T_dof> operands_and_partials(y, nu);

      std::fill(operands_and_partials.all_partials,
		operands_and_partials.all_partials + operands_and_partials.nvaris, 0.0);

      // Compute CDF and its gradients
      using stan::math::value_of;
      using boost::math::gamma_p_derivative;
      using boost::math::gamma_q;
      using boost::math::tgamma;
      using boost::math::digamma;

      // Cache a few expensive function calls if nu is a parameter
      DoubleVectorView<!is_constant_struct<T_dof>::value, is_vector<T_dof>::value> gamma_vec(stan::length(nu));
      DoubleVectorView<!is_constant_struct<T_dof>::value, is_vector<T_dof>::value> digamma_vec(stan::length(nu));

      if (!is_constant_struct<T_dof>::value)  {

	for (size_t i = 0; i < stan::length(nu); i++) {
	  const double nu_dbl = value_of(nu_vec[i]);
	  gamma_vec[i] = tgamma(nu_dbl);
	  digamma_vec[i] = digamma(nu_dbl);
	}

      }

      // Compute vectorized CDF and gradient
      for (size_t n = 0; n < N; n++) {

	// Pull out values
	const double y_dbl = value_of(y_vec[n]);
	const double y_inv_dbl = 1.0 / y_dbl;
	const double nu_dbl = value_of(nu_vec[n]);

	// Compute
	const double Pn = gamma_q(0.5 * nu_dbl, 0.5 * y_inv_dbl);

	P *= Pn;

	if (!is_constant_struct<T_y>::value)
	  operands_and_partials.d_x1[n]
	    += 0.5 * y_inv_dbl * y_inv_dbl * gamma_p_derivative(0.5 * nu_dbl, 0.5 * y_inv_dbl) / Pn;

	if (!is_constant_struct<T_dof>::value)
	  operands_and_partials.d_x2[n]
	    += 0.5 * stan::math::gradRegIncGamma(0.5 * nu_dbl, 0.5 * y_inv_dbl, gamma_vec[n], digamma_vec[n]) / Pn;

      }

      for (size_t n = 0; n < N; n++) {

	if (!is_constant_struct<T_y>::value)
	  operands_and_partials.d_x1[n] *= P;

	if (!is_constant_struct<T_dof>::value)
	  operands_and_partials.d_x2[n] *= P;

      }

      return operands_and_partials.to_var(P);

    }

    template <typename T_y, typename T_dof>
    inline typename return_type<T_y,T_dof>::type
    inv_chi_square_cdf(const T_y& y, const T_dof& nu) {
      return inv_chi_square_cdf(y, nu, stan::math::default_policy());
    }

  }
}

#endif

<|endoftext|>


<commit_before>//
//  Copyright Silvin Lubecki 2010
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef OPENCLAM_CL_HPP_INCLUDED
#define OPENCLAM_CL_HPP_INCLUDED

#include <CL/cl.h>
#include "error.hpp"
#include "context.hpp"
#include "builtin.hpp"

#define __kernel
#define kernel

#define __global
#define global

#define APPLY_DEFINES( NAME, FUNCTION )     \
class NAME_CLASS : public openclam::builtin \
{                                           \
private:                                    \
             NAME_CLASS() {}                \
    virtual ~NAME_CLASS() {}                \
                                            \
    FUNCTION;                               \
};                                          \

#define KERNEL( NAME, FUNCTION ) \
#FUNCTION;                       \
APPLY_DEFINES( NAME, FUNCTION );

#endif // #ifndef OPENCLAM_CL_HPP_INCLUDED
<commit_msg>cleaning<commit_after>//
//  Copyright Silvin Lubecki 2010
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef OPENCLAM_CL_HPP_INCLUDED
#define OPENCLAM_CL_HPP_INCLUDED

#include <CL/cl.h>
#include "error.hpp"
#include "context.hpp"
#include "builtin.hpp"

#define __kernel
#define kernel

#define __global
#define global

#define APPLY_DEFINES( NAME, FUNCTION )      \
class NAME_CLASS : private openclam::builtin \
{                                            \
private:                                     \
             NAME_CLASS() {}                 \
    virtual ~NAME_CLASS() {}                 \
                                             \
    FUNCTION;                                \
};                                           \

#define KERNEL( NAME, FUNCTION ) \
#FUNCTION;                       \
APPLY_DEFINES( NAME, FUNCTION );

#endif // #ifndef OPENCLAM_CL_HPP_INCLUDED
<|endoftext|>


<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "rpc_target.h"
#include "shared_rpc_resources.h"
#include <vespa/fastos/thread.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/frt/target.h>
#include <vespa/fnet/transport.h>
#include <vespa/slobrok/sbregister.h>
#include <vespa/slobrok/sbmirror.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <cassert>
#include <chrono>
#include <thread>

#include <vespa/log/log.h>
LOG_SETUP(".storage.shared_rpc_resources");

using namespace std::chrono_literals;

namespace storage::rpc {

namespace {

class RpcTargetImpl : public RpcTarget {
private:
    FRT_Target* _target;
    vespalib::string _spec;

public:
    RpcTargetImpl(FRT_Target* target, const vespalib::string& spec)
        : _target(target),
          _spec(spec)
    {}
    ~RpcTargetImpl() override {
        _target->SubRef();
    }
    FRT_Target* get() noexcept override { return _target; }
    bool is_valid() const noexcept override { return _target->IsValid(); }
    const vespalib::string& spec() const noexcept override { return _spec; }
};

}

class SharedRpcResources::RpcTargetFactoryImpl : public RpcTargetFactory {
private:
    FRT_Supervisor& _orb;

public:
    RpcTargetFactoryImpl(FRT_Supervisor& orb)
        : _orb(orb)
    {}
    std::unique_ptr<RpcTarget> make_target(const vespalib::string& connection_spec) const override {
        auto* raw_target = _orb.GetTarget(connection_spec.c_str());
        if (raw_target) {
            return std::make_unique<RpcTargetImpl>(raw_target, connection_spec);
        }
        return std::unique_ptr<RpcTarget>();
    }
};

SharedRpcResources::SharedRpcResources(const config::ConfigUri& config_uri,
                                       int rpc_server_port,
                                       size_t rpc_thread_pool_size,
                                       size_t rpc_events_before_wakeup)
    : _thread_pool(std::make_unique<FastOS_ThreadPool>(1024*60)),
      _transport(std::make_unique<FNET_Transport>(fnet::TransportConfig(rpc_thread_pool_size).
              events_before_wakeup(rpc_events_before_wakeup))),
      _orb(std::make_unique<FRT_Supervisor>(_transport.get())),
      _slobrok_register(std::make_unique<slobrok::api::RegisterAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))),
      _slobrok_mirror(std::make_unique<slobrok::api::MirrorAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))),
      _target_factory(std::make_unique<RpcTargetFactoryImpl>(*_orb)),
      _hostname(vespalib::HostName::get()),
      _rpc_server_port(rpc_server_port),
      _shutdown(false)
{ }

// TODO make sure init/shutdown is safe for aborted init in comm. mgr.

SharedRpcResources::~SharedRpcResources() {
    if (!_shutdown) {
        shutdown();
    }
}

void SharedRpcResources::start_server_and_register_slobrok(vespalib::stringref my_handle) {
    LOG(debug, "Starting main RPC supervisor on port %d with slobrok handle '%s'",
        _rpc_server_port, vespalib::string(my_handle).c_str());
    if (!_orb->Listen(_rpc_server_port)) {
        throw vespalib::IllegalStateException(vespalib::make_string("Failed to listen to RPC port %d", _rpc_server_port),
                                              VESPA_STRLOC);
    }
    _transport->Start(_thread_pool.get());
    _slobrok_register->registerName(my_handle);
    wait_until_slobrok_is_ready();
    _handle = my_handle;
}

void SharedRpcResources::wait_until_slobrok_is_ready() {
    // TODO look more closely at how mbus does its slobrok business
    while (_slobrok_register->busy() || !_slobrok_mirror->ready()) {
        // TODO some form of timeout mechanism here, and warning logging to identify SB issues
        LOG(debug, "Waiting for Slobrok to become ready");
        std::this_thread::sleep_for(50ms);
    }
}

void SharedRpcResources::shutdown() {
    assert(!_shutdown);
    if (listen_port() > 0) {
        _slobrok_register->unregisterName(_handle);
        // Give slobrok some time to dispatch unregister RPC
        while (_slobrok_register->busy()) {
            std::this_thread::sleep_for(10ms);
        }
    }
    _slobrok_register.reset(); // Implicitly kill any pending slobrok tasks prior to shutting down transport layer
    _transport->ShutDown(true);
    // FIXME need to reset to break weak_ptrs? But ShutDown should already sync pending resolves...!
    _shutdown = true;
}

int SharedRpcResources::listen_port() const noexcept {
    return _orb->GetListenPort();
}

const RpcTargetFactory& SharedRpcResources::target_factory() const {
    return *_target_factory;
}

}
<commit_msg>delay destruction of the slobrok register component<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "rpc_target.h"
#include "shared_rpc_resources.h"
#include <vespa/fastos/thread.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/frt/target.h>
#include <vespa/fnet/transport.h>
#include <vespa/slobrok/sbregister.h>
#include <vespa/slobrok/sbmirror.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <cassert>
#include <chrono>
#include <thread>

#include <vespa/log/log.h>
LOG_SETUP(".storage.shared_rpc_resources");

using namespace std::chrono_literals;

namespace storage::rpc {

namespace {

class RpcTargetImpl : public RpcTarget {
private:
    FRT_Target* _target;
    vespalib::string _spec;

public:
    RpcTargetImpl(FRT_Target* target, const vespalib::string& spec)
        : _target(target),
          _spec(spec)
    {}
    ~RpcTargetImpl() override {
        _target->SubRef();
    }
    FRT_Target* get() noexcept override { return _target; }
    bool is_valid() const noexcept override { return _target->IsValid(); }
    const vespalib::string& spec() const noexcept override { return _spec; }
};

}

class SharedRpcResources::RpcTargetFactoryImpl : public RpcTargetFactory {
private:
    FRT_Supervisor& _orb;

public:
    RpcTargetFactoryImpl(FRT_Supervisor& orb)
        : _orb(orb)
    {}
    std::unique_ptr<RpcTarget> make_target(const vespalib::string& connection_spec) const override {
        auto* raw_target = _orb.GetTarget(connection_spec.c_str());
        if (raw_target) {
            return std::make_unique<RpcTargetImpl>(raw_target, connection_spec);
        }
        return std::unique_ptr<RpcTarget>();
    }
};

SharedRpcResources::SharedRpcResources(const config::ConfigUri& config_uri,
                                       int rpc_server_port,
                                       size_t rpc_thread_pool_size,
                                       size_t rpc_events_before_wakeup)
    : _thread_pool(std::make_unique<FastOS_ThreadPool>(1024*60)),
      _transport(std::make_unique<FNET_Transport>(fnet::TransportConfig(rpc_thread_pool_size).
              events_before_wakeup(rpc_events_before_wakeup))),
      _orb(std::make_unique<FRT_Supervisor>(_transport.get())),
      _slobrok_register(std::make_unique<slobrok::api::RegisterAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))),
      _slobrok_mirror(std::make_unique<slobrok::api::MirrorAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))),
      _target_factory(std::make_unique<RpcTargetFactoryImpl>(*_orb)),
      _hostname(vespalib::HostName::get()),
      _rpc_server_port(rpc_server_port),
      _shutdown(false)
{ }

// TODO make sure init/shutdown is safe for aborted init in comm. mgr.

SharedRpcResources::~SharedRpcResources() {
    if (!_shutdown) {
        shutdown();
    }
}

void SharedRpcResources::start_server_and_register_slobrok(vespalib::stringref my_handle) {
    LOG(debug, "Starting main RPC supervisor on port %d with slobrok handle '%s'",
        _rpc_server_port, vespalib::string(my_handle).c_str());
    if (!_orb->Listen(_rpc_server_port)) {
        throw vespalib::IllegalStateException(vespalib::make_string("Failed to listen to RPC port %d", _rpc_server_port),
                                              VESPA_STRLOC);
    }
    _transport->Start(_thread_pool.get());
    _slobrok_register->registerName(my_handle);
    wait_until_slobrok_is_ready();
    _handle = my_handle;
}

void SharedRpcResources::wait_until_slobrok_is_ready() {
    // TODO look more closely at how mbus does its slobrok business
    while (_slobrok_register->busy() || !_slobrok_mirror->ready()) {
        // TODO some form of timeout mechanism here, and warning logging to identify SB issues
        LOG(debug, "Waiting for Slobrok to become ready");
        std::this_thread::sleep_for(50ms);
    }
}

void SharedRpcResources::shutdown() {
    assert(!_shutdown);
    if (listen_port() > 0) {
        _slobrok_register->unregisterName(_handle);
        // Give slobrok some time to dispatch unregister RPC
        while (_slobrok_register->busy()) {
            std::this_thread::sleep_for(10ms);
        }
    }
    _transport->ShutDown(true);
    // FIXME need to reset to break weak_ptrs? But ShutDown should already sync pending resolves...!
    _shutdown = true;
}

int SharedRpcResources::listen_port() const noexcept {
    return _orb->GetListenPort();
}

const RpcTargetFactory& SharedRpcResources::target_factory() const {
    return *_target_factory;
}

}
<|endoftext|>


<commit_before>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include <cstdint>

#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"

// Please use the appropriate namespace for your project
namespace tensorflow {
namespace custom_op_examples {

using ::tensorflow::OpKernel;
using ::tensorflow::OpKernelConstruction;
using ::tensorflow::OpKernelContext;
using ::tensorflow::Tensor;
using ::tensorflow::errors::Internal;
using ::tensorflow::errors::InvalidArgument;

// Multiple types for the values inside two of the input tensors
// (e.g. int32, float) are supported by using a template where the type is T.
template <typename T>
class MultiplexDenseOp : public OpKernel {
 public:
  explicit MultiplexDenseOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("N", &num_cond_a_));
  }

  MultiplexDenseOp(const MultiplexDenseOp& other) = delete;
  MultiplexDenseOp& operator=(const MultiplexDenseOp& other) = delete;
  ~MultiplexDenseOp() override = default;

  void Compute(OpKernelContext* ctx) override {
    // Optional error checking: cond and a_values are lists of N, so there are
    // a total of 2N+1 inputs. Check that the  number of inputs and the
    // `N` Attr is consistent.
    const int64_t expected_inputs = 2 * num_cond_a_ + 1;
    OP_REQUIRES(ctx, expected_inputs == ctx->num_inputs(),
                Internal("expected_inputs != num_inputs(): ", expected_inputs,
                         " != ", ctx->num_inputs()));
    VLOG(1) << "N " << num_cond_a_;

    const auto& first_cond_tensor = ctx->input(0);
    const auto& first_a_values_tensor = ctx->input(num_cond_a_);
    const auto& b_values_tensor = ctx->input(2 * num_cond_a_);

    // Allow any shape, but require that a_values, b_values, and cond all
    // have the same shape.
    // Note that ::tensorflow::TensorShapeUtils has some useful functions
    // for checking shapes.
    for (int64_t i = 0; i < num_cond_a_; i++) {
      const auto& cond_tensor_i = ctx->input(i);
      const auto& a_values_tensor_i = ctx->input(num_cond_a_ + i);
      OP_REQUIRES(
          ctx, a_values_tensor_i.shape() == b_values_tensor.shape(),
          InvalidArgument(
              "a_values[", i,
              "] and b_values must have the same shape. "
              "a_values[",
              i, "] shape: ", a_values_tensor_i.DebugString(),
              " b_values shape: ", b_values_tensor.shape().DebugString()));
      OP_REQUIRES(
          ctx, cond_tensor_i.shape() == b_values_tensor.shape(),
          InvalidArgument(
              "cond_values[", i,
              "] and b_valuesmust have the same shape. "
              "cond_values[",
              i, "] shape: ", first_a_values_tensor.shape().DebugString(),
              " b_values shape: ", first_cond_tensor.shape().DebugString()));
    }

    // Create an output tensor
    Tensor* output_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output(0, b_values_tensor.shape(), &output_tensor));
    auto output = output_tensor->template flat<T>();

    const auto b_values = b_values_tensor.flat<T>();
    // np.select style behavior, `cond` and `a_values` are lists of tensors.
    // Also works for the np.where style case where there is only one `cond`
    // and one `a_values` tensor.
    const int64_t N = first_a_values_tensor.NumElements();
    for (int64_t i = 0; i < N; i++) {
      bool flag = false;
      for (int64_t list_index = 0; list_index < num_cond_a_; list_index++) {
        const auto& cond_tensor = ctx->input(list_index);
        const auto& a_values_tensor = ctx->input(num_cond_a_ + list_index);
        const auto cond = cond_tensor.flat<bool>();
        const auto a_values = a_values_tensor.flat<T>();
        if (cond(i)) {
          output(i) = a_values(i);
          flag = true;
          VLOG(1) << "A " << list_index << " for " << i;
          break;
        }
      }
      if (!flag) {
        output(i) = b_values(i);
        VLOG(1) << "B for " << i;
      }
    }
  }

 private:
  int64_t num_cond_a_;  // the number of `cond` and `a` input tensors
};

// The "Name" used by REGISTER_KERNEL_BUILDER is defined by REGISTER_OP,
// see multiplex_4_op.cc.
// To support tensors containing different types (e.g. int32, float), one
// kernel per type is registered and is templatized by the "T" attr value.
// The TF_CALL_ALL_TYPES macro registers the op for all types appropriate for
// the target platform. See go/tf-custom-ops-guide
#define REGISTER_KERNELS(type)                                  \
  REGISTER_KERNEL_BUILDER(Name("Examples>MultiplexDense")       \
                              .Device(::tensorflow::DEVICE_CPU) \
                              .TypeConstraint<type>("T"),       \
                          MultiplexDenseOp<type>)

TF_CALL_ALL_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

}  // namespace custom_op_examples
}  // namespace tensorflow
<commit_msg>use 'template' keyword to treat 'flat' as a dependent template name in multiplex_4<commit_after>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include <cstdint>

#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"

// Please use the appropriate namespace for your project
namespace tensorflow {
namespace custom_op_examples {

using ::tensorflow::OpKernel;
using ::tensorflow::OpKernelConstruction;
using ::tensorflow::OpKernelContext;
using ::tensorflow::Tensor;
using ::tensorflow::errors::Internal;
using ::tensorflow::errors::InvalidArgument;

// Multiple types for the values inside two of the input tensors
// (e.g. int32, float) are supported by using a template where the type is T.
template <typename T>
class MultiplexDenseOp : public OpKernel {
 public:
  explicit MultiplexDenseOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("N", &num_cond_a_));
  }

  MultiplexDenseOp(const MultiplexDenseOp& other) = delete;
  MultiplexDenseOp& operator=(const MultiplexDenseOp& other) = delete;
  ~MultiplexDenseOp() override = default;

  void Compute(OpKernelContext* ctx) override {
    // Optional error checking: cond and a_values are lists of N, so there are
    // a total of 2N+1 inputs. Check that the  number of inputs and the
    // `N` Attr is consistent.
    const int64_t expected_inputs = 2 * num_cond_a_ + 1;
    OP_REQUIRES(ctx, expected_inputs == ctx->num_inputs(),
                Internal("expected_inputs != num_inputs(): ", expected_inputs,
                         " != ", ctx->num_inputs()));
    VLOG(1) << "N " << num_cond_a_;

    const auto& first_cond_tensor = ctx->input(0);
    const auto& first_a_values_tensor = ctx->input(num_cond_a_);
    const auto& b_values_tensor = ctx->input(2 * num_cond_a_);

    // Allow any shape, but require that a_values, b_values, and cond all
    // have the same shape.
    // Note that ::tensorflow::TensorShapeUtils has some useful functions
    // for checking shapes.
    for (int64_t i = 0; i < num_cond_a_; i++) {
      const auto& cond_tensor_i = ctx->input(i);
      const auto& a_values_tensor_i = ctx->input(num_cond_a_ + i);
      OP_REQUIRES(
          ctx, a_values_tensor_i.shape() == b_values_tensor.shape(),
          InvalidArgument(
              "a_values[", i,
              "] and b_values must have the same shape. "
              "a_values[",
              i, "] shape: ", a_values_tensor_i.DebugString(),
              " b_values shape: ", b_values_tensor.shape().DebugString()));
      OP_REQUIRES(
          ctx, cond_tensor_i.shape() == b_values_tensor.shape(),
          InvalidArgument(
              "cond_values[", i,
              "] and b_valuesmust have the same shape. "
              "cond_values[",
              i, "] shape: ", first_a_values_tensor.shape().DebugString(),
              " b_values shape: ", first_cond_tensor.shape().DebugString()));
    }

    // Create an output tensor
    Tensor* output_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output(0, b_values_tensor.shape(), &output_tensor));
    auto output = output_tensor->template flat<T>();

    const auto b_values = b_values_tensor.template flat<T>();
    // np.select style behavior, `cond` and `a_values` are lists of tensors.
    // Also works for the np.where style case where there is only one `cond`
    // and one `a_values` tensor.
    const int64_t N = first_a_values_tensor.NumElements();
    for (int64_t i = 0; i < N; i++) {
      bool flag = false;
      for (int64_t list_index = 0; list_index < num_cond_a_; list_index++) {
        const auto& cond_tensor = ctx->input(list_index);
        const auto& a_values_tensor = ctx->input(num_cond_a_ + list_index);
        const auto cond = cond_tensor.template flat<bool>();
        const auto a_values = a_values_tensor.template flat<T>();
        if (cond(i)) {
          output(i) = a_values(i);
          flag = true;
          VLOG(1) << "A " << list_index << " for " << i;
          break;
        }
      }
      if (!flag) {
        output(i) = b_values(i);
        VLOG(1) << "B for " << i;
      }
    }
  }

 private:
  int64_t num_cond_a_;  // the number of `cond` and `a` input tensors
};

// The "Name" used by REGISTER_KERNEL_BUILDER is defined by REGISTER_OP,
// see multiplex_4_op.cc.
// To support tensors containing different types (e.g. int32, float), one
// kernel per type is registered and is templatized by the "T" attr value.
// The TF_CALL_ALL_TYPES macro registers the op for all types appropriate for
// the target platform. See go/tf-custom-ops-guide
#define REGISTER_KERNELS(type)                                  \
  REGISTER_KERNEL_BUILDER(Name("Examples>MultiplexDense")       \
                              .Device(::tensorflow::DEVICE_CPU) \
                              .TypeConstraint<type>("T"),       \
                          MultiplexDenseOp<type>)

TF_CALL_ALL_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

}  // namespace custom_op_examples
}  // namespace tensorflow
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2003-2007 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "arch/x86/generated/decoder.hh"
#include "arch/x86/faults.hh"
#include "arch/x86/isa_traits.hh"
#include "base/trace.hh"
#include "cpu/thread_context.hh"
#include "debug/Faults.hh"
#include "sim/full_system.hh"

namespace X86ISA
{
    void X86FaultBase::invoke(ThreadContext * tc, StaticInstPtr inst)
    {
        if (!FullSystem) {
            FaultBase::invoke(tc, inst);
            return;
        }

        PCState pcState = tc->pcState();
        Addr pc = pcState.pc();
        DPRINTF(Faults, "RIP %#x: vector %d: %s\n",
                pc, vector, describe());
        using namespace X86ISAInst::RomLabels;
        HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
        MicroPC entry;
        if (m5reg.mode == LongMode) {
            if (isSoft()) {
                entry = extern_label_longModeSoftInterrupt;
            } else {
                entry = extern_label_longModeInterrupt;
            }
        } else {
            entry = extern_label_legacyModeInterrupt;
        }
        tc->setIntReg(INTREG_MICRO(1), vector);
        tc->setIntReg(INTREG_MICRO(7), pc);
        if (errorCode != (uint64_t)(-1)) {
            if (m5reg.mode == LongMode) {
                entry = extern_label_longModeInterruptWithError;
            } else {
                panic("Legacy mode interrupts with error codes "
                        "aren't implementde.\n");
            }
            // Software interrupts shouldn't have error codes. If one
            // does, there would need to be microcode to set it up.
            assert(!isSoft());
            tc->setIntReg(INTREG_MICRO(15), errorCode);
        }
        pcState.upc(romMicroPC(entry));
        pcState.nupc(romMicroPC(entry) + 1);
        tc->pcState(pcState);
    }

    std::string
    X86FaultBase::describe() const
    {
        std::stringstream ss;
        ccprintf(ss, "%s", mnemonic());
        if (errorCode != (uint64_t)(-1)) {
            ccprintf(ss, "(%#x)", errorCode);
        }

        return ss.str();
    }

    void X86Trap::invoke(ThreadContext * tc, StaticInstPtr inst)
    {
        X86FaultBase::invoke(tc);
        if (!FullSystem)
            return;

        // This is the same as a fault, but it happens -after- the
        // instruction.
        PCState pc = tc->pcState();
        pc.uEnd();
    }

    void X86Abort::invoke(ThreadContext * tc, StaticInstPtr inst)
    {
        panic("Abort exception!");
    }

    void
    InvalidOpcode::invoke(ThreadContext * tc, StaticInstPtr inst)
    {
        if (FullSystem) {
            X86Fault::invoke(tc, inst);
        } else {
            panic("Unrecognized/invalid instruction executed:\n %s",
                    inst->machInst);
        }
    }

    void PageFault::invoke(ThreadContext * tc, StaticInstPtr inst)
    {
        if (FullSystem) {
            HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
            X86FaultBase::invoke(tc);
            /*
             * If something bad happens while trying to enter the page fault
             * handler, I'm pretty sure that's a double fault and then all
             * bets are off. That means it should be safe to update this
             * state now.
             */
            if (m5reg.mode == LongMode) {
                tc->setMiscReg(MISCREG_CR2, addr);
            } else {
                tc->setMiscReg(MISCREG_CR2, (uint32_t)addr);
            }
        } else {
            PageFaultErrorCode code = errorCode;
            const char *modeStr = "";
            if (code.fetch)
                modeStr = "execute";
            else if (code.write)
                modeStr = "write";
            else
                modeStr = "read";
            panic("Tried to %s unmapped address %#x.\n", modeStr, addr);
        }
    }

    std::string
    PageFault::describe() const
    {
        std::stringstream ss;
        ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr);
        return ss.str();
    }

    void
    InitInterrupt::invoke(ThreadContext *tc, StaticInstPtr inst)
    {
        DPRINTF(Faults, "Init interrupt.\n");
        // The otherwise unmodified integer registers should be set to 0.
        for (int index = 0; index < NUM_INTREGS; index++) {
            tc->setIntReg(index, 0);
        }

        CR0 cr0 = tc->readMiscReg(MISCREG_CR0);
        CR0 newCR0 = 1 << 4;
        newCR0.cd = cr0.cd;
        newCR0.nw = cr0.nw;
        tc->setMiscReg(MISCREG_CR0, newCR0);
        tc->setMiscReg(MISCREG_CR2, 0);
        tc->setMiscReg(MISCREG_CR3, 0);
        tc->setMiscReg(MISCREG_CR4, 0);

        tc->setMiscReg(MISCREG_RFLAGS, 0x0000000000000002ULL);

        tc->setMiscReg(MISCREG_EFER, 0);

        SegAttr dataAttr = 0;
        dataAttr.dpl = 0;
        dataAttr.unusable = 0;
        dataAttr.defaultSize = 0;
        dataAttr.longMode = 0;
        dataAttr.avl = 0;
        dataAttr.granularity = 0;
        dataAttr.present = 1;
        dataAttr.type = 3;
        dataAttr.writable = 1;
        dataAttr.readable = 1;
        dataAttr.expandDown = 0;
        dataAttr.system = 1;

        for (int seg = 0; seg != NUM_SEGMENTREGS; seg++) {
            tc->setMiscReg(MISCREG_SEG_SEL(seg), 0);
            tc->setMiscReg(MISCREG_SEG_BASE(seg), 0);
            tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), 0);
            tc->setMiscReg(MISCREG_SEG_LIMIT(seg), 0xffff);
            tc->setMiscReg(MISCREG_SEG_ATTR(seg), dataAttr);
        }

        SegAttr codeAttr = 0;
        codeAttr.dpl = 0;
        codeAttr.unusable = 0;
        codeAttr.defaultSize = 0;
        codeAttr.longMode = 0;
        codeAttr.avl = 0;
        codeAttr.granularity = 0;
        codeAttr.present = 1;
        codeAttr.type = 10;
        codeAttr.writable = 0;
        codeAttr.readable = 1;
        codeAttr.expandDown = 0;
        codeAttr.system = 1;

        tc->setMiscReg(MISCREG_CS, 0xf000);
        tc->setMiscReg(MISCREG_CS_BASE,
                0x00000000ffff0000ULL);
        tc->setMiscReg(MISCREG_CS_EFF_BASE,
                0x00000000ffff0000ULL);
        // This has the base value pre-added.
        tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff);
        tc->setMiscReg(MISCREG_CS_ATTR, codeAttr);

        PCState pc(0x000000000000fff0ULL + tc->readMiscReg(MISCREG_CS_BASE));
        tc->pcState(pc);

        tc->setMiscReg(MISCREG_TSG_BASE, 0);
        tc->setMiscReg(MISCREG_TSG_LIMIT, 0xffff);

        tc->setMiscReg(MISCREG_IDTR_BASE, 0);
        tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff);

        tc->setMiscReg(MISCREG_TSL, 0);
        tc->setMiscReg(MISCREG_TSL_BASE, 0);
        tc->setMiscReg(MISCREG_TSL_LIMIT, 0xffff);
        tc->setMiscReg(MISCREG_TSL_ATTR, 0);

        tc->setMiscReg(MISCREG_TR, 0);
        tc->setMiscReg(MISCREG_TR_BASE, 0);
        tc->setMiscReg(MISCREG_TR_LIMIT, 0xffff);
        tc->setMiscReg(MISCREG_TR_ATTR, 0);

        // This value should be the family/model/stepping of the processor.
        // (page 418). It should be consistent with the value from CPUID, but
        // the actual value probably doesn't matter much.
        tc->setIntReg(INTREG_RDX, 0);

        tc->setMiscReg(MISCREG_DR0, 0);
        tc->setMiscReg(MISCREG_DR1, 0);
        tc->setMiscReg(MISCREG_DR2, 0);
        tc->setMiscReg(MISCREG_DR3, 0);

        tc->setMiscReg(MISCREG_DR6, 0x00000000ffff0ff0ULL);
        tc->setMiscReg(MISCREG_DR7, 0x0000000000000400ULL);

        // Update the handy M5 Reg.
        tc->setMiscReg(MISCREG_M5_REG, 0);
        MicroPC entry = X86ISAInst::RomLabels::extern_label_initIntHalt;
        pc.upc(romMicroPC(entry));
        pc.nupc(romMicroPC(entry) + 1);
        tc->pcState(pc);
    }

    void
    StartupInterrupt::invoke(ThreadContext *tc, StaticInstPtr inst)
    {
        DPRINTF(Faults, "Startup interrupt with vector %#x.\n", vector);
        HandyM5Reg m5Reg = tc->readMiscReg(MISCREG_M5_REG);
        if (m5Reg.mode != LegacyMode || m5Reg.submode != RealMode) {
            panic("Startup IPI recived outside of real mode. "
                    "Don't know what to do. %d, %d", m5Reg.mode, m5Reg.submode);
        }

        tc->setMiscReg(MISCREG_CS, vector << 8);
        tc->setMiscReg(MISCREG_CS_BASE, vector << 12);
        tc->setMiscReg(MISCREG_CS_EFF_BASE, vector << 12);
        // This has the base value pre-added.
        tc->setMiscReg(MISCREG_CS_LIMIT, 0xffff);

        tc->pcState(tc->readMiscReg(MISCREG_CS_BASE));
    }
} // namespace X86ISA

<commit_msg>x86: Initialize the MXCSR register<commit_after>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2003-2007 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "arch/x86/generated/decoder.hh"
#include "arch/x86/faults.hh"
#include "arch/x86/isa_traits.hh"
#include "base/trace.hh"
#include "cpu/thread_context.hh"
#include "debug/Faults.hh"
#include "sim/full_system.hh"

namespace X86ISA
{
    void X86FaultBase::invoke(ThreadContext * tc, StaticInstPtr inst)
    {
        if (!FullSystem) {
            FaultBase::invoke(tc, inst);
            return;
        }

        PCState pcState = tc->pcState();
        Addr pc = pcState.pc();
        DPRINTF(Faults, "RIP %#x: vector %d: %s\n",
                pc, vector, describe());
        using namespace X86ISAInst::RomLabels;
        HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
        MicroPC entry;
        if (m5reg.mode == LongMode) {
            if (isSoft()) {
                entry = extern_label_longModeSoftInterrupt;
            } else {
                entry = extern_label_longModeInterrupt;
            }
        } else {
            entry = extern_label_legacyModeInterrupt;
        }
        tc->setIntReg(INTREG_MICRO(1), vector);
        tc->setIntReg(INTREG_MICRO(7), pc);
        if (errorCode != (uint64_t)(-1)) {
            if (m5reg.mode == LongMode) {
                entry = extern_label_longModeInterruptWithError;
            } else {
                panic("Legacy mode interrupts with error codes "
                        "aren't implementde.\n");
            }
            // Software interrupts shouldn't have error codes. If one
            // does, there would need to be microcode to set it up.
            assert(!isSoft());
            tc->setIntReg(INTREG_MICRO(15), errorCode);
        }
        pcState.upc(romMicroPC(entry));
        pcState.nupc(romMicroPC(entry) + 1);
        tc->pcState(pcState);
    }

    std::string
    X86FaultBase::describe() const
    {
        std::stringstream ss;
        ccprintf(ss, "%s", mnemonic());
        if (errorCode != (uint64_t)(-1)) {
            ccprintf(ss, "(%#x)", errorCode);
        }

        return ss.str();
    }

    void X86Trap::invoke(ThreadContext * tc, StaticInstPtr inst)
    {
        X86FaultBase::invoke(tc);
        if (!FullSystem)
            return;

        // This is the same as a fault, but it happens -after- the
        // instruction.
        PCState pc = tc->pcState();
        pc.uEnd();
    }

    void X86Abort::invoke(ThreadContext * tc, StaticInstPtr inst)
    {
        panic("Abort exception!");
    }

    void
    InvalidOpcode::invoke(ThreadContext * tc, StaticInstPtr inst)
    {
        if (FullSystem) {
            X86Fault::invoke(tc, inst);
        } else {
            panic("Unrecognized/invalid instruction executed:\n %s",
                    inst->machInst);
        }
    }

    void PageFault::invoke(ThreadContext * tc, StaticInstPtr inst)
    {
        if (FullSystem) {
            HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
            X86FaultBase::invoke(tc);
            /*
             * If something bad happens while trying to enter the page fault
             * handler, I'm pretty sure that's a double fault and then all
             * bets are off. That means it should be safe to update this
             * state now.
             */
            if (m5reg.mode == LongMode) {
                tc->setMiscReg(MISCREG_CR2, addr);
            } else {
                tc->setMiscReg(MISCREG_CR2, (uint32_t)addr);
            }
        } else {
            PageFaultErrorCode code = errorCode;
            const char *modeStr = "";
            if (code.fetch)
                modeStr = "execute";
            else if (code.write)
                modeStr = "write";
            else
                modeStr = "read";
            panic("Tried to %s unmapped address %#x.\n", modeStr, addr);
        }
    }

    std::string
    PageFault::describe() const
    {
        std::stringstream ss;
        ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr);
        return ss.str();
    }

    void
    InitInterrupt::invoke(ThreadContext *tc, StaticInstPtr inst)
    {
        DPRINTF(Faults, "Init interrupt.\n");
        // The otherwise unmodified integer registers should be set to 0.
        for (int index = 0; index < NUM_INTREGS; index++) {
            tc->setIntReg(index, 0);
        }

        CR0 cr0 = tc->readMiscReg(MISCREG_CR0);
        CR0 newCR0 = 1 << 4;
        newCR0.cd = cr0.cd;
        newCR0.nw = cr0.nw;
        tc->setMiscReg(MISCREG_CR0, newCR0);
        tc->setMiscReg(MISCREG_CR2, 0);
        tc->setMiscReg(MISCREG_CR3, 0);
        tc->setMiscReg(MISCREG_CR4, 0);

        tc->setMiscReg(MISCREG_RFLAGS, 0x0000000000000002ULL);

        tc->setMiscReg(MISCREG_EFER, 0);

        SegAttr dataAttr = 0;
        dataAttr.dpl = 0;
        dataAttr.unusable = 0;
        dataAttr.defaultSize = 0;
        dataAttr.longMode = 0;
        dataAttr.avl = 0;
        dataAttr.granularity = 0;
        dataAttr.present = 1;
        dataAttr.type = 3;
        dataAttr.writable = 1;
        dataAttr.readable = 1;
        dataAttr.expandDown = 0;
        dataAttr.system = 1;

        for (int seg = 0; seg != NUM_SEGMENTREGS; seg++) {
            tc->setMiscReg(MISCREG_SEG_SEL(seg), 0);
            tc->setMiscReg(MISCREG_SEG_BASE(seg), 0);
            tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), 0);
            tc->setMiscReg(MISCREG_SEG_LIMIT(seg), 0xffff);
            tc->setMiscReg(MISCREG_SEG_ATTR(seg), dataAttr);
        }

        SegAttr codeAttr = 0;
        codeAttr.dpl = 0;
        codeAttr.unusable = 0;
        codeAttr.defaultSize = 0;
        codeAttr.longMode = 0;
        codeAttr.avl = 0;
        codeAttr.granularity = 0;
        codeAttr.present = 1;
        codeAttr.type = 10;
        codeAttr.writable = 0;
        codeAttr.readable = 1;
        codeAttr.expandDown = 0;
        codeAttr.system = 1;

        tc->setMiscReg(MISCREG_CS, 0xf000);
        tc->setMiscReg(MISCREG_CS_BASE,
                0x00000000ffff0000ULL);
        tc->setMiscReg(MISCREG_CS_EFF_BASE,
                0x00000000ffff0000ULL);
        // This has the base value pre-added.
        tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff);
        tc->setMiscReg(MISCREG_CS_ATTR, codeAttr);

        PCState pc(0x000000000000fff0ULL + tc->readMiscReg(MISCREG_CS_BASE));
        tc->pcState(pc);

        tc->setMiscReg(MISCREG_TSG_BASE, 0);
        tc->setMiscReg(MISCREG_TSG_LIMIT, 0xffff);

        tc->setMiscReg(MISCREG_IDTR_BASE, 0);
        tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff);

        tc->setMiscReg(MISCREG_TSL, 0);
        tc->setMiscReg(MISCREG_TSL_BASE, 0);
        tc->setMiscReg(MISCREG_TSL_LIMIT, 0xffff);
        tc->setMiscReg(MISCREG_TSL_ATTR, 0);

        tc->setMiscReg(MISCREG_TR, 0);
        tc->setMiscReg(MISCREG_TR_BASE, 0);
        tc->setMiscReg(MISCREG_TR_LIMIT, 0xffff);
        tc->setMiscReg(MISCREG_TR_ATTR, 0);

        // This value should be the family/model/stepping of the processor.
        // (page 418). It should be consistent with the value from CPUID, but
        // the actual value probably doesn't matter much.
        tc->setIntReg(INTREG_RDX, 0);

        tc->setMiscReg(MISCREG_DR0, 0);
        tc->setMiscReg(MISCREG_DR1, 0);
        tc->setMiscReg(MISCREG_DR2, 0);
        tc->setMiscReg(MISCREG_DR3, 0);

        tc->setMiscReg(MISCREG_DR6, 0x00000000ffff0ff0ULL);
        tc->setMiscReg(MISCREG_DR7, 0x0000000000000400ULL);

        tc->setMiscReg(MISCREG_MXCSR, 0x1f80);

        // Update the handy M5 Reg.
        tc->setMiscReg(MISCREG_M5_REG, 0);
        MicroPC entry = X86ISAInst::RomLabels::extern_label_initIntHalt;
        pc.upc(romMicroPC(entry));
        pc.nupc(romMicroPC(entry) + 1);
        tc->pcState(pc);
    }

    void
    StartupInterrupt::invoke(ThreadContext *tc, StaticInstPtr inst)
    {
        DPRINTF(Faults, "Startup interrupt with vector %#x.\n", vector);
        HandyM5Reg m5Reg = tc->readMiscReg(MISCREG_M5_REG);
        if (m5Reg.mode != LegacyMode || m5Reg.submode != RealMode) {
            panic("Startup IPI recived outside of real mode. "
                    "Don't know what to do. %d, %d", m5Reg.mode, m5Reg.submode);
        }

        tc->setMiscReg(MISCREG_CS, vector << 8);
        tc->setMiscReg(MISCREG_CS_BASE, vector << 12);
        tc->setMiscReg(MISCREG_CS_EFF_BASE, vector << 12);
        // This has the base value pre-added.
        tc->setMiscReg(MISCREG_CS_LIMIT, 0xffff);

        tc->pcState(tc->readMiscReg(MISCREG_CS_BASE));
    }
} // namespace X86ISA

<|endoftext|>


<commit_before>namespace mant {
  class StandardParticleSwarmOptimisation2011 : public PopulationBasedOptimisationAlgorithm<double> {
    public:
      inline explicit StandardParticleSwarmOptimisation2011(
          const std::shared_ptr<OptimisationProblem<double>> optimisationProblem,
          const unsigned int populationSize) noexcept;

      inline void setNeighbourhoodProbability(
          const double neighbourhoodProbability) noexcept;

      inline void setMaximalAcceleration(
          const double maximalAcceleration) noexcept;
      inline void setMaximalLocalAttraction(
          const double maximalLocalAttraction) noexcept;
      inline void setMaximalGlobalAttraction(
          const double maximalGlobalAttraction) noexcept;

      inline void setMaximalSwarmConvergence(
          const double maximalSwarmConvergence) noexcept;

      inline std::string toString() const noexcept override;

    protected:
      double neighbourhoodProbability_;

      double maximalAcceleration_;
      double maximalLocalAttraction_;
      double maximalGlobalAttraction_;

      double maximalSwarmConvergence_;

      arma::Mat<double> particles_;
      arma::Mat<double> velocities_;

      unsigned int particleIndex_;
      arma::Col<double> particle_;

      arma::Col<unsigned int> neighbourhoodParticlesIndecies_;
      unsigned int neighbourhoodBestParticleIndex_;

      arma::Col<double> attractionCenter_;

      arma::Mat<double> localBestSolutions_;
      arma::Row<double> localBestSoftConstraintsValues_;
      arma::Row<double> localBestObjectiveValues_;

      bool randomizeTopology_;

      arma::Mat<unsigned int> topology_;

      inline void optimiseImplementation() noexcept override;

      inline void initialiseSwarm() noexcept;

      inline arma::Mat<unsigned int> getRandomNeighbourhoodTopology() noexcept;

      inline double getAcceleration() noexcept;
      inline arma::Col<double> getVelocity() noexcept;
  };

  //
  // Implementation
  //

  inline StandardParticleSwarmOptimisation2011::StandardParticleSwarmOptimisation2011(
      const std::shared_ptr<OptimisationProblem<double>> optimisationProblem,
      const unsigned int populationSize) noexcept
    : PopulationBasedOptimisationAlgorithm<double>(optimisationProblem, populationSize),
      localBestObjectiveValues_(this->populationSize_),
      randomizeTopology_(true) {
    setNeighbourhoodProbability(std::pow(1.0 - 1.0 / static_cast<double>(this->populationSize_), 3.0));
    setMaximalAcceleration(1.0 / (2.0 * std::log(2.0)));
    setMaximalLocalAttraction(0.5 + std::log(2.0));
    setMaximalGlobalAttraction(maximalLocalAttraction_);
    setMaximalSwarmConvergence(0.05); // TODO Check value within the paper
  }

  inline void StandardParticleSwarmOptimisation2011::optimiseImplementation() noexcept {
    initialiseSwarm();

    while(!this->isFinished() && !this->isTerminated()) {
      if (randomizeTopology_) {
        topology_ = getRandomNeighbourhoodTopology();
        randomizeTopology_ = false;
      }

      const arma::Col<unsigned int>& permutation = getRandomPermutation(this->populationSize_);
      for (std::size_t n = 0; n < this->populationSize_; ++n) {
        ++this->numberOfIterations_;

        particleIndex_ = permutation(n);
        particle_ = particles_.col(particleIndex_);

        neighbourhoodParticlesIndecies_ = arma::find(topology_.col(particleIndex_));
        static_cast<arma::Col<double>>(localBestObjectiveValues_.elem(neighbourhoodParticlesIndecies_)).min(neighbourhoodBestParticleIndex_);
        neighbourhoodBestParticleIndex_ = neighbourhoodParticlesIndecies_(neighbourhoodBestParticleIndex_);

        if (neighbourhoodBestParticleIndex_ == particleIndex_) {
          attractionCenter_ = (maximalLocalAttraction_ * (localBestSolutions_.col(particleIndex_) - particle_)) / 2.0;
        } else {
          attractionCenter_ = (maximalLocalAttraction_ * (localBestSolutions_.col(particleIndex_) - particle_) + maximalGlobalAttraction_ * (localBestSolutions_.col(neighbourhoodBestParticleIndex_) - particle_)) / 3.0;
        }

        arma::Col<double> velocityCandidate = maximalAcceleration_ * getAcceleration() *  velocities_.col(particleIndex_) + getVelocity() * arma::norm(attractionCenter_) + attractionCenter_;
        arma::Col<double> solutionCandidate = particle_ + velocityCandidate;

        const arma::Col<unsigned int>& belowLowerBound = arma::find(solutionCandidate < this->getLowerBounds());
        const arma::Col<unsigned int>& aboveUpperBound = arma::find(solutionCandidate > this->getUpperBounds());

        velocityCandidate.elem(belowLowerBound) *= -0.5;
        velocityCandidate.elem(aboveUpperBound) *= -0.5;

        solutionCandidate.elem(belowLowerBound) = this->getLowerBounds().elem(belowLowerBound);
        solutionCandidate.elem(aboveUpperBound) = this->getUpperBounds().elem(aboveUpperBound);

        velocities_.col(particleIndex_) = velocityCandidate;
        particles_.col(particleIndex_) = solutionCandidate;

        const double& objectiveValue = this->getObjectiveValue(solutionCandidate) + this->getSoftConstraintsValue(solutionCandidate);

        if (objectiveValue < localBestObjectiveValues_(particleIndex_)) {
          localBestObjectiveValues_(particleIndex_) = objectiveValue;
          localBestSolutions_.col(particleIndex_) = solutionCandidate;
        }

        if (objectiveValue < this->bestObjectiveValue_) {
          this->bestObjectiveValue_ = objectiveValue;
          this->bestParameter_ = solutionCandidate;
        } else {
          randomizeTopology_ = true;
        }

        if (this->isFinished() || this->isTerminated()) {
          break;
        }
      }

      if (static_cast<arma::Row<double>>(arma::stddev(particles_, 1)).max() < maximalSwarmConvergence_) {
        initialiseSwarm();
      }
    }
  }

  inline void StandardParticleSwarmOptimisation2011::initialiseSwarm() noexcept {
    particles_ = arma::randu<arma::Mat<double>>(this->numberOfDimensions_, this->populationSize_);
    particles_.each_col() %= this->getUpperBounds() - this->getLowerBounds();
    particles_.each_col() += this->getLowerBounds();

    velocities_ = arma::randu<arma::Mat<double>>(this->numberOfDimensions_, this->populationSize_);
    velocities_.each_col() %= this->getUpperBounds() - this->getLowerBounds();
    velocities_.each_col() += this->getLowerBounds();
    velocities_ -= particles_;

    localBestSolutions_ = particles_;

    for (std::size_t n = 0; n < this->populationSize_; ++n) {
      ++this->numberOfIterations_;

      arma::Col<double> localBestSolution = localBestSolutions_.col(n);
      double localBestObjectiveValue = this->getObjectiveValue(localBestSolution) + this->getSoftConstraintsValue(localBestSolution);
      localBestObjectiveValues_(n) = localBestObjectiveValue;

      if (localBestObjectiveValue < this->bestObjectiveValue_) {
        this->bestParameter_ = localBestSolution;
        this->bestObjectiveValue_ = localBestObjectiveValue;
      }

      if (this->isFinished() || this->isTerminated()) {
        break;
      }
    }

    randomizeTopology_ = true;
  }

  inline double StandardParticleSwarmOptimisation2011::getAcceleration() noexcept {
    return std::uniform_real_distribution<double>(0.0, 1.0)(Rng::getGenerator());
  }

  inline arma::Col<double> StandardParticleSwarmOptimisation2011::getVelocity() noexcept {
    return arma::normalise(arma::randn<arma::Col<double>>(this->numberOfDimensions_)) * std::uniform_real_distribution<double>(0.0, 1.0)(Rng::getGenerator());
  }

  inline arma::Mat<unsigned int> StandardParticleSwarmOptimisation2011::getRandomNeighbourhoodTopology() noexcept {
    arma::Mat<unsigned int> topology = (arma::randu<arma::Mat<double>>(this->populationSize_, this->populationSize_) <= neighbourhoodProbability_);
    topology.diag() += 1.0;

    return topology;
  }

  inline void StandardParticleSwarmOptimisation2011::setNeighbourhoodProbability(
      const double neighbourhoodProbability) noexcept {
    neighbourhoodProbability_ = neighbourhoodProbability;
  }

  inline void StandardParticleSwarmOptimisation2011::setMaximalAcceleration(
      const double maximalAcceleration) noexcept {
    maximalAcceleration_ = maximalAcceleration;
  }

  inline void StandardParticleSwarmOptimisation2011::setMaximalLocalAttraction(
      const double maximalLocalAttraction) noexcept {
    maximalLocalAttraction_ = maximalLocalAttraction;
  }

  inline void StandardParticleSwarmOptimisation2011::setMaximalGlobalAttraction(
      const double maximalGlobalAttraction) noexcept {
    maximalGlobalAttraction_ = maximalGlobalAttraction;
  }

  inline void StandardParticleSwarmOptimisation2011::setMaximalSwarmConvergence(
      const double maximalSwarmConvergence) noexcept {
    maximalSwarmConvergence_ = maximalSwarmConvergence;
  }

  inline std::string StandardParticleSwarmOptimisation2011::toString() const noexcept {
    return "StandardParticleSwarmOptimisation2011";
  }
}
<commit_msg>Added template information<commit_after>namespace mant {
  template <typename T>
  class StandardParticleSwarmOptimisation2011 : public PopulationBasedOptimisationAlgorithm<T> {
    public:
      inline explicit StandardParticleSwarmOptimisation2011(
          const std::shared_ptr<OptimisationProblem<T>> optimisationProblem,
          const unsigned int populationSize) noexcept;

      inline void setNeighbourhoodProbability(
          const T neighbourhoodProbability) noexcept;

      inline void setMaximalAcceleration(
          const T maximalAcceleration) noexcept;
      inline void setMaximalLocalAttraction(
          const T maximalLocalAttraction) noexcept;
      inline void setMaximalGlobalAttraction(
          const T maximalGlobalAttraction) noexcept;

      inline void setMaximalSwarmConvergence(
          const T maximalSwarmConvergence) noexcept;

      inline std::string toString() const noexcept override;

    protected:
      T neighbourhoodProbability_;

      T maximalAcceleration_;
      T maximalLocalAttraction_;
      T maximalGlobalAttraction_;

      T maximalSwarmConvergence_;

      arma::Mat<T> particles_;
      arma::Mat<T> velocities_;

      unsigned int particleIndex_;
      arma::Col<T> particle_;

      arma::Col<unsigned int> neighbourhoodParticlesIndecies_;
      unsigned int neighbourhoodBestParticleIndex_;

      arma::Col<T> attractionCenter_;

      arma::Mat<T> localBestSolutions_;
      arma::Row<double> localBestSoftConstraintsValues_;
      arma::Row<double> localBestObjectiveValues_;

      bool randomizeTopology_;

      arma::Mat<unsigned int> topology_;

      inline void optimiseImplementation() noexcept override;

      inline void initialiseSwarm() noexcept;

      inline arma::Mat<unsigned int> getRandomNeighbourhoodTopology() noexcept;

      inline T getAcceleration() noexcept;
      inline arma::Col<T> getVelocity() noexcept;
  };

  //
  // Implementation
  //

  template <typename T>
  inline StandardParticleSwarmOptimisation2011<T>::StandardParticleSwarmOptimisation2011(
      const std::shared_ptr<OptimisationProblem<T>> optimisationProblem,
      const unsigned int populationSize) noexcept
    : PopulationBasedOptimisationAlgorithm<T>(optimisationProblem, populationSize),
      localBestObjectiveValues_(this->populationSize_),
      randomizeTopology_(true) {
    setNeighbourhoodProbability(std::pow(1.0 - 1.0 / static_cast<T>(this->populationSize_), 3.0));
    setMaximalAcceleration(1.0 / (2.0 * std::log(2.0)));
    setMaximalLocalAttraction(0.5 + std::log(2.0));
    setMaximalGlobalAttraction(maximalLocalAttraction_);
    setMaximalSwarmConvergence(0.05); // TODO Check value within the paper
  }

  template <typename T>
  inline void StandardParticleSwarmOptimisation2011<T>::optimiseImplementation() noexcept {
    initialiseSwarm();

    while(!this->isFinished() && !this->isTerminated()) {
      if (randomizeTopology_) {
        topology_ = getRandomNeighbourhoodTopology();
        randomizeTopology_ = false;
      }

      const arma::Col<unsigned int>& permutation = getRandomPermutation(this->populationSize_);
      for (std::size_t n = 0; n < this->populationSize_; ++n) {
        ++this->numberOfIterations_;

        particleIndex_ = permutation(n);
        particle_ = particles_.col(particleIndex_);

        neighbourhoodParticlesIndecies_ = arma::find(topology_.col(particleIndex_));
        static_cast<arma::Col<T>>(localBestObjectiveValues_.elem(neighbourhoodParticlesIndecies_)).min(neighbourhoodBestParticleIndex_);
        neighbourhoodBestParticleIndex_ = neighbourhoodParticlesIndecies_(neighbourhoodBestParticleIndex_);

        if (neighbourhoodBestParticleIndex_ == particleIndex_) {
          attractionCenter_ = (maximalLocalAttraction_ * (localBestSolutions_.col(particleIndex_) - particle_)) / 2.0;
        } else {
          attractionCenter_ = (maximalLocalAttraction_ * (localBestSolutions_.col(particleIndex_) - particle_) + maximalGlobalAttraction_ * (localBestSolutions_.col(neighbourhoodBestParticleIndex_) - particle_)) / 3.0;
        }

        arma::Col<T> velocityCandidate = maximalAcceleration_ * getAcceleration() *  velocities_.col(particleIndex_) + getVelocity() * arma::norm(attractionCenter_) + attractionCenter_;
        arma::Col<T> solutionCandidate = particle_ + velocityCandidate;

        const arma::Col<unsigned int>& belowLowerBound = arma::find(solutionCandidate < this->getLowerBounds());
        const arma::Col<unsigned int>& aboveUpperBound = arma::find(solutionCandidate > this->getUpperBounds());

        velocityCandidate.elem(belowLowerBound) *= -0.5;
        velocityCandidate.elem(aboveUpperBound) *= -0.5;

        solutionCandidate.elem(belowLowerBound) = this->getLowerBounds().elem(belowLowerBound);
        solutionCandidate.elem(aboveUpperBound) = this->getUpperBounds().elem(aboveUpperBound);

        velocities_.col(particleIndex_) = velocityCandidate;
        particles_.col(particleIndex_) = solutionCandidate;

        const double& objectiveValue = this->getObjectiveValue(solutionCandidate) + this->getSoftConstraintsValue(solutionCandidate);

        if (objectiveValue < localBestObjectiveValues_(particleIndex_)) {
          localBestObjectiveValues_(particleIndex_) = objectiveValue;
          localBestSolutions_.col(particleIndex_) = solutionCandidate;
        }

        if (objectiveValue < this->bestObjectiveValue_) {
          this->bestObjectiveValue_ = objectiveValue;
          this->bestParameter_ = solutionCandidate;
        } else {
          randomizeTopology_ = true;
        }

        if (this->isFinished() || this->isTerminated()) {
          break;
        }
      }

      if (static_cast<arma::Row<T>>(arma::stddev(particles_, 1)).max() < maximalSwarmConvergence_) {
        initialiseSwarm();
      }
    }
  }

  template <typename T>
  inline void StandardParticleSwarmOptimisation2011<T>::initialiseSwarm() noexcept {
    particles_ = arma::randu<arma::Mat<T>>(this->numberOfDimensions_, this->populationSize_);
    particles_.each_col() %= this->getUpperBounds() - this->getLowerBounds();
    particles_.each_col() += this->getLowerBounds();

    velocities_ = arma::randu<arma::Mat<T>>(this->numberOfDimensions_, this->populationSize_);
    velocities_.each_col() %= this->getUpperBounds() - this->getLowerBounds();
    velocities_.each_col() += this->getLowerBounds();
    velocities_ -= particles_;

    localBestSolutions_ = particles_;

    for (std::size_t n = 0; n < this->populationSize_; ++n) {
      ++this->numberOfIterations_;

      arma::Col<double> localBestSolution = localBestSolutions_.col(n);
      double localBestObjectiveValue = this->getObjectiveValue(localBestSolution) + this->getSoftConstraintsValue(localBestSolution);
      localBestObjectiveValues_(n) = localBestObjectiveValue;

      if (localBestObjectiveValue < this->bestObjectiveValue_) {
        this->bestParameter_ = localBestSolution;
        this->bestObjectiveValue_ = localBestObjectiveValue;
      }

      if (this->isFinished() || this->isTerminated()) {
        break;
      }
    }

    randomizeTopology_ = true;
  }

  template <typename T>
  inline T StandardParticleSwarmOptimisation2011<T>::getAcceleration() noexcept {
    return std::uniform_real_distribution<T>(0.0, 1.0)(Rng::getGenerator());
  }

  template <typename T>
  inline arma::Col<T> StandardParticleSwarmOptimisation2011<T>::getVelocity() noexcept {
    return arma::normalise(arma::randn<arma::Col<T>>(this->numberOfDimensions_)) * std::uniform_real_distribution<T>(0.0, 1.0)(Rng::getGenerator());
  }

  template <typename T>
  inline arma::Mat<unsigned int> StandardParticleSwarmOptimisation2011<T>::getRandomNeighbourhoodTopology() noexcept {
    arma::Mat<unsigned int> topology = (arma::randu<arma::Mat<T>>(this->populationSize_, this->populationSize_) <= neighbourhoodProbability_);
    topology.diag() += 1.0;

    return topology;
  }

  template <typename T>
  inline void StandardParticleSwarmOptimisation2011<T>::setNeighbourhoodProbability(
      const T neighbourhoodProbability) noexcept {
    neighbourhoodProbability_ = neighbourhoodProbability;
  }

  template <typename T>
  inline void StandardParticleSwarmOptimisation2011<T>::setMaximalAcceleration(
      const T maximalAcceleration) noexcept {
    maximalAcceleration_ = maximalAcceleration;
  }

  template <typename T>
  inline void StandardParticleSwarmOptimisation2011<T>::setMaximalLocalAttraction(
      const T maximalLocalAttraction) noexcept {
    maximalLocalAttraction_ = maximalLocalAttraction;
  }

  template <typename T>
  inline void StandardParticleSwarmOptimisation2011<T>::setMaximalGlobalAttraction(
      const T maximalGlobalAttraction) noexcept {
    maximalGlobalAttraction_ = maximalGlobalAttraction;
  }

  template <typename T>
  inline void StandardParticleSwarmOptimisation2011<T>::setMaximalSwarmConvergence(
      const T maximalSwarmConvergence) noexcept {
    maximalSwarmConvergence_ = maximalSwarmConvergence;
  }

  template <typename T>
  inline std::string StandardParticleSwarmOptimisation2011<T>::toString() const noexcept {
    return "StandardParticleSwarmOptimisation2011";
  }
}
<|endoftext|>


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

#include "perfetto/ext/base/file_utils.h"

#include <sys/stat.h>
#include <sys/types.h>

#include <algorithm>
#include <deque>
#include <string>
#include <vector>

#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/platform_handle.h"
#include "perfetto/base/status.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/utils.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <Windows.h>
#include <direct.h>
#include <io.h>
#else
#include <dirent.h>
#include <unistd.h>
#endif

namespace perfetto {
namespace base {
namespace {
constexpr size_t kBufSize = 2048;

#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
// Wrap FindClose to: (1) make the return unix-style; (2) deal with stdcall.
int CloseFindHandle(HANDLE h) {
  return FindClose(h) ? 0 : -1;
};
#endif

}  // namespace

ssize_t Read(int fd, void* dst, size_t dst_size) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return _read(fd, dst, static_cast<unsigned>(dst_size));
#else
  return PERFETTO_EINTR(read(fd, dst, dst_size));
#endif
}

bool ReadFileDescriptor(int fd, std::string* out) {
  // Do not override existing data in string.
  size_t i = out->size();

  struct stat buf {};
  if (fstat(fd, &buf) != -1) {
    if (buf.st_size > 0)
      out->resize(i + static_cast<size_t>(buf.st_size));
  }

  ssize_t bytes_read;
  for (;;) {
    if (out->size() < i + kBufSize)
      out->resize(out->size() + kBufSize);

    bytes_read = Read(fd, &((*out)[i]), kBufSize);
    if (bytes_read > 0) {
      i += static_cast<size_t>(bytes_read);
    } else {
      out->resize(i);
      return bytes_read == 0;
    }
  }
}

bool ReadPlatformHandle(PlatformHandle h, std::string* out) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // Do not override existing data in string.
  size_t i = out->size();

  for (;;) {
    if (out->size() < i + kBufSize)
      out->resize(out->size() + kBufSize);
    DWORD bytes_read = 0;
    auto res = ::ReadFile(h, &((*out)[i]), kBufSize, &bytes_read, nullptr);
    if (res && bytes_read > 0) {
      i += static_cast<size_t>(bytes_read);
    } else {
      out->resize(i);
      const bool is_eof = res && bytes_read == 0;
      auto err = res ? 0 : GetLastError();
      // The "Broken pipe" error on Windows is slighly different than Unix:
      // On Unix: a "broken pipe" error can happen only on the writer side. On
      // the reader there is no broken pipe, just a EOF.
      // On windows: the reader also sees a broken pipe error.
      // Here we normalize on the Unix behavior, treating broken pipe as EOF.
      return is_eof || err == ERROR_BROKEN_PIPE;
    }
  }
#else
  return ReadFileDescriptor(h, out);
#endif
}

bool ReadFileStream(FILE* f, std::string* out) {
  return ReadFileDescriptor(fileno(f), out);
}

bool ReadFile(const std::string& path, std::string* out) {
  base::ScopedFile fd = base::OpenFile(path, O_RDONLY);
  if (!fd)
    return false;

  return ReadFileDescriptor(*fd, out);
}

ssize_t WriteAll(int fd, const void* buf, size_t count) {
  size_t written = 0;
  while (written < count) {
    // write() on windows takes an unsigned int size.
    uint32_t bytes_left = static_cast<uint32_t>(
        std::min(count - written, static_cast<size_t>(UINT32_MAX)));
    ssize_t wr = PERFETTO_EINTR(
        write(fd, static_cast<const char*>(buf) + written, bytes_left));
    if (wr == 0)
      break;
    if (wr < 0)
      return wr;
    written += static_cast<size_t>(wr);
  }
  return static_cast<ssize_t>(written);
}

ssize_t WriteAllHandle(PlatformHandle h, const void* buf, size_t count) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  DWORD wsize = 0;
  if (::WriteFile(h, buf, static_cast<DWORD>(count), &wsize, nullptr)) {
    return wsize;
  } else {
    return -1;
  }
#else
  return WriteAll(h, buf, count);
#endif
}

bool FlushFile(int fd) {
  PERFETTO_DCHECK(fd != 0);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  return !PERFETTO_EINTR(fdatasync(fd));
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return !PERFETTO_EINTR(_commit(fd));
#else
  return !PERFETTO_EINTR(fsync(fd));
#endif
}

bool Mkdir(const std::string& path) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return _mkdir(path.c_str()) == 0;
#else
  return mkdir(path.c_str(), 0755) == 0;
#endif
}

bool Rmdir(const std::string& path) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return _rmdir(path.c_str()) == 0;
#else
  return rmdir(path.c_str()) == 0;
#endif
}

int CloseFile(int fd) {
  return close(fd);
}

ScopedFile OpenFile(const std::string& path, int flags, FileOpenMode mode) {
  PERFETTO_DCHECK((flags & O_CREAT) == 0 || mode != kFileModeInvalid);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // Always use O_BINARY on Windows, to avoid silly EOL translations.
  ScopedFile fd(_open(path.c_str(), flags | O_BINARY, mode));
#else
  // Always open a ScopedFile with O_CLOEXEC so we can safely fork and exec.
  ScopedFile fd(open(path.c_str(), flags | O_CLOEXEC, mode));
#endif
  return fd;
}

bool FileExists(const std::string& path) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return _access(path.c_str(), 0) == 0;
#else
  return access(path.c_str(), F_OK) == 0;
#endif
}

// Declared in base/platform_handle.h.
int ClosePlatformHandle(PlatformHandle handle) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // Make the return value UNIX-style.
  return CloseHandle(handle) ? 0 : -1;
#else
  return close(handle);
#endif
}

base::Status ListFilesRecursive(const std::string& dir_path,
                                std::vector<std::string>& output) {
  std::string root_dir_path = dir_path;
  if (root_dir_path.back() == '\\') {
    root_dir_path.back() = '/';
  } else if (root_dir_path.back() != '/') {
    root_dir_path.push_back('/');
  }

  // dir_queue contains full paths to the directories. The paths include the
  // root_dir_path at the beginning and the trailing slash at the end.
  std::deque<std::string> dir_queue;
  dir_queue.push_back(root_dir_path);

  while (!dir_queue.empty()) {
    const std::string cur_dir = std::move(dir_queue.front());
    dir_queue.pop_front();
#if PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
    return base::ErrStatus("ListFilesRecursive not supported yet");
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
    std::string glob_path = cur_dir + "*";
    // + 1 because we also have to count the NULL terminator.
    if (glob_path.length() + 1 > MAX_PATH)
      return base::ErrStatus("Directory path %s is too long", dir_path.c_str());
    WIN32_FIND_DATAA ffd;

    base::ScopedResource<HANDLE, CloseFindHandle, nullptr, false,
                         base::PlatformHandleChecker>
        hFind(FindFirstFileA(glob_path.c_str(), &ffd));
    if (!hFind) {
      // For empty directories, there should be at least one entry '.'.
      // If FindFirstFileA returns INVALID_HANDLE_VALUE, this means directory
      // couldn't be accessed.
      return base::ErrStatus("Failed to open directory %s", cur_dir.c_str());
    }
    do {
      if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0)
        continue;
      if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
        std::string subdir_path = cur_dir + ffd.cFileName + '/';
        dir_queue.push_back(subdir_path);
      } else {
        const std::string full_path = cur_dir + ffd.cFileName;
        PERFETTO_CHECK(full_path.length() > root_dir_path.length());
        output.push_back(full_path.substr(root_dir_path.length()));
      }
    } while (FindNextFileA(*hFind, &ffd));
#else
    ScopedDir dir = ScopedDir(opendir(cur_dir.c_str()));
    if (!dir) {
      return base::ErrStatus("Failed to open directory %s", cur_dir.c_str());
    }
    for (auto* dirent = readdir(dir.get()); dirent != nullptr;
         dirent = readdir(dir.get())) {
      if (strcmp(dirent->d_name, ".") == 0 ||
          strcmp(dirent->d_name, "..") == 0) {
        continue;
      }
      if (dirent->d_type == DT_DIR) {
        dir_queue.push_back(cur_dir + dirent->d_name + '/');
      } else if (dirent->d_type == DT_REG) {
        const std::string full_path = cur_dir + dirent->d_name;
        PERFETTO_CHECK(full_path.length() > root_dir_path.length());
        output.push_back(full_path.substr(root_dir_path.length()));
      }
    }
#endif
  }
  return base::OkStatus();
}

std::string GetFileExtension(const std::string& filename) {
  auto ext_idx = filename.rfind('.');
  if (ext_idx == std::string::npos)
    return std::string();
  return filename.substr(ext_idx);
}

base::Optional<size_t> GetFileSize(const std::string& file_path) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  HANDLE file =
      CreateFileA(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  if (file == INVALID_HANDLE_VALUE) {
    return nullopt;
  }
  LARGE_INTEGER file_size;
  file_size.QuadPart = 0;
  BOOL ok = GetFileSizeEx(file, &file_size);
  CloseHandle(file);
  if (!ok) {
    return nullopt;
  }
  return static_cast<size_t>(file_size.QuadPart);
#else
  base::ScopedFile fd(base::OpenFile(file_path, O_RDONLY | O_CLOEXEC));
  if (!fd) {
    return nullopt;
  }
  struct stat buf{};
  if (fstat(*fd, &buf) == -1) {
    return nullopt;
  }
  return static_cast<size_t>(buf.st_size);
#endif
}

}  // namespace base
}  // namespace perfetto
<commit_msg>Fix chromium windows build am: d21ed9d314 am: a73d9a39da am: 2b5bba496b am: ebb9ca236d<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "perfetto/ext/base/file_utils.h"

#include <sys/stat.h>
#include <sys/types.h>

#include <algorithm>
#include <deque>
#include <string>
#include <vector>

#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/platform_handle.h"
#include "perfetto/base/status.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/utils.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <Windows.h>
#include <direct.h>
#include <io.h>
#else
#include <dirent.h>
#include <unistd.h>
#endif

namespace perfetto {
namespace base {
namespace {
constexpr size_t kBufSize = 2048;

#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
// Wrap FindClose to: (1) make the return unix-style; (2) deal with stdcall.
int CloseFindHandle(HANDLE h) {
  return FindClose(h) ? 0 : -1;
}
#endif

}  // namespace

ssize_t Read(int fd, void* dst, size_t dst_size) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return _read(fd, dst, static_cast<unsigned>(dst_size));
#else
  return PERFETTO_EINTR(read(fd, dst, dst_size));
#endif
}

bool ReadFileDescriptor(int fd, std::string* out) {
  // Do not override existing data in string.
  size_t i = out->size();

  struct stat buf {};
  if (fstat(fd, &buf) != -1) {
    if (buf.st_size > 0)
      out->resize(i + static_cast<size_t>(buf.st_size));
  }

  ssize_t bytes_read;
  for (;;) {
    if (out->size() < i + kBufSize)
      out->resize(out->size() + kBufSize);

    bytes_read = Read(fd, &((*out)[i]), kBufSize);
    if (bytes_read > 0) {
      i += static_cast<size_t>(bytes_read);
    } else {
      out->resize(i);
      return bytes_read == 0;
    }
  }
}

bool ReadPlatformHandle(PlatformHandle h, std::string* out) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // Do not override existing data in string.
  size_t i = out->size();

  for (;;) {
    if (out->size() < i + kBufSize)
      out->resize(out->size() + kBufSize);
    DWORD bytes_read = 0;
    auto res = ::ReadFile(h, &((*out)[i]), kBufSize, &bytes_read, nullptr);
    if (res && bytes_read > 0) {
      i += static_cast<size_t>(bytes_read);
    } else {
      out->resize(i);
      const bool is_eof = res && bytes_read == 0;
      auto err = res ? 0 : GetLastError();
      // The "Broken pipe" error on Windows is slighly different than Unix:
      // On Unix: a "broken pipe" error can happen only on the writer side. On
      // the reader there is no broken pipe, just a EOF.
      // On windows: the reader also sees a broken pipe error.
      // Here we normalize on the Unix behavior, treating broken pipe as EOF.
      return is_eof || err == ERROR_BROKEN_PIPE;
    }
  }
#else
  return ReadFileDescriptor(h, out);
#endif
}

bool ReadFileStream(FILE* f, std::string* out) {
  return ReadFileDescriptor(fileno(f), out);
}

bool ReadFile(const std::string& path, std::string* out) {
  base::ScopedFile fd = base::OpenFile(path, O_RDONLY);
  if (!fd)
    return false;

  return ReadFileDescriptor(*fd, out);
}

ssize_t WriteAll(int fd, const void* buf, size_t count) {
  size_t written = 0;
  while (written < count) {
    // write() on windows takes an unsigned int size.
    uint32_t bytes_left = static_cast<uint32_t>(
        std::min(count - written, static_cast<size_t>(UINT32_MAX)));
    ssize_t wr = PERFETTO_EINTR(
        write(fd, static_cast<const char*>(buf) + written, bytes_left));
    if (wr == 0)
      break;
    if (wr < 0)
      return wr;
    written += static_cast<size_t>(wr);
  }
  return static_cast<ssize_t>(written);
}

ssize_t WriteAllHandle(PlatformHandle h, const void* buf, size_t count) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  DWORD wsize = 0;
  if (::WriteFile(h, buf, static_cast<DWORD>(count), &wsize, nullptr)) {
    return wsize;
  } else {
    return -1;
  }
#else
  return WriteAll(h, buf, count);
#endif
}

bool FlushFile(int fd) {
  PERFETTO_DCHECK(fd != 0);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  return !PERFETTO_EINTR(fdatasync(fd));
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return !PERFETTO_EINTR(_commit(fd));
#else
  return !PERFETTO_EINTR(fsync(fd));
#endif
}

bool Mkdir(const std::string& path) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return _mkdir(path.c_str()) == 0;
#else
  return mkdir(path.c_str(), 0755) == 0;
#endif
}

bool Rmdir(const std::string& path) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return _rmdir(path.c_str()) == 0;
#else
  return rmdir(path.c_str()) == 0;
#endif
}

int CloseFile(int fd) {
  return close(fd);
}

ScopedFile OpenFile(const std::string& path, int flags, FileOpenMode mode) {
  PERFETTO_DCHECK((flags & O_CREAT) == 0 || mode != kFileModeInvalid);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // Always use O_BINARY on Windows, to avoid silly EOL translations.
  ScopedFile fd(_open(path.c_str(), flags | O_BINARY, mode));
#else
  // Always open a ScopedFile with O_CLOEXEC so we can safely fork and exec.
  ScopedFile fd(open(path.c_str(), flags | O_CLOEXEC, mode));
#endif
  return fd;
}

bool FileExists(const std::string& path) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return _access(path.c_str(), 0) == 0;
#else
  return access(path.c_str(), F_OK) == 0;
#endif
}

// Declared in base/platform_handle.h.
int ClosePlatformHandle(PlatformHandle handle) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // Make the return value UNIX-style.
  return CloseHandle(handle) ? 0 : -1;
#else
  return close(handle);
#endif
}

base::Status ListFilesRecursive(const std::string& dir_path,
                                std::vector<std::string>& output) {
  std::string root_dir_path = dir_path;
  if (root_dir_path.back() == '\\') {
    root_dir_path.back() = '/';
  } else if (root_dir_path.back() != '/') {
    root_dir_path.push_back('/');
  }

  // dir_queue contains full paths to the directories. The paths include the
  // root_dir_path at the beginning and the trailing slash at the end.
  std::deque<std::string> dir_queue;
  dir_queue.push_back(root_dir_path);

  while (!dir_queue.empty()) {
    const std::string cur_dir = std::move(dir_queue.front());
    dir_queue.pop_front();
#if PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
    return base::ErrStatus("ListFilesRecursive not supported yet");
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
    std::string glob_path = cur_dir + "*";
    // + 1 because we also have to count the NULL terminator.
    if (glob_path.length() + 1 > MAX_PATH)
      return base::ErrStatus("Directory path %s is too long", dir_path.c_str());
    WIN32_FIND_DATAA ffd;

    base::ScopedResource<HANDLE, CloseFindHandle, nullptr, false,
                         base::PlatformHandleChecker>
        hFind(FindFirstFileA(glob_path.c_str(), &ffd));
    if (!hFind) {
      // For empty directories, there should be at least one entry '.'.
      // If FindFirstFileA returns INVALID_HANDLE_VALUE, this means directory
      // couldn't be accessed.
      return base::ErrStatus("Failed to open directory %s", cur_dir.c_str());
    }
    do {
      if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0)
        continue;
      if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
        std::string subdir_path = cur_dir + ffd.cFileName + '/';
        dir_queue.push_back(subdir_path);
      } else {
        const std::string full_path = cur_dir + ffd.cFileName;
        PERFETTO_CHECK(full_path.length() > root_dir_path.length());
        output.push_back(full_path.substr(root_dir_path.length()));
      }
    } while (FindNextFileA(*hFind, &ffd));
#else
    ScopedDir dir = ScopedDir(opendir(cur_dir.c_str()));
    if (!dir) {
      return base::ErrStatus("Failed to open directory %s", cur_dir.c_str());
    }
    for (auto* dirent = readdir(dir.get()); dirent != nullptr;
         dirent = readdir(dir.get())) {
      if (strcmp(dirent->d_name, ".") == 0 ||
          strcmp(dirent->d_name, "..") == 0) {
        continue;
      }
      if (dirent->d_type == DT_DIR) {
        dir_queue.push_back(cur_dir + dirent->d_name + '/');
      } else if (dirent->d_type == DT_REG) {
        const std::string full_path = cur_dir + dirent->d_name;
        PERFETTO_CHECK(full_path.length() > root_dir_path.length());
        output.push_back(full_path.substr(root_dir_path.length()));
      }
    }
#endif
  }
  return base::OkStatus();
}

std::string GetFileExtension(const std::string& filename) {
  auto ext_idx = filename.rfind('.');
  if (ext_idx == std::string::npos)
    return std::string();
  return filename.substr(ext_idx);
}

base::Optional<size_t> GetFileSize(const std::string& file_path) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  HANDLE file =
      CreateFileA(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  if (file == INVALID_HANDLE_VALUE) {
    return nullopt;
  }
  LARGE_INTEGER file_size;
  file_size.QuadPart = 0;
  BOOL ok = GetFileSizeEx(file, &file_size);
  CloseHandle(file);
  if (!ok) {
    return nullopt;
  }
  return static_cast<size_t>(file_size.QuadPart);
#else
  base::ScopedFile fd(base::OpenFile(file_path, O_RDONLY | O_CLOEXEC));
  if (!fd) {
    return nullopt;
  }
  struct stat buf{};
  if (fstat(*fd, &buf) == -1) {
    return nullopt;
  }
  return static_cast<size_t>(buf.st_size);
#endif
}

}  // namespace base
}  // namespace perfetto
<|endoftext|>