<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2010-2012 The PECOS Development Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Version 2 GNU General
// Public License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301 USA
//
//-----------------------------------------------------------------------el-
//
// $Id$
//
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------

#include "low_mach_navier_stokes_stab_base.h"

template<class Mu, class SH, class TC>
GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::LowMachNavierStokesStabilizationBase( const std::string& physics_name,
											   const GetPot& input )
  : GRINS::LowMachNavierStokesBase<Mu,SH,TC>(physics_name,input)
{
  this->read_input_options(input);

  return;
}

template<class Mu, class SH, class TC>
GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::~LowMachNavierStokesStabilizationBase()
{
  return;
}

template<class Mu, class SH, class TC>
void GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::read_input_options( const GetPot& input )
{
  this->_C = input("Physics/"+this->_physics_name+"/tau_constant", 1 );
  this->_tau_factor = input("Physics/"+this->_physics_name+"/tau_factor", 0.5 );
  return;
}

template<class Mu, class SH, class TC>
void GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::init_context( libMesh::DiffContext &context )
{
  // First call base class
  GRINS::LowMachNavierStokesBase<Mu,SH,TC>::init_context(context);

  libMesh::FEMContext &c = libmesh_cast_ref<libMesh::FEMContext&>(context);

  // We need pressure derivatives
  c.element_fe_var[this->_p_var]->get_dphi();

  // We also need second derivatives, so initialize those.
  c.element_fe_var[this->_u_var]->get_d2phi();
  c.element_fe_var[this->_T_var]->get_d2phi();

  return;
}

template<class Mu, class SH, class TC>
libMesh::Real GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_continuity_steady( libMesh::FEMContext& c,
												   unsigned int qp ) const
{
  libMesh::Real T = c.interior_value(this->_T_var, qp);
  libMesh::RealGradient grad_T = c.interior_gradient(this->_T_var, qp);

  libMesh::RealGradient U( c.interior_value(this->_u_var, qp),
			   c.interior_value(this->_v_var, qp) );

  libMesh::RealGradient grad_u, grad_v;

  grad_u = c.interior_gradient(this->_u_var, qp);
  grad_v = c.interior_gradient(this->_v_var, qp);

  libMesh::Real divU = grad_u(0) + grad_v(1);

  if( this->_dim == 3 )
    {
      U(2) = c.interior_value(this->_w_var, qp);
      divU += (c.interior_gradient(this->_w_var, qp))(2);
    }

  return divU - (U*grad_T)/T;
}

template<class Mu, class SH, class TC>
libMesh::Real GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_continuity_transient( libMesh::FEMContext& c,
												      unsigned int qp ) const
{
  libMesh::Real T = c.fixed_interior_value(this->_T_var, qp);
  libMesh::Real T_dot = c.interior_value(this->_T_var, qp);

  libMesh::Real RC_t = -T_dot/T;

  if( this->_enable_thermo_press_calc )
    {
      libMesh::Real p0 = c.fixed_interior_value(this->_p0_var, qp);
      libMesh::Real p0_dot = c.interior_value(this->_p0_var, qp);

      RC_t += p0_dot/p0;
    }

  return RC_t;
}

template<class Mu, class SH, class TC>
libMesh::RealGradient GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_momentum_steady( libMesh::FEMContext& c,
													 unsigned int qp ) const
{
  libMesh::Real T = c.interior_value(this->_T_var, qp);

  libMesh::Real rho = this->compute_rho(T, this->get_p0_steady(c,qp) );

  libMesh::RealGradient rhoU( rho*c.interior_value(this->_u_var, qp),
			      rho*c.interior_value(this->_v_var, qp) );
  if(this->_dim == 3)
    rhoU(2) = rho*c.interior_value(this->_w_var, qp);

  libMesh::RealGradient rhoUdotGradU( rhoU*c.interior_gradient(this->_u_var, qp),
				      rhoU*c.interior_gradient(this->_v_var, qp) );
  if(this->_dim == 3)
    rhoUdotGradU(2) = rhoU*c.interior_gradient(this->_w_var, qp);

  libMesh::RealGradient grad_p = c.interior_gradient(this->_p_var, qp);

  libMesh::RealTensor hess_u = c.interior_hessian(this->_u_var, qp);
  libMesh::RealTensor hess_v = c.interior_hessian(this->_v_var, qp);

  libMesh::RealGradient divGradU( hess_u(0,0) + hess_u(1,1),
				  hess_v(0,0) + hess_v(1,1) );

  libMesh::RealGradient divGradUT( hess_u(0,0) + hess_v(0,1),
				   hess_u(1,0) + hess_v(1,1) );

  libMesh::RealGradient divdivU( hess_u(0,0) + hess_v(1,0),
				 hess_u(0,1) + hess_v(1,1) );

  if(this->_dim == 3)
    {
      libMesh::RealTensor hess_w = c.interior_hessian(this->_w_var, qp);

      divGradU(0) += hess_u(2,2);
      divGradU(1) += hess_v(2,2);
      divGradU(2) = hess_w(0,0) + hess_w(1,1) + hess_w(2,2);

      divGradUT(0) += hess_w(0,2);
      divGradUT(1) += hess_w(1,2);
      divGradUT(2) = hess_u(2,0) + hess_v(2,1) + hess_w(2,2);

      divdivU(0) += hess_w(2,0);
      divdivU(1) += hess_w(2,1);
      divdivU(2) = hess_u(0,2) + hess_v(1,2) + hess_w(2,2);
    }

  libMesh::RealGradient divT = this->_mu(T)*(divGradU + divGradUT - 2.0/3.0*divdivU);

  if( this->_mu.deriv(T) != 0.0 )
    {
      libMesh::Gradient grad_T = c.interior_gradient(this->_T_var, qp);

      libMesh::Gradient grad_u = c.interior_gradient(this->_u_var, qp);
      libMesh::Gradient grad_v = c.interior_gradient(this->_v_var, qp);

      libMesh::Gradient gradTgradu( grad_T*grad_u, grad_T*grad_v );

      libMesh::Gradient gradTgraduT( grad_T(0)*grad_u(0) + grad_T(1)*grad_u(1),
				     grad_T(0)*grad_v(0) + grad_T(1)*grad_v(1) );

      libMesh::Real divU = grad_u(0) + grad_v(1);

      libMesh::Gradient gradTdivU( grad_T(0)*divU, grad_T(1)*divU );

      if(this->_dim == 3)
	{
	  libMesh::Gradient grad_w = c.interior_gradient(this->_w_var, qp);

	  gradTgradu(2) = grad_T*grad_w;

	  gradTgraduT(0) += grad_T(2)*grad_u(2);
	  gradTgraduT(1) += grad_T(2)*grad_v(2);
	  gradTgraduT(2) = grad_T(0)*grad_w(0) + grad_T(1)*grad_w(1) + grad_T(2)*grad_w(2);

	  divU += grad_w(2);
	  gradTdivU(0) += grad_T(0)*grad_w(2);
	  gradTdivU(1) += grad_T(1)*grad_w(2);
	  gradTdivU(2) += grad_T(2)*divU;
	}

      divT += this->_mu.deriv(T)*( gradTgradu + gradTgraduT - 2.0/3.0*gradTdivU );
    }

  libMesh::RealGradient rhog( rho*this->_g(0), rho*this->_g(1) );
  if(this->_dim == 3)
    rhog(2) = rho*this->_g(2);

  return rhoUdotGradU + grad_p - divT - rhog;
}

template<class Mu, class SH, class TC>
libMesh::RealGradient GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_momentum_transient( libMesh::FEMContext& c,
													    unsigned int qp ) const
{
  libMesh::Real T = c.fixed_interior_value(this->_T_var, qp);
  libMesh::Real rho = this->compute_rho(T, this->get_p0_transient(c,qp) );

  libMesh::RealGradient u_dot( c.interior_value(this->_u_var, qp), c.interior_value(this->_v_var, qp) );

  if(this->_dim == 3)
    u_dot(2) = c.interior_value(this->_w_var, qp);

  return rho*u_dot;
}

template<class Mu, class SH, class TC>
libMesh::Real GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_energy_steady( libMesh::FEMContext& c,
											       unsigned int qp ) const
{
  libMesh::Real T = c.interior_value(this->_T_var, qp);
  libMesh::Gradient grad_T = c.interior_gradient(this->_T_var, qp);
  libMesh::Tensor hess_T = c.interior_hessian(this->_T_var, qp);

  libMesh::Real rho = this->compute_rho(T, this->get_p0_steady(c,qp) );
  libMesh::Real rho_cp = rho*this->_cp(T);

  libMesh::RealGradient rhocpU( rho_cp*c.interior_value(this->_u_var, qp),
				rho_cp*c.interior_value(this->_v_var, qp) );
  if(this->_dim == 3)
    rhocpU(2) = rho_cp*c.interior_value(this->_w_var, qp);

  return rhocpU*grad_T - this->_k.deriv(T)*(grad_T*grad_T) - this->_k(T)*(hess_T(0,0) + hess_T(1,1) + hess_T(2,2));
}

template<class Mu, class SH, class TC>
libMesh::Real GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_energy_transient( libMesh::FEMContext& c,
												  unsigned int qp ) const
{
  libMesh::Real T = c.fixed_interior_value(this->_T_var, qp);
  libMesh::Real rho = this->compute_rho(T, this->get_p0_transient(c,qp) );
  libMesh::Real rho_cp = rho*this->_cp(T);
  libMesh::Real T_dot = c.interior_value(this->_T_var, qp);

  libMesh::Real RE_t = rho_cp*T_dot;

  if( this->_enable_thermo_press_calc )
    {
      RE_t -= c.interior_value(this->_p0_var, qp);
    }

  return RE_t;
}

// Instantiate
template class GRINS::LowMachNavierStokesStabilizationBase<GRINS::ConstantViscosity,GRINS::ConstantSpecificHeat,GRINS::ConstantConductivity>;
<commit_msg>[GRINS]: Updated low Mach stabilization base class to have steady residual functions callable from the mass_residual routines (#2381).<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2010-2012 The PECOS Development Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Version 2 GNU General
// Public License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301 USA
//
//-----------------------------------------------------------------------el-
//
// $Id$
//
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------

#include "low_mach_navier_stokes_stab_base.h"

template<class Mu, class SH, class TC>
GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::LowMachNavierStokesStabilizationBase( const std::string& physics_name,
											   const GetPot& input )
  : GRINS::LowMachNavierStokesBase<Mu,SH,TC>(physics_name,input)
{
  this->read_input_options(input);

  return;
}

template<class Mu, class SH, class TC>
GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::~LowMachNavierStokesStabilizationBase()
{
  return;
}

template<class Mu, class SH, class TC>
void GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::read_input_options( const GetPot& input )
{
  this->_C = input("Physics/"+this->_physics_name+"/tau_constant", 1 );
  this->_tau_factor = input("Physics/"+this->_physics_name+"/tau_factor", 0.5 );
  return;
}

template<class Mu, class SH, class TC>
void GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::init_context( libMesh::DiffContext &context )
{
  // First call base class
  GRINS::LowMachNavierStokesBase<Mu,SH,TC>::init_context(context);

  libMesh::FEMContext &c = libmesh_cast_ref<libMesh::FEMContext&>(context);

  // We need pressure derivatives
  c.element_fe_var[this->_p_var]->get_dphi();

  // We also need second derivatives, so initialize those.
  c.element_fe_var[this->_u_var]->get_d2phi();
  c.element_fe_var[this->_T_var]->get_d2phi();

  return;
}

template<class Mu, class SH, class TC>
libMesh::Real GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_continuity_steady( libMesh::FEMContext& c,
												   unsigned int qp ) const
{
  libMesh::Real T = c.fixed_interior_value(this->_T_var, qp);
  libMesh::RealGradient grad_T = c.fixed_interior_gradient(this->_T_var, qp);

  libMesh::RealGradient U( c.fixed_interior_value(this->_u_var, qp),
			   c.fixed_interior_value(this->_v_var, qp) );

  libMesh::RealGradient grad_u, grad_v;

  grad_u = c.fixed_interior_gradient(this->_u_var, qp);
  grad_v = c.fixed_interior_gradient(this->_v_var, qp);

  libMesh::Real divU = grad_u(0) + grad_v(1);

  if( this->_dim == 3 )
    {
      U(2) = c.fixed_interior_value(this->_w_var, qp);
      divU += (c.fixed_interior_gradient(this->_w_var, qp))(2);
    }

  return divU - (U*grad_T)/T;
}

template<class Mu, class SH, class TC>
libMesh::Real GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_continuity_transient( libMesh::FEMContext& c,
												      unsigned int qp ) const
{
  libMesh::Real T = c.fixed_interior_value(this->_T_var, qp);
  libMesh::Real T_dot = c.interior_value(this->_T_var, qp);

  libMesh::Real RC_t = -T_dot/T;

  if( this->_enable_thermo_press_calc )
    {
      libMesh::Real p0 = c.fixed_interior_value(this->_p0_var, qp);
      libMesh::Real p0_dot = c.interior_value(this->_p0_var, qp);

      RC_t += p0_dot/p0;
    }

  return RC_t;
}

template<class Mu, class SH, class TC>
libMesh::RealGradient GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_momentum_steady( libMesh::FEMContext& c,
													 unsigned int qp ) const
{
  libMesh::Real T = c.fixed_interior_value(this->_T_var, qp);

  libMesh::Real rho = this->compute_rho(T, this->get_p0_transient(c,qp) );

  libMesh::RealGradient rhoU( rho*c.fixed_interior_value(this->_u_var, qp),
			      rho*c.fixed_interior_value(this->_v_var, qp) );
  if(this->_dim == 3)
    rhoU(2) = rho*c.fixed_interior_value(this->_w_var, qp);

  libMesh::RealGradient rhoUdotGradU( rhoU*c.fixed_interior_gradient(this->_u_var, qp),
				      rhoU*c.fixed_interior_gradient(this->_v_var, qp) );
  if(this->_dim == 3)
    rhoUdotGradU(2) = rhoU*c.fixed_interior_gradient(this->_w_var, qp);

  libMesh::RealGradient grad_p = c.fixed_interior_gradient(this->_p_var, qp);

  libMesh::RealTensor hess_u = c.fixed_interior_hessian(this->_u_var, qp);
  libMesh::RealTensor hess_v = c.fixed_interior_hessian(this->_v_var, qp);

  libMesh::RealGradient divGradU( hess_u(0,0) + hess_u(1,1),
				  hess_v(0,0) + hess_v(1,1) );

  libMesh::RealGradient divGradUT( hess_u(0,0) + hess_v(0,1),
				   hess_u(1,0) + hess_v(1,1) );

  libMesh::RealGradient divdivU( hess_u(0,0) + hess_v(1,0),
				 hess_u(0,1) + hess_v(1,1) );

  if(this->_dim == 3)
    {
      libMesh::RealTensor hess_w = c.fixed_interior_hessian(this->_w_var, qp);

      divGradU(0) += hess_u(2,2);
      divGradU(1) += hess_v(2,2);
      divGradU(2) = hess_w(0,0) + hess_w(1,1) + hess_w(2,2);

      divGradUT(0) += hess_w(0,2);
      divGradUT(1) += hess_w(1,2);
      divGradUT(2) = hess_u(2,0) + hess_v(2,1) + hess_w(2,2);

      divdivU(0) += hess_w(2,0);
      divdivU(1) += hess_w(2,1);
      divdivU(2) = hess_u(0,2) + hess_v(1,2) + hess_w(2,2);
    }

  libMesh::RealGradient divT = this->_mu(T)*(divGradU + divGradUT - 2.0/3.0*divdivU);

  if( this->_mu.deriv(T) != 0.0 )
    {
      libMesh::Gradient grad_T = c.fixed_interior_gradient(this->_T_var, qp);

      libMesh::Gradient grad_u = c.fixed_interior_gradient(this->_u_var, qp);
      libMesh::Gradient grad_v = c.fixed_interior_gradient(this->_v_var, qp);

      libMesh::Gradient gradTgradu( grad_T*grad_u, grad_T*grad_v );

      libMesh::Gradient gradTgraduT( grad_T(0)*grad_u(0) + grad_T(1)*grad_u(1),
				     grad_T(0)*grad_v(0) + grad_T(1)*grad_v(1) );

      libMesh::Real divU = grad_u(0) + grad_v(1);

      libMesh::Gradient gradTdivU( grad_T(0)*divU, grad_T(1)*divU );

      if(this->_dim == 3)
	{
	  libMesh::Gradient grad_w = c.fixed_interior_gradient(this->_w_var, qp);

	  gradTgradu(2) = grad_T*grad_w;

	  gradTgraduT(0) += grad_T(2)*grad_u(2);
	  gradTgraduT(1) += grad_T(2)*grad_v(2);
	  gradTgraduT(2) = grad_T(0)*grad_w(0) + grad_T(1)*grad_w(1) + grad_T(2)*grad_w(2);

	  divU += grad_w(2);
	  gradTdivU(0) += grad_T(0)*grad_w(2);
	  gradTdivU(1) += grad_T(1)*grad_w(2);
	  gradTdivU(2) += grad_T(2)*divU;
	}

      divT += this->_mu.deriv(T)*( gradTgradu + gradTgraduT - 2.0/3.0*gradTdivU );
    }

  libMesh::RealGradient rhog( rho*this->_g(0), rho*this->_g(1) );
  if(this->_dim == 3)
    rhog(2) = rho*this->_g(2);

  return rhoUdotGradU + grad_p - divT - rhog;
}

template<class Mu, class SH, class TC>
libMesh::RealGradient GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_momentum_transient( libMesh::FEMContext& c,
													    unsigned int qp ) const
{
  libMesh::Real T = c.fixed_interior_value(this->_T_var, qp);
  libMesh::Real rho = this->compute_rho(T, this->get_p0_transient(c,qp) );

  libMesh::RealGradient u_dot( c.interior_value(this->_u_var, qp), c.interior_value(this->_v_var, qp) );

  if(this->_dim == 3)
    u_dot(2) = c.interior_value(this->_w_var, qp);

  return rho*u_dot;
}

template<class Mu, class SH, class TC>
libMesh::Real GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_energy_steady( libMesh::FEMContext& c,
											       unsigned int qp ) const
{
  libMesh::Real T = c.fixed_interior_value(this->_T_var, qp);
  libMesh::Gradient grad_T = c.fixed_interior_gradient(this->_T_var, qp);
  libMesh::Tensor hess_T = c.fixed_interior_hessian(this->_T_var, qp);

  libMesh::Real rho = this->compute_rho(T, this->get_p0_transient(c,qp) );
  libMesh::Real rho_cp = rho*this->_cp(T);

  libMesh::RealGradient rhocpU( rho_cp*c.fixed_interior_value(this->_u_var, qp),
				rho_cp*c.fixed_interior_value(this->_v_var, qp) );
  if(this->_dim == 3)
    rhocpU(2) = rho_cp*c.fixed_interior_value(this->_w_var, qp);

  return rhocpU*grad_T - this->_k.deriv(T)*(grad_T*grad_T) - this->_k(T)*(hess_T(0,0) + hess_T(1,1) + hess_T(2,2));
}

template<class Mu, class SH, class TC>
libMesh::Real GRINS::LowMachNavierStokesStabilizationBase<Mu,SH,TC>::compute_res_energy_transient( libMesh::FEMContext& c,
												  unsigned int qp ) const
{
  libMesh::Real T = c.fixed_interior_value(this->_T_var, qp);
  libMesh::Real rho = this->compute_rho(T, this->get_p0_transient(c,qp) );
  libMesh::Real rho_cp = rho*this->_cp(T);
  libMesh::Real T_dot = c.interior_value(this->_T_var, qp);

  libMesh::Real RE_t = rho_cp*T_dot;

  if( this->_enable_thermo_press_calc )
    {
      RE_t -= c.interior_value(this->_p0_var, qp);
    }

  return RE_t;
}

// Instantiate
template class GRINS::LowMachNavierStokesStabilizationBase<GRINS::ConstantViscosity,GRINS::ConstantSpecificHeat,GRINS::ConstantConductivity>;
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// 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
//
//      https://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 "iree/compiler/IR/Dialect.h"
#include "iree/compiler/IR/Interpreter/LLDialect.h"
#include "iree/compiler/IR/Interpreter/LLOps.h"
#include "iree/compiler/IR/Interpreter/HLDialect.h"
#include "iree/compiler/IR/Interpreter/HLOps.h"
#include "iree/compiler/IR/Ops.h"
#include "iree/compiler/Transforms/ConversionUtils.h"
#include "iree/compiler/Utils/MemRefUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/Function.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/StandardTypes.h"
#include "mlir/IR/TypeUtilities.h"
#include "mlir/IR/Value.h"
#include "mlir/Pass/Pass.h"
#include "tensorflow/compiler/mlir/xla/ir/hlo_ops.h"

namespace mlir {
namespace iree_compiler {

namespace {

LogicalResult convertReductionOp(FuncOp entryPoint, FuncOp applyFunc,
                                 Operation *elementOp, OpBuilder &builder) {
  // Ensure that this op is pass-through and does not interact with any other
  // ops within the function.
  // TODO(b/139313439): support fused reductions.
  for (auto *operand : elementOp->getOperands()) {
    if (operand->getDefiningOp() != nullptr) {
      return elementOp->emitOpError()
             << "Fused reductions are not supported (operand not sourced from "
                "block args)";
    }
  }
  for (auto *result : elementOp->getResults()) {
    for (auto *user : result->getUsers()) {
      if (!user->isKnownTerminator()) {
        return elementOp->emitOpError() << "Fused reductions are not supported "
                                           "(result used by non-terminator)";
      }
    }
  }

  // Determine the index of the args we care about. We'll use these to match up
  // the operands of the entry point with our application.
  // Our arguments are expanded tuples like <lhs0, rhs0>, <lhs1, rhs1>, so this
  // index gets the offset * 2.
  auto &applyEntryBlock = applyFunc.getBlocks().front();
  int setIndex = std::distance(applyEntryBlock.args_begin(),
                               llvm::find(applyEntryBlock.getArguments(),
                                          elementOp->getOperand(0))) /
                 2;

  // Map to the args from the entry point.
  auto &entryPointEntryBlock = entryPoint.getBlocks().front();
  Value *srcArg = entryPointEntryBlock.getArgument(setIndex);
  Value *initArg = entryPointEntryBlock.getArgument(
      applyFunc.getNumArguments() / 2 + setIndex);
  Value *dstArg =
      entryPointEntryBlock.getArgument(applyFunc.getNumArguments() + setIndex);
  auto dstType = dstArg->getType().cast<ShapedType>();
  Type elementType = dstType.getElementType();
  auto dimensionAttr = entryPoint.getAttrOfType<IntegerAttr>(
      "iree.executable.reduction.dimension");

  Operation *expandedOp = nullptr;
  if (isa<IREEInterp::HL::AddFOp>(elementOp) ||
      isa<IREEInterp::HL::AddIOp>(elementOp)) {
    if (elementType.isa<FloatType>()) {
      expandedOp = builder.create<IREEInterp::LL::ReduceSumFOp>(
          elementOp->getLoc(), srcArg, initArg, dimensionAttr, dstArg);
    } else {
      expandedOp = builder.create<IREEInterp::LL::ReduceSumIOp>(
          elementOp->getLoc(), srcArg, initArg, dimensionAttr, dstArg);
    }
  } else if (isa<IREEInterp::HL::MinFOp>(elementOp) ||
             isa<IREEInterp::HL::MinISOp>(elementOp) ||
             isa<IREEInterp::HL::MinIUOp>(elementOp)) {
    if (elementType.isa<FloatType>()) {
      expandedOp = builder.create<IREEInterp::LL::ReduceMinFOp>(
          elementOp->getLoc(), srcArg, initArg, dimensionAttr, dstArg);
    } else {
      expandedOp = builder.create<IREEInterp::LL::ReduceMinIOp>(
          elementOp->getLoc(), srcArg, initArg, dimensionAttr, dstArg);
    }
  } else if (isa<IREEInterp::HL::MaxFOp>(elementOp) ||
             isa<IREEInterp::HL::MaxISOp>(elementOp) ||
             isa<IREEInterp::HL::MaxIUOp>(elementOp)) {
    if (elementType.isa<FloatType>()) {
      expandedOp = builder.create<IREEInterp::LL::ReduceMaxFOp>(
          elementOp->getLoc(), srcArg, initArg, dimensionAttr, dstArg);
    } else {
      expandedOp = builder.create<IREEInterp::LL::ReduceMaxIOp>(
          elementOp->getLoc(), srcArg, initArg, dimensionAttr, dstArg);
    }
  }
  if (!expandedOp) {
    return elementOp->emitOpError()
           << "No matching expanded reduction op for elemental op";
  }

  return success();
}

// Replaces the given elemental |funcOp| with a widened reduction.
LogicalResult expandReductionFunction(FuncOp entryFunc) {
  if (!entryFunc.empty()) {
    return entryFunc.emitError()
           << "Function has already been expanded or has existing contents";
  } else if (!entryFunc.getAttr("iree.executable.reduction.dimension")) {
    return entryFunc.emitError() << "Windowed reductions are not yet supported";
  }
  auto applySym =
      entryFunc.getAttrOfType<SymbolRefAttr>("iree.executable.reduction.apply");
  if (!applySym) {
    return entryFunc.emitError() << "No reduction application function defined";
  }
  auto applyFunc = entryFunc.getParentOfType<ModuleOp>().lookupSymbol<FuncOp>(
      applySym.getValue());
  if (!applyFunc) {
    return entryFunc.emitError()
           << "Unable to find apply function " << applySym;
  }

  auto *entryBlock = entryFunc.addEntryBlock();
  OpBuilder builder(entryBlock);

  if (applyFunc.getBlocks()
          .front()
          .walk([&](Operation *op) {
            if (!op->isKnownTerminator()) {
              if (failed(
                      convertReductionOp(entryFunc, applyFunc, op, builder))) {
                return WalkResult::interrupt();
              }
            }
            return WalkResult::advance();
          })
          .wasInterrupted()) {
    return applyFunc.emitError() << "Unable to convert apply func";
  }

  builder.create<IREE::ReturnOp>(builder.getUnknownLoc());

  // Remove the apply function as we have inlined it.
  applyFunc.erase();
  entryFunc.removeAttr("iree.executable.reduction.apply");
  entryFunc.removeAttr("iree.executable.reduction.dimension");

  return success();
}

// Limited lowering of reductions to fat reduce_* ops.
//
// The specific subset this supports is:
//   * 'min', 'max', and 'add' computations, with function names matching the
//      computation
//   * one op per reduction (no fusions yet).
// Note: computations and shapes are not validated.
//
// TODO(b/139410773): Implement more generally, supporting custom computations.
class ExpandReductionsToOpsPass : public ModulePass<ExpandReductionsToOpsPass> {
 public:
  void runOnModule() override {
    auto module = getModule();
    SmallVector<FuncOp, 4> reductionFuncs;
    for (auto funcOp : module.getOps<FuncOp>()) {
      if (funcOp.getAttr("iree.executable.reduction.apply")) {
        reductionFuncs.push_back(funcOp);
      }
    }
    for (auto funcOp : reductionFuncs) {
      if (failed(expandReductionFunction(funcOp))) {
        return signalPassFailure();
      }
    }
  }
};

}  // namespace

std::unique_ptr<OpPassBase<ModuleOp>> createExpandReductionsToOpsPass() {
  return std::make_unique<ExpandReductionsToOpsPass>();
}

static PassRegistration<ExpandReductionsToOpsPass> pass(
    "iree-expand-reductions-to-ops",
    "Expands IREE reduction functions to their interpreter ops");

}  // namespace iree_compiler
}  // namespace mlir
<commit_msg>Expand reductions to HL ops instead of LL ops<commit_after>// Copyright 2019 Google LLC
//
// 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
//
//      https://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 "iree/compiler/IR/Dialect.h"
#include "iree/compiler/IR/Interpreter/HLDialect.h"
#include "iree/compiler/IR/Interpreter/HLOps.h"
#include "iree/compiler/IR/Ops.h"
#include "iree/compiler/Transforms/ConversionUtils.h"
#include "iree/compiler/Utils/MemRefUtils.h"
#include "iree/compiler/Utils/OpCreationUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/Function.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/StandardTypes.h"
#include "mlir/IR/TypeUtilities.h"
#include "mlir/IR/Value.h"
#include "mlir/Pass/Pass.h"
#include "tensorflow/compiler/mlir/xla/ir/hlo_ops.h"

namespace mlir {
namespace iree_compiler {

namespace {

LogicalResult convertReductionOp(FuncOp entryPoint, FuncOp applyFunc,
                                 Operation *elementOp, OpBuilder &builder) {
  // Ensure that this op is pass-through and does not interact with any other
  // ops within the function.
  // TODO(b/139313439): support fused reductions.
  for (auto *operand : elementOp->getOperands()) {
    if (operand->getDefiningOp() != nullptr) {
      return elementOp->emitOpError()
             << "Fused reductions are not supported (operand not sourced from "
                "block args)";
    }
  }
  for (auto *result : elementOp->getResults()) {
    for (auto *user : result->getUsers()) {
      if (!user->isKnownTerminator()) {
        return elementOp->emitOpError() << "Fused reductions are not supported "
                                           "(result used by non-terminator)";
      }
    }
  }

  // Determine the index of the args we care about. We'll use these to match up
  // the operands of the entry point with our application.
  // Our arguments are expanded tuples like <lhs0, rhs0>, <lhs1, rhs1>, so this
  // index gets the offset * 2.
  auto &applyEntryBlock = applyFunc.getBlocks().front();
  int setIndex = std::distance(applyEntryBlock.args_begin(),
                               llvm::find(applyEntryBlock.getArguments(),
                                          elementOp->getOperand(0))) /
                 2;

  // Map to the args from the entry point.
  auto &entryPointEntryBlock = entryPoint.getBlocks().front();
  Value *srcArg = entryPointEntryBlock.getArgument(setIndex);
  Value *initArg = entryPointEntryBlock.getArgument(
      applyFunc.getNumArguments() / 2 + setIndex);
  Value *dstArg =
      entryPointEntryBlock.getArgument(applyFunc.getNumArguments() + setIndex);
  auto dstType = dstArg->getType().cast<ShapedType>();
  Type elementType = dstType.getElementType();
  auto loc = elementOp->getLoc();
  auto dimensionAttr = entryPoint.getAttrOfType<IntegerAttr>(
      "iree.executable.reduction.dimension");

  Operation *expandedOp = nullptr;
  if (isa<IREEInterp::HL::AddFOp>(elementOp) ||
      isa<IREEInterp::HL::AddIOp>(elementOp)) {
    if (elementType.isa<FloatType>()) {
      expandedOp = builder.create<IREEInterp::HL::ReduceSumFOp>(
          loc, dstType, srcArg, initArg, dimensionAttr);
    } else {
      expandedOp = builder.create<IREEInterp::HL::ReduceSumIOp>(
          loc, dstType, srcArg, initArg, dimensionAttr);
    }
  } else if (isa<IREEInterp::HL::MinFOp>(elementOp) ||
             isa<IREEInterp::HL::MinISOp>(elementOp) ||
             isa<IREEInterp::HL::MinIUOp>(elementOp)) {
    if (elementType.isa<FloatType>()) {
      expandedOp = builder.create<IREEInterp::HL::ReduceMinFOp>(
          loc, dstType, srcArg, initArg, dimensionAttr);
    } else {
      expandedOp = builder.create<IREEInterp::HL::ReduceMinIOp>(
          loc, dstType, srcArg, initArg, dimensionAttr);
    }
  } else if (isa<IREEInterp::HL::MaxFOp>(elementOp) ||
             isa<IREEInterp::HL::MaxISOp>(elementOp) ||
             isa<IREEInterp::HL::MaxIUOp>(elementOp)) {
    if (elementType.isa<FloatType>()) {
      expandedOp = builder.create<IREEInterp::HL::ReduceMaxFOp>(
          loc, dstType, srcArg, initArg, dimensionAttr);
    } else {
      expandedOp = builder.create<IREEInterp::HL::ReduceMaxIOp>(
          loc, dstType, srcArg, initArg, dimensionAttr);
    }
  }
  if (!expandedOp) {
    return elementOp->emitOpError()
           << "No matching expanded reduction op for elemental op";
  }
  llvm::SmallVector<int64_t, 4> zeroOffset(dstType.getRank(), 0);
  auto zeroIndices = createArrayConstant(builder, loc, zeroOffset);
  auto lengths = createArrayConstant(builder, loc, dstType.getShape());
  builder.create<IREEInterp::HL::CopyOp>(
      loc, expandedOp->getResult(0), zeroIndices, dstArg, zeroIndices, lengths);

  return success();
}

// Replaces the given elemental |funcOp| with a widened reduction.
LogicalResult expandReductionFunction(FuncOp entryFunc) {
  if (!entryFunc.empty()) {
    return entryFunc.emitError()
           << "Function has already been expanded or has existing contents";
  } else if (!entryFunc.getAttr("iree.executable.reduction.dimension")) {
    return entryFunc.emitError() << "Windowed reductions are not yet supported";
  }
  auto applySym =
      entryFunc.getAttrOfType<SymbolRefAttr>("iree.executable.reduction.apply");
  if (!applySym) {
    return entryFunc.emitError() << "No reduction application function defined";
  }
  auto applyFunc = entryFunc.getParentOfType<ModuleOp>().lookupSymbol<FuncOp>(
      applySym.getValue());
  if (!applyFunc) {
    return entryFunc.emitError()
           << "Unable to find apply function " << applySym;
  }

  auto *entryBlock = entryFunc.addEntryBlock();
  OpBuilder builder(entryBlock);

  if (applyFunc.getBlocks()
          .front()
          .walk([&](Operation *op) {
            if (!op->isKnownTerminator()) {
              if (failed(
                      convertReductionOp(entryFunc, applyFunc, op, builder))) {
                return WalkResult::interrupt();
              }
            }
            return WalkResult::advance();
          })
          .wasInterrupted()) {
    return applyFunc.emitError() << "Unable to convert apply func";
  }

  builder.create<IREE::ReturnOp>(builder.getUnknownLoc());

  // Remove the apply function as we have inlined it.
  applyFunc.erase();
  entryFunc.removeAttr("iree.executable.reduction.apply");
  entryFunc.removeAttr("iree.executable.reduction.dimension");

  return success();
}

// Limited lowering of reductions to fat reduce_* ops.
//
// The specific subset this supports is:
//   * 'min', 'max', and 'add' computations, with function names matching the
//      computation
//   * one op per reduction (no fusions yet).
// Note: computations and shapes are not validated.
//
// TODO(b/139410773): Implement more generally, supporting custom computations.
class ExpandReductionsToOpsPass : public ModulePass<ExpandReductionsToOpsPass> {
 public:
  void runOnModule() override {
    auto module = getModule();
    SmallVector<FuncOp, 4> reductionFuncs;
    for (auto funcOp : module.getOps<FuncOp>()) {
      if (funcOp.getAttr("iree.executable.reduction.apply")) {
        reductionFuncs.push_back(funcOp);
      }
    }
    for (auto funcOp : reductionFuncs) {
      if (failed(expandReductionFunction(funcOp))) {
        return signalPassFailure();
      }
    }
  }
};

}  // namespace

std::unique_ptr<OpPassBase<ModuleOp>> createExpandReductionsToOpsPass() {
  return std::make_unique<ExpandReductionsToOpsPass>();
}

static PassRegistration<ExpandReductionsToOpsPass> pass(
    "iree-expand-reductions-to-ops",
    "Expands IREE reduction functions to their interpreter ops");

}  // namespace iree_compiler
}  // namespace mlir
<|endoftext|>


<commit_before>/*  This file is part of the KDE project.

    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    Copyright (C) 2008 Matthias Kretz <kretz@kde.org>

    This library is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 2.1 or 3 of the License.

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

    You should have received a copy of the GNU Lesser General Public License
    along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"
#include "audiooutput.h"
#include "backend.h"
#include "mediaobject.h"
#include "gsthelper.h"
#include <phonon/audiooutput.h>

QT_BEGIN_NAMESPACE

namespace Phonon
{
namespace Gstreamer
{
AudioOutput::AudioOutput(Backend *backend, QObject *parent)
        : QObject(parent)
        , MediaNode(backend, AudioSink)
        , m_volumeLevel(1.0)
        , m_device(0) // ### get from backend
        , m_volumeElement(0)
        , m_audioBin(0)
        , m_audioSink(0)
        , m_conv(0)
{
    static int count = 0;
    m_name = "AudioOutput" + QString::number(count++);
    if (m_backend->isValid()) {
        m_audioBin = gst_bin_new (NULL);
        gst_object_ref (GST_OBJECT (m_audioBin));
        gst_object_sink (GST_OBJECT (m_audioBin));

        m_conv = gst_element_factory_make ("audioconvert", NULL);

        // Get category from parent
        Phonon::Category category = Phonon::NoCategory;
        if (Phonon::AudioOutput *audioOutput = qobject_cast<Phonon::AudioOutput *>(parent))
            category = audioOutput->category();

        m_audioSink = m_backend->deviceManager()->createAudioSink(category);
        m_volumeElement = gst_element_factory_make ("volume", NULL);
        GstElement *queue = gst_element_factory_make ("queue", NULL);
        GstElement *audioresample = gst_element_factory_make ("audioresample", NULL);

        if (queue && m_audioBin && m_conv && audioresample && m_audioSink && m_volumeElement) {
            gst_bin_add_many (GST_BIN (m_audioBin), queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL);

            if (gst_element_link_many (queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL)) {
                // Add ghost sink for audiobin
                GstPad *audiopad = gst_element_get_pad (queue, "sink");
                gst_element_add_pad (m_audioBin, gst_ghost_pad_new ("sink", audiopad));
                gst_object_unref (audiopad);
                m_isValid = true; // Initialization ok, accept input
            }
        }
    }
}

void AudioOutput::mediaNodeEvent(const MediaNodeEvent *event)
{
    if (!m_audioBin)
        return;

    switch (event->type()) {

    default:
        break;
    }
}

AudioOutput::~AudioOutput()
{
    if (m_audioBin) {
        gst_element_set_state (m_audioBin, GST_STATE_NULL);
        gst_object_unref (m_audioBin);
    }
}

qreal AudioOutput::volume() const
{
    return m_volumeLevel;
}

int AudioOutput::outputDevice() const
{
    return m_device;
}

void AudioOutput::setVolume(qreal newVolume)
{
    if (newVolume > 2.0 )
        newVolume = 2.0;
    else if (newVolume < 0.0)
        newVolume = 0.0;

    if (newVolume == m_volumeLevel)
        return;

    m_volumeLevel = newVolume;

    if (m_volumeElement) {
        g_object_set(G_OBJECT(m_volumeElement), "volume", newVolume, (const char*)NULL);
    }

    emit volumeChanged(newVolume);
}

bool AudioOutput::setOutputDevice(int newDevice)
{
    m_backend->logMessage(Q_FUNC_INFO + QString::number(newDevice), Backend::Info, this);
    if (newDevice == m_device)
        return true;

    if (root()) {
        root()->saveState();
        if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
            return false;
    }

    bool success = false;
    const QList<AudioDevice> deviceList = m_backend->deviceManager()->audioOutputDevices();
    if (m_audioSink &&  newDevice >= 0 && newDevice < deviceList.size()) {
        // Save previous state
        GstState oldState = GST_STATE(m_audioSink);
        const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");
        const QByteArray deviceId = deviceList.at(newDevice).gstId;
        m_device = newDevice;

        // We test if the device can be opened by checking if it can go from NULL to READY state
        gst_element_set_state(m_audioSink, GST_STATE_NULL);
        success = GstHelper::setProperty(m_audioSink, "device", deviceId);
        if (success) {
            success = (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS);
        }
        if (!success) { // Revert state
            m_backend->logMessage(Q_FUNC_INFO +
                                  QLatin1String(" Failed to change device ") +
                                  deviceId, Backend::Info, this);

            GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
            gst_element_set_state(m_audioSink, oldState);
        } else {
            m_backend->logMessage(Q_FUNC_INFO +
                                  QLatin1String(" Successfully changed device ") +
                                  deviceId, Backend::Info, this);
        }

        // Note the stopped state should not really be neccessary, but seems to be required to
        // properly reset after changing the audio state
        if (root()) {
            QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
            root()->resumeState();
        }
    }
    return success;
}

#if (PHONON_VERSION >= PHONON_VERSION_CHECK(4, 2, 0))
bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
{
    m_backend->logMessage(Q_FUNC_INFO, Backend::Info, this);
    if (!m_audioSink || !newDevice.isValid()) {
        return false;
    }
    const QVariant driver = newDevice.property("driver");
    if (!driver.isValid()) {
        return setOutputDevice(newDevice.index());
    }
    if (newDevice.index() == m_device) {
        return true;
    }

    if (root()) {
        root()->saveState();
        if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
            return false;
    }

    // Save previous state
    const GstState oldState = GST_STATE(m_audioSink);
    const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");

    const QByteArray sinkName = GstHelper::property(m_audioSink, "name");
    if (sinkName == "alsasink" || sinkName == "alsasink2") {
        if (driver.toByteArray() != "alsa") {
            return false;
        }
    }

    const QVariant deviceIdsProperty = newDevice.property("deviceIds");
    QStringList deviceIds;
    if (deviceIdsProperty.type() == QVariant::StringList) {
        deviceIds = deviceIdsProperty.toStringList();
    } else if (deviceIdsProperty.type() == QVariant::String) {
        deviceIds += deviceIdsProperty.toString();
    }

    // We test if the device can be opened by checking if it can go from NULL to READY state
    foreach (const QString &deviceId, deviceIds) {
        gst_element_set_state(m_audioSink, GST_STATE_NULL);
        if (GstHelper::setProperty(m_audioSink, "device", deviceId.toUtf8())) {
            m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
                                  deviceId + QLatin1String(") succeeded"), Backend::Info, this);
            if (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS) {
                m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
                                      deviceId + QLatin1String(" succeeded"), Backend::Info, this);
                m_device = newDevice.index();
                if (root()) {
                    QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
                    root()->resumeState();
                }
                return true;
            } else {
                m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
                                      deviceId + QLatin1String(" failed"), Backend::Info, this);
            }
        } else {
            m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
                                  deviceId + QLatin1String(") failed"), Backend::Info, this);
        }
    }
    // Revert state
    GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
    gst_element_set_state(m_audioSink, oldState);

    if (root()) {
        QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
        root()->resumeState();
    }

    return false;
}
#endif

}
} //namespace Phonon::Gstreamer

QT_END_NAMESPACE
#include "moc_audiooutput.cpp"
<commit_msg>Set the glib appname for gstreamer. This will  allow sound servers such as pulseaudio to show the application name with a volume slider.<commit_after>/*  This file is part of the KDE project.

    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    Copyright (C) 2008 Matthias Kretz <kretz@kde.org>

    This library is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 2.1 or 3 of the License.

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

    You should have received a copy of the GNU Lesser General Public License
    along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"
#include "audiooutput.h"
#include "backend.h"
#include "mediaobject.h"
#include "gsthelper.h"
#include <phonon/audiooutput.h>

QT_BEGIN_NAMESPACE

namespace Phonon
{
namespace Gstreamer
{
AudioOutput::AudioOutput(Backend *backend, QObject *parent)
        : QObject(parent)
        , MediaNode(backend, AudioSink)
        , m_volumeLevel(1.0)
        , m_device(0) // ### get from backend
        , m_volumeElement(0)
        , m_audioBin(0)
        , m_audioSink(0)
        , m_conv(0)
{
    static int count = 0;
    m_name = "AudioOutput" + QString::number(count++);
    if (m_backend->isValid()) {
        g_set_application_name(qApp->applicationName().toUtf8());
        m_audioBin = gst_bin_new (NULL);
        gst_object_ref (GST_OBJECT (m_audioBin));
        gst_object_sink (GST_OBJECT (m_audioBin));

        m_conv = gst_element_factory_make ("audioconvert", NULL);

        // Get category from parent
        Phonon::Category category = Phonon::NoCategory;
        if (Phonon::AudioOutput *audioOutput = qobject_cast<Phonon::AudioOutput *>(parent))
            category = audioOutput->category();

        m_audioSink = m_backend->deviceManager()->createAudioSink(category);
        m_volumeElement = gst_element_factory_make ("volume", NULL);
        GstElement *queue = gst_element_factory_make ("queue", NULL);
        GstElement *audioresample = gst_element_factory_make ("audioresample", NULL);

        if (queue && m_audioBin && m_conv && audioresample && m_audioSink && m_volumeElement) {
            gst_bin_add_many (GST_BIN (m_audioBin), queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL);

            if (gst_element_link_many (queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL)) {
                // Add ghost sink for audiobin
                GstPad *audiopad = gst_element_get_pad (queue, "sink");
                gst_element_add_pad (m_audioBin, gst_ghost_pad_new ("sink", audiopad));
                gst_object_unref (audiopad);
                m_isValid = true; // Initialization ok, accept input
            }
        }
    }
}

void AudioOutput::mediaNodeEvent(const MediaNodeEvent *event)
{
    if (!m_audioBin)
        return;

    switch (event->type()) {

    default:
        break;
    }
}

AudioOutput::~AudioOutput()
{
    if (m_audioBin) {
        gst_element_set_state (m_audioBin, GST_STATE_NULL);
        gst_object_unref (m_audioBin);
    }
}

qreal AudioOutput::volume() const
{
    return m_volumeLevel;
}

int AudioOutput::outputDevice() const
{
    return m_device;
}

void AudioOutput::setVolume(qreal newVolume)
{
    if (newVolume > 2.0 )
        newVolume = 2.0;
    else if (newVolume < 0.0)
        newVolume = 0.0;

    if (newVolume == m_volumeLevel)
        return;

    m_volumeLevel = newVolume;

    if (m_volumeElement) {
        g_object_set(G_OBJECT(m_volumeElement), "volume", newVolume, (const char*)NULL);
    }

    emit volumeChanged(newVolume);
}

bool AudioOutput::setOutputDevice(int newDevice)
{
    m_backend->logMessage(Q_FUNC_INFO + QString::number(newDevice), Backend::Info, this);
    if (newDevice == m_device)
        return true;

    if (root()) {
        root()->saveState();
        if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
            return false;
    }

    bool success = false;
    const QList<AudioDevice> deviceList = m_backend->deviceManager()->audioOutputDevices();
    if (m_audioSink &&  newDevice >= 0 && newDevice < deviceList.size()) {
        // Save previous state
        GstState oldState = GST_STATE(m_audioSink);
        const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");
        const QByteArray deviceId = deviceList.at(newDevice).gstId;
        m_device = newDevice;

        // We test if the device can be opened by checking if it can go from NULL to READY state
        gst_element_set_state(m_audioSink, GST_STATE_NULL);
        success = GstHelper::setProperty(m_audioSink, "device", deviceId);
        if (success) {
            success = (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS);
        }
        if (!success) { // Revert state
            m_backend->logMessage(Q_FUNC_INFO +
                                  QLatin1String(" Failed to change device ") +
                                  deviceId, Backend::Info, this);

            GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
            gst_element_set_state(m_audioSink, oldState);
        } else {
            m_backend->logMessage(Q_FUNC_INFO +
                                  QLatin1String(" Successfully changed device ") +
                                  deviceId, Backend::Info, this);
        }

        // Note the stopped state should not really be neccessary, but seems to be required to
        // properly reset after changing the audio state
        if (root()) {
            QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
            root()->resumeState();
        }
    }
    return success;
}

#if (PHONON_VERSION >= PHONON_VERSION_CHECK(4, 2, 0))
bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
{
    m_backend->logMessage(Q_FUNC_INFO, Backend::Info, this);
    if (!m_audioSink || !newDevice.isValid()) {
        return false;
    }
    const QVariant driver = newDevice.property("driver");
    if (!driver.isValid()) {
        return setOutputDevice(newDevice.index());
    }
    if (newDevice.index() == m_device) {
        return true;
    }

    if (root()) {
        root()->saveState();
        if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
            return false;
    }

    // Save previous state
    const GstState oldState = GST_STATE(m_audioSink);
    const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");

    const QByteArray sinkName = GstHelper::property(m_audioSink, "name");
    if (sinkName == "alsasink" || sinkName == "alsasink2") {
        if (driver.toByteArray() != "alsa") {
            return false;
        }
    }

    const QVariant deviceIdsProperty = newDevice.property("deviceIds");
    QStringList deviceIds;
    if (deviceIdsProperty.type() == QVariant::StringList) {
        deviceIds = deviceIdsProperty.toStringList();
    } else if (deviceIdsProperty.type() == QVariant::String) {
        deviceIds += deviceIdsProperty.toString();
    }

    // We test if the device can be opened by checking if it can go from NULL to READY state
    foreach (const QString &deviceId, deviceIds) {
        gst_element_set_state(m_audioSink, GST_STATE_NULL);
        if (GstHelper::setProperty(m_audioSink, "device", deviceId.toUtf8())) {
            m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
                                  deviceId + QLatin1String(") succeeded"), Backend::Info, this);
            if (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS) {
                m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
                                      deviceId + QLatin1String(" succeeded"), Backend::Info, this);
                m_device = newDevice.index();
                if (root()) {
                    QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
                    root()->resumeState();
                }
                return true;
            } else {
                m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
                                      deviceId + QLatin1String(" failed"), Backend::Info, this);
            }
        } else {
            m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
                                  deviceId + QLatin1String(") failed"), Backend::Info, this);
        }
    }
    // Revert state
    GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
    gst_element_set_state(m_audioSink, oldState);

    if (root()) {
        QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
        root()->resumeState();
    }

    return false;
}
#endif

}
} //namespace Phonon::Gstreamer

QT_END_NAMESPACE
#include "moc_audiooutput.cpp"
<|endoftext|>


<commit_before>// Time:  O(nlogn)
// Space: O(n)

// BIT solution. (281ms)
class Solution {
public:
   /**
     * @param A: An integer array
     * @return: Count the number of element before this element 'ai' is
     *          smaller than it and return count number array
     */
    vector<int> countOfSmallerNumberII(vector<int> &A) {
        vector<int> sorted_A(A), orderings(A.size());
        sort(sorted_A.begin(), sorted_A.end());
        for (int i = 0; i < A.size(); ++i) {
            orderings[i] =
                lower_bound(sorted_A.begin(), sorted_A.end(), A[i]) -
                sorted_A.begin();
        }
        vector<int> bit(A.size() + 1), ans(A.size());
        for (int i = 0; i < orderings.size(); ++i) {
            ans[i] = query(bit, orderings[i]);
            add(bit, orderings[i] + 1, 1);
        }
        return ans;
    }

private:
    void add(vector<int>& bit, int i, int val) {
        for (; i < bit.size(); i += lower_bit(i)) {
            bit[i] += val;
        }
    }

    int query(const vector<int>& bit, int i) {
        int sum = 0;
        for (; i > 0; i -= lower_bit(i)) {
            sum += bit[i];
        }
        return sum;
    }

    int lower_bit(int i) {
        return i & -i;
    }
};

// Time:  O(nlogn)
// Space: O(n)
// BST solution. (743ms)
class Solution2 {
public:
    class BSTreeNode {
    public:
        int val, count;
        BSTreeNode *left, *right;
        BSTreeNode(int val, int count) {
            this->val = val;
            this->count = count;
            this->left = this->right = nullptr;
        }
    };
    /**
     * @param A: An integer array
     * @return: Count the number of element before this element 'ai' is
     *          smaller than it and return count number array
     */
    vector<int> countOfSmallerNumberII(vector<int> &A) {
        vector<int> res;

        BSTreeNode *root = nullptr;

        // Insert into BST and get left count.
        for (int i = 0; i < A.size(); ++i) {
            int count = 0;
            BSTreeNode *node = new BSTreeNode(A[i], 0);
            root = insertNode(root, node);
            count = query(root, A[i]);
            res.emplace_back(count);
        }

        return res;
    }

    // Insert node into BST.
    BSTreeNode* insertNode(BSTreeNode* root, BSTreeNode* node) {
        if (root == nullptr) {
            return node;
        }
        BSTreeNode* curr = root;
        while (curr) {
            // Insert left if smaller.
            if (node->val < curr->val) {
                ++curr->count; // Increase the number of left children.
                if (curr->left != nullptr) {
                    curr = curr->left;
                } else {
                    curr->left = node;
                    break;
                }
            } else {  // Insert right if larger or equal.
                if (curr->right != nullptr) {
                    curr = curr->right;
                } else {
                    curr->right = node;
                    break;
                }
            }
        }
        return root;
    }

    // Query the smaller count of the value.
    int query(BSTreeNode* root, int val) {
        if (root == nullptr) {
            return 0;
        }
        int count = 0;
        BSTreeNode* curr = root;
        while (curr) {
            // Insert left.
            if (val < curr->val) {
                curr = curr->left;
            } else if (val > curr->val) {
                count += 1 + curr->count; // Count the number of the smaller nodes.
                curr = curr->right;
            } else {  // Equal.
                return count + curr->count;
            }
        }
        return 0;
    }
};
<commit_msg>Update count-of-smaller-number-before-itself.cpp<commit_after>// Time:  O(nlogn)
// Space: O(n)

// BIT solution. (281ms)
class Solution {
public:
   /**
     * @param A: An integer array
     * @return: Count the number of element before this element 'ai' is
     *          smaller than it and return count number array
     */
    vector<int> countOfSmallerNumberII(vector<int> &A) {
        vector<int> sorted_A(A), nth_smallest(A.size());
        sort(sorted_A.begin(), sorted_A.end());
        for (int i = 0; i < A.size(); ++i) {
            nth_smallest[i] =
                lower_bound(sorted_A.begin(), sorted_A.end(), A[i]) -
                sorted_A.begin();
        }
        vector<int> bit(A.size() + 1), ans(A.size());
        for (int i = 0; i < nth_smallest.size(); ++i) {
            ans[i] = query(bit, nth_smallest[i]);
            add(bit, nth_smallest[i] + 1, 1);
        }
        return ans;
    }

private:
    void add(vector<int>& bit, int i, int val) {
        for (; i < bit.size(); i += lower_bit(i)) {
            bit[i] += val;
        }
    }

    int query(const vector<int>& bit, int i) {
        int sum = 0;
        for (; i > 0; i -= lower_bit(i)) {
            sum += bit[i];
        }
        return sum;
    }

    int lower_bit(int i) {
        return i & -i;
    }
};

// Time:  O(nlogn)
// Space: O(n)
// BST solution. (743ms)
class Solution2 {
public:
    class BSTreeNode {
    public:
        int val, count;
        BSTreeNode *left, *right;
        BSTreeNode(int val, int count) {
            this->val = val;
            this->count = count;
            this->left = this->right = nullptr;
        }
    };
    /**
     * @param A: An integer array
     * @return: Count the number of element before this element 'ai' is
     *          smaller than it and return count number array
     */
    vector<int> countOfSmallerNumberII(vector<int> &A) {
        vector<int> res;

        BSTreeNode *root = nullptr;

        // Insert into BST and get left count.
        for (int i = 0; i < A.size(); ++i) {
            int count = 0;
            BSTreeNode *node = new BSTreeNode(A[i], 0);
            root = insertNode(root, node);
            count = query(root, A[i]);
            res.emplace_back(count);
        }

        return res;
    }

    // Insert node into BST.
    BSTreeNode* insertNode(BSTreeNode* root, BSTreeNode* node) {
        if (root == nullptr) {
            return node;
        }
        BSTreeNode* curr = root;
        while (curr) {
            // Insert left if smaller.
            if (node->val < curr->val) {
                ++curr->count; // Increase the number of left children.
                if (curr->left != nullptr) {
                    curr = curr->left;
                } else {
                    curr->left = node;
                    break;
                }
            } else {  // Insert right if larger or equal.
                if (curr->right != nullptr) {
                    curr = curr->right;
                } else {
                    curr->right = node;
                    break;
                }
            }
        }
        return root;
    }

    // Query the smaller count of the value.
    int query(BSTreeNode* root, int val) {
        if (root == nullptr) {
            return 0;
        }
        int count = 0;
        BSTreeNode* curr = root;
        while (curr) {
            // Insert left.
            if (val < curr->val) {
                curr = curr->left;
            } else if (val > curr->val) {
                count += 1 + curr->count; // Count the number of the smaller nodes.
                curr = curr->right;
            } else {  // Equal.
                return count + curr->count;
            }
        }
        return 0;
    }
};
<|endoftext|>


<commit_before>#include "test.hpp"
#include <heap.hpp>
#include <vector>
#include <string.h>
static constexpr size_t PAGE_SIZE {4096};

template<size_t ALIGNMENT = 16>
class test_ctx
{
public:
    test_ctx(size_t size) :
        ptr_raw(new char [size + ALIGNMENT]),
        ptr_align(reinterpret_cast<char *>((reinterpret_cast<size_t>(ptr_raw) + ALIGNMENT - 1) & ~(ALIGNMENT -1))),
        mem(reinterpret_cast<size_t>(ptr_align), size),
        heap(mem)
    {
    }

    ~test_ctx() { delete[] ptr_raw; }

    void *alloc(size_t size) { return heap.alloc(size); };
    void free(void *p) { heap.free(p); }

private:
    char *ptr_raw;
    char *ptr_align;
public:
    fixed_memory mem;
    first_fit_heap<ALIGNMENT> heap;

};

template<class CTX>
static bool check_alignment()
{
    CTX ctx(PAGE_SIZE);
    const size_t alignment {ctx.heap.alignment()};
    TRACE("alignment: %ld", alignment);

    void *ptr = ctx.alloc(alignment);
    size_t addr = reinterpret_cast<size_t>(ptr);

    return ((addr & (alignment - 1)) == 0);
}

template<size_t ALIGNMENT, class ON_PTR_ALLOC_FN, class ON_PTR_FREE_FN>
bool generic_alloc_and_free(ON_PTR_ALLOC_FN ptr_alloc_fn,
                            ON_PTR_FREE_FN ptr_free_fn,
                            size_t alloc_size = ALIGNMENT
                            )
{
    test_ctx<> ctx(32 * PAGE_SIZE);

    std::vector<void *> ptrs;

    size_t init_size {ctx.heap.free_mem()};
    void  *p {nullptr};

    for (unsigned pass = 0; pass < 10; pass++) {
        while((p = ctx.alloc(alloc_size))) {
            ptrs.push_back(p);
            if (TEST_FAILED == ptr_alloc_fn(p, alloc_size)) {
                return TEST_FAILED;
            }
        }

        if (ctx.heap.num_blocks() > 1) { return TEST_FAILED; }

        while (ptrs.size() > 0) {
            if (TEST_FAILED == ptr_free_fn(ptrs.back(), alloc_size)) {
                return TEST_FAILED;
            }

            ctx.free(ptrs.back());
            ptrs.pop_back();
        }

        if (ctx.heap.free_mem() != init_size) {
            return TEST_FAILED;
        }
    }

    return TEST_SUCCESS;
}

TEST_SUITE_START

TEST(zero_alloc_should_not_return_nullptr,
{
    test_ctx<> ctx(PAGE_SIZE);

    void *ptr = ctx.alloc(0);
    ASSERT(ptr != nullptr);

    return TEST_SUCCESS;
});

TEST(simple_alloc_and_free,
{
    test_ctx<> ctx(PAGE_SIZE);

    ctx.free(ctx.alloc(10));
    ASSERT(ctx.heap.num_blocks() == 1);

    return TEST_SUCCESS;
});

TEST(heap_alignment,
{
    ASSERT(check_alignment<test_ctx<16>>());
    ASSERT(check_alignment<test_ctx<32>>());
    ASSERT(check_alignment<test_ctx<64>>());
    ASSERT(check_alignment<test_ctx<128>>());
    ASSERT(check_alignment<test_ctx<256>>());
    ASSERT(check_alignment<test_ctx<1024>>());
    return TEST_SUCCESS;
});

TEST(linear_alloc_and_free,
{
    auto after_alloc = [](void *p, size_t size) {
        memset(p, 0xf, size);
        return TEST_SUCCESS;
    };

    auto before_free = [](void *p, size_t size) {
        char *ptr = reinterpret_cast<char *>(p);
        for (size_t i = 0; i < size; i++) {
            if (ptr[i] != 0xf) {
                TRACE("pointer mismatch at %zd: %c vs %c", i, ptr[i], 0xf);
                return TEST_FAILED;
            }
        }

        return TEST_SUCCESS;
    };

    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<32>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<64>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<256>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<1024>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<2048>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<4096>(after_alloc, before_free));

    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 32));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 64));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 128));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 256));

    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 31));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 60));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 129));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 277));

    return TEST_SUCCESS;
});

TEST(heap_has_valid_default_alignment,
{
    __attribute__((aligned(HEAP_MIN_ALIGNMENT))) char buffer[1024];

    fixed_memory mem(size_t(buffer), 1024);
    first_fit_heap<> heap(mem);
    ASSERT(heap.alignment() == HEAP_MIN_ALIGNMENT);
    return TEST_SUCCESS;
});

TEST_SUITE_END
<commit_msg>fix space issues<commit_after>#include "test.hpp"
#include <heap.hpp>
#include <vector>
#include <string.h>
static constexpr size_t PAGE_SIZE {4096};

template<size_t ALIGNMENT = 16>
class test_ctx
{
public:
    test_ctx(size_t size) :
        ptr_raw(new char [size + ALIGNMENT]),
        ptr_align(reinterpret_cast<char *>((reinterpret_cast<size_t>(ptr_raw) + ALIGNMENT - 1) & ~(ALIGNMENT - 1))),
        mem(reinterpret_cast<size_t>(ptr_align), size),
        heap(mem)
    {
    }

    ~test_ctx() { delete[] ptr_raw; }

    void *alloc(size_t size) { return heap.alloc(size); };
    void free(void *p) { heap.free(p); }

private:
    char *ptr_raw;
    char *ptr_align;
public:
    fixed_memory mem;
    first_fit_heap<ALIGNMENT> heap;

};

template<class CTX>
static bool check_alignment()
{
    CTX ctx(PAGE_SIZE);
    const size_t alignment {ctx.heap.alignment()};
    TRACE("alignment: %ld", alignment);

    void *ptr = ctx.alloc(alignment);
    size_t addr = reinterpret_cast<size_t>(ptr);

    return ((addr & (alignment - 1)) == 0);
}

template<size_t ALIGNMENT, class ON_PTR_ALLOC_FN, class ON_PTR_FREE_FN>
bool generic_alloc_and_free(ON_PTR_ALLOC_FN ptr_alloc_fn,
                            ON_PTR_FREE_FN ptr_free_fn,
                            size_t alloc_size = ALIGNMENT
                            )
{
    test_ctx<> ctx(32 * PAGE_SIZE);

    std::vector<void *> ptrs;

    size_t init_size {ctx.heap.free_mem()};
    void  *p {nullptr};

    for (unsigned pass = 0; pass < 10; pass++) {
        while((p = ctx.alloc(alloc_size))) {
            ptrs.push_back(p);
            if (TEST_FAILED == ptr_alloc_fn(p, alloc_size)) {
                return TEST_FAILED;
            }
        }

        if (ctx.heap.num_blocks() > 1) { return TEST_FAILED; }

        while (ptrs.size() > 0) {
            if (TEST_FAILED == ptr_free_fn(ptrs.back(), alloc_size)) {
                return TEST_FAILED;
            }

            ctx.free(ptrs.back());
            ptrs.pop_back();
        }

        if (ctx.heap.free_mem() != init_size) {
            return TEST_FAILED;
        }
    }

    return TEST_SUCCESS;
}

TEST_SUITE_START

TEST(zero_alloc_should_not_return_nullptr,
{
    test_ctx<> ctx(PAGE_SIZE);

    void *ptr = ctx.alloc(0);
    ASSERT(ptr != nullptr);

    return TEST_SUCCESS;
});

TEST(simple_alloc_and_free,
{
    test_ctx<> ctx(PAGE_SIZE);

    ctx.free(ctx.alloc(10));
    ASSERT(ctx.heap.num_blocks() == 1);

    return TEST_SUCCESS;
});

TEST(heap_alignment,
{
    ASSERT(check_alignment<test_ctx<16>>());
    ASSERT(check_alignment<test_ctx<32>>());
    ASSERT(check_alignment<test_ctx<64>>());
    ASSERT(check_alignment<test_ctx<128>>());
    ASSERT(check_alignment<test_ctx<256>>());
    ASSERT(check_alignment<test_ctx<1024>>());
    return TEST_SUCCESS;
});

TEST(linear_alloc_and_free,
{
    auto after_alloc = [](void *p, size_t size) {
        memset(p, 0xf, size);
        return TEST_SUCCESS;
    };

    auto before_free = [](void *p, size_t size) {
        char *ptr = reinterpret_cast<char *>(p);
        for (size_t i = 0; i < size; i++) {
            if (ptr[i] != 0xf) {
                TRACE("pointer mismatch at %zd: %c vs %c", i, ptr[i], 0xf);
                return TEST_FAILED;
            }
        }

        return TEST_SUCCESS;
    };

    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<32>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<64>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<256>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<1024>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<2048>(after_alloc, before_free));
    ASSERT(generic_alloc_and_free<4096>(after_alloc, before_free));

    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 32));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 64));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 128));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 256));

    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 31));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 60));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 129));
    ASSERT(generic_alloc_and_free<16>(after_alloc, before_free, 277));

    return TEST_SUCCESS;
});

TEST(heap_has_valid_default_alignment,
{
    __attribute__((aligned(HEAP_MIN_ALIGNMENT))) char buffer[1024];

    fixed_memory mem(size_t(buffer), 1024);
    first_fit_heap<> heap(mem);
    ASSERT(heap.alignment() == HEAP_MIN_ALIGNMENT);
    return TEST_SUCCESS;
});

TEST_SUITE_END
<|endoftext|>


<commit_before>#ifndef ecmdStructs_H
#define ecmdStructs_H
// Copyright **********************************************************
//
// File ecmdStructs.H
//
// IBM Confidential
// OCO Source Materials
// 9400 Licensed Internal Code
// (C) COPYRIGHT IBM CORP. 2003
//
// The source code for this program is not published or otherwise
// divested of its trade secrets, irrespective of what has been
// deposited with the U.S. Copyright Office.
//
// End Copyright ******************************************************
/**
  @file ecmdStructs.H
  @brief All the Structures required for the eCMD Capi
*/

//--------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------
#include <stdint.h>
#include <vector>  /* For STL vector */

//--------------------------------------------------------------------
//  Forward References
//--------------------------------------------------------------------

//--------------------------------------------------------------------
//  Defines
//--------------------------------------------------------------------

#define ECMD_CAPI_VERSION ".1"          ///< eCMD API Version

#define ECMD_MAX_CHIP_TYPE_LENGTH 15    ///< @see ecmdChipTarget

// Change Log *********************************************************
//
//  Flag Reason   Vers Date     Coder  Description
//  ---- -------- ---- -------- -----  -------------------------------
//                              willsj Initial Creation
//
// End Change Log *****************************************************

/**
 @brief Structure used to designate which cec object you would like the function to operate on

*/
struct ecmdChipTarget {

  char chipType[ECMD_MAX_CHIP_TYPE_LENGTH];  ///< name of chip to access

  uint32_t cage;  ///< cage that contains node with chip
  uint32_t node;  ///< node that contains chip
  uint32_t pos;   ///< position of chip within node
  uint32_t core;  ///< which core on chip to access, if chip is multi-core
  uint32_t thread; ///< which thread on chip to access, if chip is multi-threaded

  uint8_t cageLoopValid;  ///< Tell the calling function that this function operates at a cage level
  uint8_t nodeLoopValid;  ///< Tell the calling function that this function operates at a node level
  uint8_t posLoopValid;   ///< Tell the calling function that this function operates at a pos level
  uint8_t coreLoopValid;  ///< Tell the calling function that this function operates at a core level
  uint8_t threadLoopValid; ///< Tell the calling function that this function operates at a thread level
  uint8_t loopValidChecked;  ///< Flag that indicates that we have signaled to the user level how to loop
};

enum ecmdChipInterfaceType_t {
  ECMD_INTERFACE_ACCESS,
  ECMD_INTERFACE_CFAM
};

/**
 @brief Used for the ecmdQueryConfig function to return core data
*/
struct ecmdCoreData {
  uint32_t coreId;              ///< core number of this entry
  uint8_t  numProcThreads;      ///< Number of threads per core this entry supports - only valid for Processors
};

/**
 @brief Used for the ecmdQueryConfig function to return chip data
*/
struct ecmdChipData {
  char     chipType[ECMD_MAX_CHIP_TYPE_LENGTH];  ///< name of chip
  uint32_t pos;                 ///< Position of this entry
  uint8_t  numProcCores;        ///< Number of cores this entry supports - only valid for Processor compute cores
  uint32_t chipEc;              ///< EC level of this chip, usually 0-F (ec read from 'jtag' chip id)
  vector<ecmdCoreData> coreData;///< Vector of all cores requested in this chip - only valid for Processor compute cores - in numerical order by coreId
};

/**
 @brief Used for the ecmdQueryConfig function to return node data
*/
struct ecmdNodeData {
  uint32_t nodeId;                ///< Node number of this entry
  vector<ecmdChipData> chipData;  ///< Vector of all chips requested in this node - in numerical order per chip by pos
};

/**
 @brief Used for the ecmdQueryConfig function to return cage data
*/
struct ecmdCageData {
  uint32_t cageId;                ///< Cage number of this entry
  vector<ecmdNodeData> nodeData;  ///< Vector of all nodes requested in this cage - in numerical order by nodeId
};

/**
 @brief Used for the ecmdQueryFileLocation function to specify the file type you are looking for
*/
enum ecmdFileType_t {
  ECMD_FILE_SCANDEF,    ///< Scandef file type
  ECMD_FILE_SPYDEF,     ///< Spy Definition file
  ECMD_FILE_ARRAYDEF    ///< Array Definition file
};

#endif
<commit_msg>changed the typedef defines for the enum types in ecmdStructs.H<commit_after>#ifndef ecmdStructs_H
#define ecmdStructs_H
// Copyright **********************************************************
//
// File ecmdStructs.H
//
// IBM Confidential
// OCO Source Materials
// 9400 Licensed Internal Code
// (C) COPYRIGHT IBM CORP. 2003
//
// The source code for this program is not published or otherwise
// divested of its trade secrets, irrespective of what has been
// deposited with the U.S. Copyright Office.
//
// End Copyright ******************************************************
/**
  @file ecmdStructs.H
  @brief All the Structures required for the eCMD Capi
*/

//--------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------
#include <inttypes.h>
#include <vector>  /* For STL vector */

//--------------------------------------------------------------------
//  Forward References
//--------------------------------------------------------------------

//--------------------------------------------------------------------
//  Defines
//--------------------------------------------------------------------

#define ECMD_CAPI_VERSION ".1"          ///< eCMD API Version

#define ECMD_MAX_CHIP_TYPE_LENGTH 15    ///< @see ecmdChipTarget

// Change Log *********************************************************
//
//  Flag Reason   Vers Date     Coder  Description
//  ---- -------- ---- -------- -----  -------------------------------
//                              willsj Initial Creation
//
// End Change Log *****************************************************

/**
 @brief Structure used to designate which cec object you would like the function to operate on

*/
struct ecmdChipTarget {

  char chipType[ECMD_MAX_CHIP_TYPE_LENGTH];  ///< name of chip to access

  uint32_t cage;  ///< cage that contains node with chip
  uint32_t node;  ///< node that contains chip
  uint32_t pos;   ///< position of chip within node
  uint32_t core;  ///< which core on chip to access, if chip is multi-core
  uint32_t thread; ///< which thread on chip to access, if chip is multi-threaded

  uint8_t cageLoopValid;  ///< Tell the calling function that this function operates at a cage level
  uint8_t nodeLoopValid;  ///< Tell the calling function that this function operates at a node level
  uint8_t posLoopValid;   ///< Tell the calling function that this function operates at a pos level
  uint8_t coreLoopValid;  ///< Tell the calling function that this function operates at a core level
  uint8_t threadLoopValid; ///< Tell the calling function that this function operates at a thread level
  uint8_t loopValidChecked;  ///< Flag that indicates that we have signaled to the user level how to loop
};

typedef enum {
  ECMD_INTERFACE_ACCESS,
  ECMD_INTERFACE_CFAM
} ecmdChipInterfaceType_t;

/**
 @brief Used for the ecmdQueryConfig function to return core data
*/
struct ecmdCoreData {
  uint32_t coreId;              ///< core number of this entry
  uint8_t  numProcThreads;      ///< Number of threads per core this entry supports - only valid for Processors
};

/**
 @brief Used for the ecmdQueryConfig function to return chip data
*/
struct ecmdChipData {
  char     chipType[ECMD_MAX_CHIP_TYPE_LENGTH];  ///< name of chip
  uint32_t pos;                 ///< Position of this entry
  uint8_t  numProcCores;        ///< Number of cores this entry supports - only valid for Processor compute cores
  uint32_t chipEc;              ///< EC level of this chip, usually 0-F (ec read from 'jtag' chip id)
  vector<ecmdCoreData> coreData;///< Vector of all cores requested in this chip - only valid for Processor compute cores - in numerical order by coreId
};

/**
 @brief Used for the ecmdQueryConfig function to return node data
*/
struct ecmdNodeData {
  uint32_t nodeId;                ///< Node number of this entry
  vector<ecmdChipData> chipData;  ///< Vector of all chips requested in this node - in numerical order per chip by pos
};

/**
 @brief Used for the ecmdQueryConfig function to return cage data
*/
struct ecmdCageData {
  uint32_t cageId;                ///< Cage number of this entry
  vector<ecmdNodeData> nodeData;  ///< Vector of all nodes requested in this cage - in numerical order by nodeId
};

/**
 @brief Used for the ecmdQueryFileLocation function to specify the file type you are looking for
*/
typedef enum {
  ECMD_FILE_SCANDEF,    ///< Scandef file type
  ECMD_FILE_SPYDEF,     ///< Spy Definition file
  ECMD_FILE_ARRAYDEF    ///< Array Definition file
} ecmdFileType_t;

#endif
<|endoftext|>