<commit_before>#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "UNetSender.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
UNetSender::UNetSender( const std::string s_host, const ost::tpport_t port, SMInterface* smi,
						const std::string s_f, const std::string s_val, SharedMemory* ic ):
s_field(s_f),
s_fvalue(s_val),
shm(smi),
s_host(s_host),
sendpause(150),
activated(false),
dlist(100),
maxItem(0),
packetnum(1),
s_thr(0)
{

	{
		ostringstream s;
		s << "(" << s_host << ":" << port << ")";
		myname = s.str();
	}

	// определяем фильтр
//	s_field = conf->getArgParam("--udp-filter-field");
//	s_fvalue = conf->getArgParam("--udp-filter-value");
	dlog[Debug::INFO] << myname << "(init): read fileter-field='" << s_field
						<< "' filter-value='" << s_fvalue << "'" << endl;

	if( dlog.debugging(Debug::INFO) )
		dlog[Debug::INFO] << "(UNetSender): UDP set to " << s_host << ":" << port << endl;

	try
	{
		addr = s_host.c_str();
		udp = new ost::UDPBroadcast(addr,port);
	}
	catch( ost::SockException& e )
	{
		ostringstream s;
		s << e.getString() << ": " << e.getSystemErrorString() << endl;
		throw SystemError(s.str());
	}

	s_thr = new ThreadCreator<UNetSender>(this, &UNetSender::send);

	// -------------------------------
	if( shm->isLocalwork() )
	{
		readConfiguration();
		dlist.resize(maxItem);
		dlog[Debug::INFO] << myname << "(init): dlist size = " << dlist.size() << endl;
	}
	else
		ic->addReadItem( sigc::mem_fun(this,&UNetSender::readItem) );

	// выставляем поля, которые не меняются
	mypack.msg.header.nodeID = conf->getLocalNode();
	mypack.msg.header.procID = shm->ID();
}
// -----------------------------------------------------------------------------
UNetSender::~UNetSender()
{
	delete s_thr;
	delete udp;
	delete shm;
}
// -----------------------------------------------------------------------------
void UNetSender::update( UniSetTypes::ObjectId id, long value )
{
	DMap::iterator it=dlist.begin();
	for( ; it!=dlist.end(); ++it )
	{
		if( it->si.id == id )
		{
			uniset_spin_lock lock(it->val_lock);
			it->val = value;
		}
		break;
	}
}
// -----------------------------------------------------------------------------
void UNetSender::send()
{
	dlist.resize(maxItem);
	dlog[Debug::INFO] << myname << "(send): dlist size = " << dlist.size() << endl;
/*
	ost::IPV4Broadcast h = s_host.c_str();
	try
	{
		udp->setPeer(h,port);
	}
	catch( ost::SockException& e )
	{
		ostringstream s;
		s << e.getString() << ": " << e.getSystemErrorString();
		dlog[Debug::CRIT] << myname << "(poll): " << s.str() << endl;
		throw SystemError(s.str());
	}
*/
	while( activated )
	{
		try
		{
			real_send();
		}
		catch( ost::SockException& e )
		{
			cerr  << myname << "(send): " << e.getString() << endl;
		}
		catch( UniSetTypes::Exception& ex)
		{
			cerr << myname << "(send): " << ex << std::endl;
		}
		catch(...)
		{
			cerr << myname << "(send): catch ..." << std::endl;
		}

		msleep(sendpause);
	}

	cerr << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
void UNetSender::real_send()
{
	mypack.msg.header.num = packetnum++;

	if( packetnum > UniSetUDP::MaxPacketNum )
		packetnum = 1;

//	cout << "************* send header: " << mypack.msg.header << endl;
	int sz = mypack.byte_size() + sizeof(UniSetUDP::UDPHeader);
	if( !udp->isPending(ost::Socket::pendingOutput) )
		return;

	size_t ret = udp->send( (char*)&(mypack.msg),sz);
	if( ret < sz )
		dlog[Debug::CRIT] << myname << "(real_send): FAILED ret=" << ret << " < sizeof=" << sz << endl;
}
// -----------------------------------------------------------------------------
void UNetSender::start()
{
	if( !activated )
	{
		activated = true;
		s_thr->start();
	}
}
// -----------------------------------------------------------------------------
void UNetSender::readConfiguration()
{
	xmlNode* root = conf->getXMLSensorsSection();
	if(!root)
	{
		ostringstream err;
		err << myname << "(readConfiguration): not found <sensors>";
		throw SystemError(err.str());
	}

	UniXML_iterator it(root);
	if( !it.goChildren() )
	{
		std::cerr << myname << "(readConfiguration): empty <sensors>?!!" << endl;
		return;
	}

	for( ;it.getCurrent(); it.goNext() )
	{
		if( check_item(it) )
			initItem(it);
	}
}
// ------------------------------------------------------------------------------------------
bool UNetSender::check_item( UniXML_iterator& it )
{
	if( s_field.empty() )
		return true;

	// просто проверка на не пустой field
	if( s_fvalue.empty() && it.getProp(s_field).empty() )
		return false;

	// просто проверка что field = value
	if( !s_fvalue.empty() && it.getProp(s_field)!=s_fvalue )
		return false;

	return true;
}
// ------------------------------------------------------------------------------------------
bool UNetSender::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{
	if( check_item(it) )
		initItem(it);
	return true;
}
// ------------------------------------------------------------------------------------------
bool UNetSender::initItem( UniXML_iterator& it )
{
	string sname( it.getProp("name") );

	string tid = it.getProp("id");

	ObjectId sid;
	if( !tid.empty() )
	{
		sid = UniSetTypes::uni_atoi(tid);
		if( sid <= 0 )
			sid = DefaultObjectId;
	}
	else
		sid = conf->getSensorID(sname);

	if( sid == DefaultObjectId )
	{
		if( dlog )
			dlog[Debug::CRIT] << myname << "(readItem): ID not found for "
							<< sname << endl;
		return false;
	}

	UItem p;
	p.si.id = sid;
	p.si.node = conf->getLocalNode();
	mypack.addData(sid,0);
	p.pack_ind = mypack.size()-1;

	if( maxItem >= mypack.size() )
		dlist.resize(maxItem+10);

	dlist[maxItem] = p;
	maxItem++;

	if( dlog.debugging(Debug::INFO) )
		dlog[Debug::INFO] << myname << "(initItem): add " << p << endl;

	return true;
}

// ------------------------------------------------------------------------------------------
void UNetSender::initIterators()
{
	DMap::iterator it=dlist.begin();
	for( ; it!=dlist.end(); it++ )
	{
		shm->initDIterator(it->dit);
		shm->initAIterator(it->ait);
	}
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, UNetSender::UItem& p )
{
	return os 	<< " sid=" << p.si.id;
}
// -----------------------------------------------------------------------------
<commit_msg>Исправил замеченный компилятором warning.<commit_after>#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "UNetSender.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
UNetSender::UNetSender( const std::string s_host, const ost::tpport_t port, SMInterface* smi,
						const std::string s_f, const std::string s_val, SharedMemory* ic ):
s_field(s_f),
s_fvalue(s_val),
shm(smi),
s_host(s_host),
sendpause(150),
activated(false),
dlist(100),
maxItem(0),
packetnum(1),
s_thr(0)
{

	{
		ostringstream s;
		s << "(" << s_host << ":" << port << ")";
		myname = s.str();
	}

	// определяем фильтр
//	s_field = conf->getArgParam("--udp-filter-field");
//	s_fvalue = conf->getArgParam("--udp-filter-value");
	dlog[Debug::INFO] << myname << "(init): read fileter-field='" << s_field
						<< "' filter-value='" << s_fvalue << "'" << endl;

	if( dlog.debugging(Debug::INFO) )
		dlog[Debug::INFO] << "(UNetSender): UDP set to " << s_host << ":" << port << endl;

	try
	{
		addr = s_host.c_str();
		udp = new ost::UDPBroadcast(addr,port);
	}
	catch( ost::SockException& e )
	{
		ostringstream s;
		s << e.getString() << ": " << e.getSystemErrorString() << endl;
		throw SystemError(s.str());
	}

	s_thr = new ThreadCreator<UNetSender>(this, &UNetSender::send);

	// -------------------------------
	if( shm->isLocalwork() )
	{
		readConfiguration();
		dlist.resize(maxItem);
		dlog[Debug::INFO] << myname << "(init): dlist size = " << dlist.size() << endl;
	}
	else
		ic->addReadItem( sigc::mem_fun(this,&UNetSender::readItem) );

	// выставляем поля, которые не меняются
	mypack.msg.header.nodeID = conf->getLocalNode();
	mypack.msg.header.procID = shm->ID();
}
// -----------------------------------------------------------------------------
UNetSender::~UNetSender()
{
	delete s_thr;
	delete udp;
	delete shm;
}
// -----------------------------------------------------------------------------
void UNetSender::update( UniSetTypes::ObjectId id, long value )
{
	DMap::iterator it=dlist.begin();
	for( ; it!=dlist.end(); ++it )
	{
		if( it->si.id == id )
		{
			uniset_spin_lock lock(it->val_lock);
			it->val = value;
		}
		break;
	}
}
// -----------------------------------------------------------------------------
void UNetSender::send()
{
	dlist.resize(maxItem);
	dlog[Debug::INFO] << myname << "(send): dlist size = " << dlist.size() << endl;
/*
	ost::IPV4Broadcast h = s_host.c_str();
	try
	{
		udp->setPeer(h,port);
	}
	catch( ost::SockException& e )
	{
		ostringstream s;
		s << e.getString() << ": " << e.getSystemErrorString();
		dlog[Debug::CRIT] << myname << "(poll): " << s.str() << endl;
		throw SystemError(s.str());
	}
*/
	while( activated )
	{
		try
		{
			real_send();
		}
		catch( ost::SockException& e )
		{
			cerr  << myname << "(send): " << e.getString() << endl;
		}
		catch( UniSetTypes::Exception& ex)
		{
			cerr << myname << "(send): " << ex << std::endl;
		}
		catch(...)
		{
			cerr << myname << "(send): catch ..." << std::endl;
		}

		msleep(sendpause);
	}

	cerr << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
void UNetSender::real_send()
{
	mypack.msg.header.num = packetnum++;

	if( packetnum > UniSetUDP::MaxPacketNum )
		packetnum = 1;

//	cout << "************* send header: " << mypack.msg.header << endl;
	size_t sz = mypack.byte_size() + sizeof(UniSetUDP::UDPHeader);
	if( !udp->isPending(ost::Socket::pendingOutput) )
		return;

	size_t ret = udp->send( (char*)&(mypack.msg),sz);
	if( ret < sz )
		dlog[Debug::CRIT] << myname << "(real_send): FAILED ret=" << ret << " < sizeof=" << sz << endl;
}
// -----------------------------------------------------------------------------
void UNetSender::start()
{
	if( !activated )
	{
		activated = true;
		s_thr->start();
	}
}
// -----------------------------------------------------------------------------
void UNetSender::readConfiguration()
{
	xmlNode* root = conf->getXMLSensorsSection();
	if(!root)
	{
		ostringstream err;
		err << myname << "(readConfiguration): not found <sensors>";
		throw SystemError(err.str());
	}

	UniXML_iterator it(root);
	if( !it.goChildren() )
	{
		std::cerr << myname << "(readConfiguration): empty <sensors>?!!" << endl;
		return;
	}

	for( ;it.getCurrent(); it.goNext() )
	{
		if( check_item(it) )
			initItem(it);
	}
}
// ------------------------------------------------------------------------------------------
bool UNetSender::check_item( UniXML_iterator& it )
{
	if( s_field.empty() )
		return true;

	// просто проверка на не пустой field
	if( s_fvalue.empty() && it.getProp(s_field).empty() )
		return false;

	// просто проверка что field = value
	if( !s_fvalue.empty() && it.getProp(s_field)!=s_fvalue )
		return false;

	return true;
}
// ------------------------------------------------------------------------------------------
bool UNetSender::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{
	if( check_item(it) )
		initItem(it);
	return true;
}
// ------------------------------------------------------------------------------------------
bool UNetSender::initItem( UniXML_iterator& it )
{
	string sname( it.getProp("name") );

	string tid = it.getProp("id");

	ObjectId sid;
	if( !tid.empty() )
	{
		sid = UniSetTypes::uni_atoi(tid);
		if( sid <= 0 )
			sid = DefaultObjectId;
	}
	else
		sid = conf->getSensorID(sname);

	if( sid == DefaultObjectId )
	{
		if( dlog )
			dlog[Debug::CRIT] << myname << "(readItem): ID not found for "
							<< sname << endl;
		return false;
	}

	UItem p;
	p.si.id = sid;
	p.si.node = conf->getLocalNode();
	mypack.addData(sid,0);
	p.pack_ind = mypack.size()-1;

	if( maxItem >= mypack.size() )
		dlist.resize(maxItem+10);

	dlist[maxItem] = p;
	maxItem++;

	if( dlog.debugging(Debug::INFO) )
		dlog[Debug::INFO] << myname << "(initItem): add " << p << endl;

	return true;
}

// ------------------------------------------------------------------------------------------
void UNetSender::initIterators()
{
	DMap::iterator it=dlist.begin();
	for( ; it!=dlist.end(); it++ )
	{
		shm->initDIterator(it->dit);
		shm->initAIterator(it->ait);
	}
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, UNetSender::UItem& p )
{
	return os 	<< " sid=" << p.si.id;
}
// -----------------------------------------------------------------------------
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE "test_mbasin_repulsive_potential"

#ifdef BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#else
#include <boost/test/included/unit_test.hpp>
#endif

#include <mjolnir/forcefield/local/GoContactPotential.hpp>
#include <mjolnir/forcefield/local/MBasinRepulsivePotential.hpp>
#include <iomanip>

BOOST_AUTO_TEST_CASE(MBasinrepulsive)
{
    using real_type = double;
    constexpr std::size_t N = 1000;
    constexpr real_type   h = 1e-6;

    const real_type e  = 1.0;
    const real_type r0 = 5.0;

    mjolnir::GoContactPotential<real_type>       ref(e, r0);
    mjolnir::MBasinRepulsivePotential<real_type> pot(e, r0);

    {
        const real_type x_min = r0 * 4.0 / 6.0;
        const real_type x_max = r0 * std::sqrt(5.0 / 6.0);
        const real_type dx = (x_max - x_min) / N;
        for(std::size_t i=0; i<N; ++i)
        {
            const real_type x = x_min + i * dx;
            const real_type p1 = pot.potential(x);
            const real_type p2 = ref.potential(x);
            const real_type d1 = pot.derivative(x);
            const real_type d2 = ref.derivative(x);

            BOOST_TEST(p1 == p2, boost::test_tools::tolerance(h));
            BOOST_TEST(d1 == d2, boost::test_tools::tolerance(h));
        }
    }
    {
        const real_type x_min = r0 * std::sqrt(5.0 / 6.0);
        const real_type x_max = pot.cutoff();
        const real_type dx = (x_max - x_min) / N;
        for(std::size_t i=1; i<N; ++i)
        {
            const real_type x = x_min + i * dx;
            const real_type p = pot.potential(x);
            const real_type d = pot.derivative(x);

            BOOST_TEST(p == 0.0, boost::test_tools::tolerance(h));
            BOOST_TEST(d == 0.0, boost::test_tools::tolerance(h));
        }
    }
}
<commit_msg>test: fix range of values to be tested<commit_after>#define BOOST_TEST_MODULE "test_mbasin_repulsive_potential"

#ifdef BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#else
#include <boost/test/included/unit_test.hpp>
#endif

#include <mjolnir/forcefield/local/GoContactPotential.hpp>
#include <mjolnir/forcefield/local/MBasinRepulsivePotential.hpp>
#include <iomanip>

BOOST_AUTO_TEST_CASE(MBasinrepulsive)
{
    using real_type = double;
    constexpr std::size_t N = 1000;
    constexpr real_type   h = 1e-6;

    const real_type e  = 1.0;
    const real_type r0 = 5.0;

    mjolnir::GoContactPotential<real_type>       ref(e, r0);
    mjolnir::MBasinRepulsivePotential<real_type> pot(e, r0);

    {
        const real_type x_min = r0 * 4.0 / 6.0;
        const real_type x_max = r0 * std::sqrt(5.0 / 6.0);
        const real_type dx = (x_max - x_min) / N;
        for(std::size_t i=0; i<N; ++i)
        {
            const real_type x = x_min + i * dx;
            const real_type p1 = pot.potential(x);
            const real_type p2 = ref.potential(x);
            const real_type d1 = pot.derivative(x);
            const real_type d2 = ref.derivative(x);

            BOOST_TEST(p1 == p2, boost::test_tools::tolerance(h));
            BOOST_TEST(d1 == d2, boost::test_tools::tolerance(h));
        }
    }
    {
        const real_type x_min = r0 * std::sqrt(5.0 / 6.0);
        const real_type x_max = r0 * 2.5;
        const real_type dx = (x_max - x_min) / N;
        for(std::size_t i=1; i<N; ++i)
        {
            const real_type x = x_min + i * dx;
            const real_type p = pot.potential(x);
            const real_type d = pot.derivative(x);

            BOOST_TEST(p == 0.0, boost::test_tools::tolerance(h));
            BOOST_TEST(d == 0.0, boost::test_tools::tolerance(h));
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "MultiStock.hxx"
#include "MapStock.hxx"
#include "GetHandler.hxx"
#include "Item.hxx"

MultiStock::Domain::Item::~Item()
{
    assert(leases.empty());

    item.Put(!reuse);
}

void
MultiStock::Domain::Item::AddLease(StockGetHandler &handler,
                                   struct lease_ref &lease_ref)
{
    lease_ref.Set(AddLease());

    handler.OnStockItemReady(item);
}

void
MultiStock::Domain::Item::DeleteLease(Lease *lease, bool _reuse)
{
    reuse &= _reuse;

    assert(!leases.empty());
    leases.erase_and_dispose(leases.iterator_to(*lease),
                             DeleteDisposer());

    if (leases.empty())
        domain->second.DeleteItem(*this);
}

StockItem *
MultiStock::Domain::GetNow(DomainMap::iterator di,
                           struct pool &caller_pool,
                           const char *uri, void *info,
                           unsigned max_leases,
                           struct lease_ref &lease_ref)
{
    auto i = FindUsableItem();
    if (i == nullptr) {
        auto *item = stock.hstock.GetNow(caller_pool, uri, info);
        i = new Item(di, max_leases, *item);
        items.push_front(*i);
    }

    return i->AddLease(lease_ref);
}

StockItem *
MultiStock::GetNow(struct pool &caller_pool, const char *uri, void *info,
                   unsigned max_leases,
                   struct lease_ref &lease_ref)
{
    auto di = domains.insert(std::make_pair(uri, Domain(*this))).first;
    return di->second.GetNow(di, caller_pool, uri, info, max_leases,
                             lease_ref);
}
<commit_msg>stock/MultiStock: use std::map::emplace() to avoid copying a Domain instance<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "MultiStock.hxx"
#include "MapStock.hxx"
#include "GetHandler.hxx"
#include "Item.hxx"

MultiStock::Domain::Item::~Item()
{
    assert(leases.empty());

    item.Put(!reuse);
}

void
MultiStock::Domain::Item::AddLease(StockGetHandler &handler,
                                   struct lease_ref &lease_ref)
{
    lease_ref.Set(AddLease());

    handler.OnStockItemReady(item);
}

void
MultiStock::Domain::Item::DeleteLease(Lease *lease, bool _reuse)
{
    reuse &= _reuse;

    assert(!leases.empty());
    leases.erase_and_dispose(leases.iterator_to(*lease),
                             DeleteDisposer());

    if (leases.empty())
        domain->second.DeleteItem(*this);
}

StockItem *
MultiStock::Domain::GetNow(DomainMap::iterator di,
                           struct pool &caller_pool,
                           const char *uri, void *info,
                           unsigned max_leases,
                           struct lease_ref &lease_ref)
{
    auto i = FindUsableItem();
    if (i == nullptr) {
        auto *item = stock.hstock.GetNow(caller_pool, uri, info);
        i = new Item(di, max_leases, *item);
        items.push_front(*i);
    }

    return i->AddLease(lease_ref);
}

StockItem *
MultiStock::GetNow(struct pool &caller_pool, const char *uri, void *info,
                   unsigned max_leases,
                   struct lease_ref &lease_ref)
{
    auto di = domains.emplace(uri, *this).first;
    return di->second.GetNow(di, caller_pool, uri, info, max_leases,
                             lease_ref);
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo 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.
 *****************************************************************************/

/**
 * @file dp_road_graph.h
 **/

#include "modules/planning/tasks/dp_poly_path/dp_road_graph.h"

#include <algorithm>
#include <limits>
#include <string>
#include <unordered_map>
#include <utility>

#include "modules/common/proto/error_code.pb.h"
#include "modules/common/proto/pnc_point.pb.h"

#include "modules/common/configs/vehicle_config_helper.h"
#include "modules/common/log.h"
#include "modules/common/util/util.h"
#include "modules/planning/common/path/frenet_frame_path.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/math/curve1d/quintic_polynomial_curve1d.h"
#include "modules/planning/tasks/dp_poly_path/trajectory_cost.h"

namespace apollo {
namespace planning {

using apollo::common::ErrorCode;
using apollo::common::Status;

DPRoadGraph::DPRoadGraph(const DpPolyPathConfig &config,
                         const ReferenceLineInfo &reference_line_info,
                         const SpeedData &speed_data)
    : config_(config),
      reference_line_info_(reference_line_info),
      reference_line_(reference_line_info.reference_line()),
      speed_data_(speed_data) {}

bool DPRoadGraph::FindPathTunnel(
    const common::TrajectoryPoint &init_point,
    const std::vector<const PathObstacle *> &obstacles,
    PathData *const path_data) {
  CHECK_NOTNULL(path_data);
  init_point_ = init_point;
  if (!reference_line_.XYToSL(
          {init_point_.path_point().x(), init_point_.path_point().y()},
          &init_sl_point_)) {
    AERROR << "Fail to create init_sl_point from : "
           << init_point.DebugString();
    return false;
  }
  std::vector<DPRoadGraphNode> min_cost_path;
  if (!GenerateMinCostPath(obstacles, &min_cost_path)) {
    AERROR << "Fail to generate graph!";
    return false;
  }
  std::vector<common::FrenetFramePoint> frenet_path;
  double accumulated_s = init_sl_point_.s();
  const double path_resolution = config_.path_resolution();

  for (std::size_t i = 1; i < min_cost_path.size(); ++i) {
    const auto &prev_node = min_cost_path[i - 1];
    const auto &cur_node = min_cost_path[i];

    const double path_length = cur_node.sl_point.s() - prev_node.sl_point.s();
    double current_s = 0.0;
    const auto &curve = cur_node.min_cost_curve;
    while (current_s + path_resolution / 2.0 < path_length) {
      const double l = curve.Evaluate(0, current_s);
      const double dl = curve.Evaluate(1, current_s);
      const double ddl = curve.Evaluate(2, current_s);
      common::FrenetFramePoint frenet_frame_point;
      frenet_frame_point.set_s(accumulated_s + current_s);
      frenet_frame_point.set_l(l);
      frenet_frame_point.set_dl(dl);
      frenet_frame_point.set_ddl(ddl);
      frenet_path.push_back(std::move(frenet_frame_point));
      current_s += path_resolution;
    }
    if (i == min_cost_path.size() - 1) {
      accumulated_s += current_s;
    } else {
      accumulated_s += path_length;
    }
  }
  FrenetFramePath tunnel(frenet_path);
  path_data->SetReferenceLine(&reference_line_);
  path_data->SetFrenetPath(tunnel);
  return true;
}

bool DPRoadGraph::GenerateMinCostPath(
    const std::vector<const PathObstacle *> &obstacles,
    std::vector<DPRoadGraphNode> *min_cost_path) {
  CHECK(min_cost_path != nullptr);

  std::vector<std::vector<common::SLPoint>> path_waypoints;
  if (!SamplePathWaypoints(init_point_, &path_waypoints)) {
    AERROR << "Fail to sample path waypoints!";
    return false;
  }
  path_waypoints.insert(path_waypoints.begin(),
                        std::vector<common::SLPoint>{init_sl_point_});

  const auto &vehicle_config =
      common::VehicleConfigHelper::instance()->GetConfig();

  TrajectoryCost trajectory_cost(config_, reference_line_, obstacles,
                                 vehicle_config.vehicle_param(), speed_data_);

  std::vector<std::vector<DPRoadGraphNode>> graph_nodes(path_waypoints.size());
  graph_nodes[0].emplace_back(init_sl_point_, nullptr, 0.0);

  for (std::size_t level = 1; level < path_waypoints.size(); ++level) {
    const auto &prev_dp_nodes = graph_nodes[level - 1];
    const auto &level_points = path_waypoints[level];
    for (const auto &cur_point : level_points) {
      graph_nodes[level].emplace_back(cur_point, nullptr);
      auto &cur_node = graph_nodes[level].back();
      for (const auto &prev_dp_node : prev_dp_nodes) {
        const auto &prev_sl_point = prev_dp_node.sl_point;
        QuinticPolynomialCurve1d curve(prev_sl_point.l(), 0.0, 0.0,
                                       cur_point.l(), 0.0, 0.0,
                                       cur_point.s() - prev_sl_point.s());
        const double cost =
            trajectory_cost.Calculate(curve, prev_sl_point.s(), cur_point.s()) +
            prev_dp_node.min_cost;
        cur_node.UpdateCost(&prev_dp_node, curve, cost);
      }
    }
  }

  // find best path
  DPRoadGraphNode fake_head;
  for (const auto &cur_dp_node : graph_nodes.back()) {
    fake_head.UpdateCost(&cur_dp_node, cur_dp_node.min_cost_curve,
                         cur_dp_node.min_cost);
  }

  const auto *min_cost_node = &fake_head;
  while (min_cost_node->min_cost_prev_node) {
    min_cost_node = min_cost_node->min_cost_prev_node;
    min_cost_path->push_back(*min_cost_node);
  }
  std::reverse(min_cost_path->begin(), min_cost_path->end());
  return true;
}

bool DPRoadGraph::SamplePathWaypoints(
    const common::TrajectoryPoint &init_point,
    std::vector<std::vector<common::SLPoint>> *const points) {
  constexpr double kSamplePointLookForwardTimeChangeLane = 3.0;
  constexpr double kSamplePointLookForwardTimeNoChangeLane = 1.0;
  CHECK(points != nullptr);

  const double reference_line_length = reference_line_.Length();

  double level_distance = 0.0;
  if (reference_line_info_.IsChangeLanePath()) {
    level_distance =
        std::max(config_.step_length_min(),
                 init_point.v() * kSamplePointLookForwardTimeChangeLane);
  } else {
    level_distance = common::math::Clamp(
        init_point.v() * kSamplePointLookForwardTimeNoChangeLane,
        config_.step_length_min(), config_.step_length_max());
  }
  double accumulated_s = init_sl_point_.s();
  for (std::size_t i = 0; accumulated_s < reference_line_length; ++i) {
    std::vector<common::SLPoint> level_points;
    accumulated_s += level_distance;
    const double s = std::fmin(accumulated_s, reference_line_length);

    double left_width = 0.0;
    double right_width = 0.0;
    reference_line_.GetLaneWidth(s, &left_width, &right_width);
    std::vector<double> sample_l;
    common::util::uniform_slice(-right_width, left_width,
                                config_.sample_points_num_each_level() - 1,
                                &sample_l);
    for (double l : sample_l) {
      level_points.emplace_back(common::util::MakeSLPoint(s, l));
    }
    if (!level_points.empty()) {
      points->emplace_back(level_points);
    }
  }
  return true;
}

}  // namespace planning
}  // namespace apollo
<commit_msg>Planning: fixed a bug in dp_road_graph sampler.<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo 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.
 *****************************************************************************/

/**
 * @file dp_road_graph.h
 **/

#include "modules/planning/tasks/dp_poly_path/dp_road_graph.h"

#include <algorithm>
#include <limits>
#include <string>
#include <unordered_map>
#include <utility>

#include "modules/common/proto/error_code.pb.h"
#include "modules/common/proto/pnc_point.pb.h"

#include "modules/common/configs/vehicle_config_helper.h"
#include "modules/common/log.h"
#include "modules/common/util/util.h"
#include "modules/planning/common/path/frenet_frame_path.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/math/curve1d/quintic_polynomial_curve1d.h"
#include "modules/planning/tasks/dp_poly_path/trajectory_cost.h"

namespace apollo {
namespace planning {

using apollo::common::ErrorCode;
using apollo::common::Status;

DPRoadGraph::DPRoadGraph(const DpPolyPathConfig &config,
                         const ReferenceLineInfo &reference_line_info,
                         const SpeedData &speed_data)
    : config_(config),
      reference_line_info_(reference_line_info),
      reference_line_(reference_line_info.reference_line()),
      speed_data_(speed_data) {}

bool DPRoadGraph::FindPathTunnel(
    const common::TrajectoryPoint &init_point,
    const std::vector<const PathObstacle *> &obstacles,
    PathData *const path_data) {
  CHECK_NOTNULL(path_data);
  init_point_ = init_point;
  if (!reference_line_.XYToSL(
          {init_point_.path_point().x(), init_point_.path_point().y()},
          &init_sl_point_)) {
    AERROR << "Fail to create init_sl_point from : "
           << init_point.DebugString();
    return false;
  }
  std::vector<DPRoadGraphNode> min_cost_path;
  if (!GenerateMinCostPath(obstacles, &min_cost_path)) {
    AERROR << "Fail to generate graph!";
    return false;
  }
  std::vector<common::FrenetFramePoint> frenet_path;
  double accumulated_s = init_sl_point_.s();
  const double path_resolution = config_.path_resolution();

  for (std::size_t i = 1; i < min_cost_path.size(); ++i) {
    const auto &prev_node = min_cost_path[i - 1];
    const auto &cur_node = min_cost_path[i];

    const double path_length = cur_node.sl_point.s() - prev_node.sl_point.s();
    double current_s = 0.0;
    const auto &curve = cur_node.min_cost_curve;
    while (current_s + path_resolution / 2.0 < path_length) {
      const double l = curve.Evaluate(0, current_s);
      const double dl = curve.Evaluate(1, current_s);
      const double ddl = curve.Evaluate(2, current_s);
      common::FrenetFramePoint frenet_frame_point;
      frenet_frame_point.set_s(accumulated_s + current_s);
      frenet_frame_point.set_l(l);
      frenet_frame_point.set_dl(dl);
      frenet_frame_point.set_ddl(ddl);
      frenet_path.push_back(std::move(frenet_frame_point));
      current_s += path_resolution;
    }
    if (i == min_cost_path.size() - 1) {
      accumulated_s += current_s;
    } else {
      accumulated_s += path_length;
    }
  }
  FrenetFramePath tunnel(frenet_path);
  path_data->SetReferenceLine(&reference_line_);
  path_data->SetFrenetPath(tunnel);
  return true;
}

bool DPRoadGraph::GenerateMinCostPath(
    const std::vector<const PathObstacle *> &obstacles,
    std::vector<DPRoadGraphNode> *min_cost_path) {
  CHECK(min_cost_path != nullptr);

  std::vector<std::vector<common::SLPoint>> path_waypoints;
  if (!SamplePathWaypoints(init_point_, &path_waypoints)) {
    AERROR << "Fail to sample path waypoints!";
    return false;
  }
  path_waypoints.insert(path_waypoints.begin(),
                        std::vector<common::SLPoint>{init_sl_point_});

  const auto &vehicle_config =
      common::VehicleConfigHelper::instance()->GetConfig();

  TrajectoryCost trajectory_cost(config_, reference_line_, obstacles,
                                 vehicle_config.vehicle_param(), speed_data_);

  std::vector<std::vector<DPRoadGraphNode>> graph_nodes(path_waypoints.size());
  graph_nodes[0].emplace_back(init_sl_point_, nullptr, 0.0);

  for (std::size_t level = 1; level < path_waypoints.size(); ++level) {
    const auto &prev_dp_nodes = graph_nodes[level - 1];
    const auto &level_points = path_waypoints[level];
    for (const auto &cur_point : level_points) {
      graph_nodes[level].emplace_back(cur_point, nullptr);
      auto &cur_node = graph_nodes[level].back();
      for (const auto &prev_dp_node : prev_dp_nodes) {
        const auto &prev_sl_point = prev_dp_node.sl_point;
        QuinticPolynomialCurve1d curve(prev_sl_point.l(), 0.0, 0.0,
                                       cur_point.l(), 0.0, 0.0,
                                       cur_point.s() - prev_sl_point.s());
        const double cost =
            trajectory_cost.Calculate(curve, prev_sl_point.s(), cur_point.s()) +
            prev_dp_node.min_cost;
        cur_node.UpdateCost(&prev_dp_node, curve, cost);
      }
    }
  }

  // find best path
  DPRoadGraphNode fake_head;
  for (const auto &cur_dp_node : graph_nodes.back()) {
    fake_head.UpdateCost(&cur_dp_node, cur_dp_node.min_cost_curve,
                         cur_dp_node.min_cost);
  }

  const auto *min_cost_node = &fake_head;
  while (min_cost_node->min_cost_prev_node) {
    min_cost_node = min_cost_node->min_cost_prev_node;
    min_cost_path->push_back(*min_cost_node);
  }
  std::reverse(min_cost_path->begin(), min_cost_path->end());
  return true;
}

bool DPRoadGraph::SamplePathWaypoints(
    const common::TrajectoryPoint &init_point,
    std::vector<std::vector<common::SLPoint>> *const points) {
  constexpr double kSamplePointLookForwardTimeChangeLane = 3.0;
  constexpr double kSamplePointLookForwardTimeNoChangeLane = 1.0;
  CHECK(points != nullptr);

  const double reference_line_length = reference_line_.Length();

  double level_distance = 0.0;
  if (reference_line_info_.IsChangeLanePath()) {
    level_distance =
        std::max(config_.step_length_min(),
                 init_point.v() * kSamplePointLookForwardTimeChangeLane);
  } else {
    level_distance = common::math::Clamp(
        init_point.v() * kSamplePointLookForwardTimeNoChangeLane,
        config_.step_length_min(), config_.step_length_max());
  }
  double accumulated_s = init_sl_point_.s();
  for (std::size_t i = 0; accumulated_s < reference_line_length; ++i) {
    std::vector<common::SLPoint> level_points;
    accumulated_s += level_distance;
    const double s = std::fmin(accumulated_s, reference_line_length);

    double left_width = 0.0;
    double right_width = 0.0;
    reference_line_.GetLaneWidth(s, &left_width, &right_width);
    const auto &vehicle_config =
        common::VehicleConfigHelper::instance()->GetConfig();
    const double half_adc_width = vehicle_config.vehicle_param().width() / 2.0;
    const double eff_right_width = right_width - half_adc_width;
    const double eff_left_width = left_width - half_adc_width;

    std::vector<double> sample_l;
    common::util::uniform_slice(-eff_right_width, eff_left_width,
                                config_.sample_points_num_each_level() - 1,
                                &sample_l);
    for (double l : sample_l) {
      level_points.emplace_back(common::util::MakeSLPoint(s, l));
    }
    if (!level_points.empty()) {
      points->emplace_back(level_points);
    }
  }
  return true;
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/video_capture/android/device_info_android.h"

#include <algorithm>
#include <sstream>
#include <vector>

#include "json/json.h"
#include "third_party/icu/source/common/unicode/unistr.h"
#include "webrtc/modules/video_capture/android/video_capture_android.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/ref_count.h"
#include "webrtc/system_wrappers/interface/trace.h"

namespace webrtc {

namespace videocapturemodule {

// Helper for storing lists of pairs of ints.  Used e.g. for resolutions & FPS
// ranges.
typedef std::pair<int, int> IntPair;
typedef std::vector<IntPair> IntPairs;

static std::string IntPairsToString(const IntPairs& pairs, char separator) {
  std::stringstream stream;
  for (size_t i = 0; i < pairs.size(); ++i) {
    if (i > 0)
      stream << ", ";
    stream << "(" << pairs[i].first << separator << pairs[i].second << ")";
  }
  return stream.str();
}

struct AndroidCameraInfo {
  std::string name;
  bool front_facing;
  int orientation;
  IntPairs resolutions;  // Pairs are: (width,height).
  // Pairs are (min,max) in units of FPS*1000 ("milli-frame-per-second").
  IntPairs mfpsRanges;

  std::string ToString() {
    std::stringstream stream;
    stream << "Name: [" << name << "], MFPS ranges: ["
           << IntPairsToString(mfpsRanges, ':')
           << "], front_facing: " << front_facing
           << ", orientation: " << orientation << ", resolutions: ["
           << IntPairsToString(resolutions, 'x') << "]";
    return stream.str();
  }
};

// Camera info; populated during DeviceInfoAndroid::Initialize() and immutable
// thereafter.
static std::vector<AndroidCameraInfo>* g_camera_info = NULL;

// Set |*index| to the index of |name| in g_camera_info or return false if no
// match found.
static bool FindCameraIndexByName(const std::string& name, size_t* index) {
  for (size_t i = 0; i < g_camera_info->size(); ++i) {
    if (g_camera_info->at(i).name == name) {
      *index = i;
      return true;
    }
  }
  return false;
}

// Returns a pointer to the named member of g_camera_info, or NULL if no match
// is found.
static AndroidCameraInfo* FindCameraInfoByName(const std::string& name) {
  size_t index = 0;
  if (FindCameraIndexByName(name, &index))
    return &g_camera_info->at(index);
  return NULL;
}

// static
void DeviceInfoAndroid::Initialize(JNIEnv* jni) {
  // TODO(henrike): this "if" would make a lot more sense as an assert, but
  // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine() and
  // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_Terminate() conspire to
  // prevent this.  Once that code is made to only
  // VideoEngine::SetAndroidObjects() once per process, this can turn into an
  // assert.
  if (g_camera_info)
    return;

  g_camera_info = new std::vector<AndroidCameraInfo>();
  jclass j_info_class =
      jni->FindClass("org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid");
  assert(j_info_class);
  jmethodID j_initialize = jni->GetStaticMethodID(
      j_info_class, "getDeviceInfo", "()Ljava/lang/String;");
  jstring j_json_info = static_cast<jstring>(
      jni->CallStaticObjectMethod(j_info_class, j_initialize));

  const jchar* jchars = jni->GetStringChars(j_json_info, NULL);
  icu::UnicodeString ustr(jchars, jni->GetStringLength(j_json_info));
  jni->ReleaseStringChars(j_json_info, jchars);
  std::string json_info;
  ustr.toUTF8String(json_info);

  Json::Value cameras;
  Json::Reader reader(Json::Features::strictMode());
  bool parsed = reader.parse(json_info, cameras);
  if (!parsed) {
    std::stringstream stream;
    stream << "Failed to parse configuration:\n"
           << reader.getFormattedErrorMessages();
    assert(false);
    return;
  }
  for (Json::ArrayIndex i = 0; i < cameras.size(); ++i) {
    const Json::Value& camera = cameras[i];
    AndroidCameraInfo info;
    info.name = camera["name"].asString();
    info.front_facing = camera["front_facing"].asBool();
    info.orientation = camera["orientation"].asInt();
    Json::Value sizes = camera["sizes"];
    for (Json::ArrayIndex j = 0; j < sizes.size(); ++j) {
      const Json::Value& size = sizes[j];
      info.resolutions.push_back(std::make_pair(
          size["width"].asInt(), size["height"].asInt()));
    }
    Json::Value mfpsRanges = camera["mfpsRanges"];
    for (Json::ArrayIndex j = 0; j < mfpsRanges.size(); ++j) {
      const Json::Value& mfpsRange = mfpsRanges[j];
      info.mfpsRanges.push_back(std::make_pair(mfpsRange["min_mfps"].asInt(),
                                               mfpsRange["max_mfps"].asInt()));
    }
    g_camera_info->push_back(info);
  }
}

void DeviceInfoAndroid::DeInitialize() {
  if (g_camera_info) {
    delete g_camera_info;
    g_camera_info = NULL;
  }
}

VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo(
    const int32_t id) {
  return new videocapturemodule::DeviceInfoAndroid(id);
}

DeviceInfoAndroid::DeviceInfoAndroid(const int32_t id) :
    DeviceInfoImpl(id) {
}

DeviceInfoAndroid::~DeviceInfoAndroid() {
}

bool DeviceInfoAndroid::FindCameraIndex(const char* deviceUniqueIdUTF8,
                                        size_t* index) {
  return FindCameraIndexByName(deviceUniqueIdUTF8, index);
}

int32_t DeviceInfoAndroid::Init() {
  return 0;
}

uint32_t DeviceInfoAndroid::NumberOfDevices() {
  return g_camera_info->size();
}

int32_t DeviceInfoAndroid::GetDeviceName(
    uint32_t deviceNumber,
    char* deviceNameUTF8,
    uint32_t deviceNameLength,
    char* deviceUniqueIdUTF8,
    uint32_t deviceUniqueIdUTF8Length,
    char* /*productUniqueIdUTF8*/,
    uint32_t /*productUniqueIdUTF8Length*/) {
  if (deviceNumber >= g_camera_info->size())
    return -1;
  const AndroidCameraInfo& info = g_camera_info->at(deviceNumber);
  if (info.name.length() + 1 > deviceNameLength ||
      info.name.length() + 1 > deviceUniqueIdUTF8Length) {
    return -1;
  }
  memcpy(deviceNameUTF8, info.name.c_str(), info.name.length() + 1);
  memcpy(deviceUniqueIdUTF8, info.name.c_str(), info.name.length() + 1);
  return 0;
}

int32_t DeviceInfoAndroid::CreateCapabilityMap(
    const char* deviceUniqueIdUTF8) {
  _captureCapabilities.clear();
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL)
    return -1;

  for (size_t i = 0; i < info->resolutions.size(); ++i) {
    for (size_t j = 0; j < info->mfpsRanges.size(); ++j) {
      const IntPair& size = info->resolutions[i];
      const IntPair& mfpsRange = info->mfpsRanges[j];
      VideoCaptureCapability cap;
      cap.width = size.first;
      cap.height = size.second;
      cap.maxFPS = mfpsRange.second / 1000;
      cap.expectedCaptureDelay = kExpectedCaptureDelay;
      cap.rawType = kVideoNV21;
      _captureCapabilities.push_back(cap);
    }
  }
  return _captureCapabilities.size();
}

int32_t DeviceInfoAndroid::GetOrientation(
    const char* deviceUniqueIdUTF8,
    VideoCaptureRotation& orientation) {
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL ||
      !VideoCaptureImpl::RotationFromDegrees(info->orientation, &orientation)) {
    return -1;
  }
  return 0;
}

void DeviceInfoAndroid::GetMFpsRange(const char* deviceUniqueIdUTF8,
                                     int max_fps_to_match,
                                     int* min_mfps, int* max_mfps) {
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL)
    return;
  int desired_mfps = max_fps_to_match * 1000;
  int best_diff_mfps = 0;
  LOG(LS_INFO) << "Search for best target mfps " << desired_mfps;
  // Search for best fps range with preference shifted to constant fps modes.
  for (size_t i = 0; i < info->mfpsRanges.size(); ++i) {
    int diff_mfps = abs(info->mfpsRanges[i].first - desired_mfps) +
        abs(info->mfpsRanges[i].second - desired_mfps) +
        (info->mfpsRanges[i].second - info->mfpsRanges[i].first) / 2;
    LOG(LS_INFO) << "Fps range " << info->mfpsRanges[i].first << ":" <<
        info->mfpsRanges[i].second << ". Distance: " << diff_mfps;
    if (i == 0 || diff_mfps < best_diff_mfps) {
      best_diff_mfps = diff_mfps;
      *min_mfps = info->mfpsRanges[i].first;
      *max_mfps = info->mfpsRanges[i].second;
    }
  }
}

}  // namespace videocapturemodule
}  // namespace webrtc
<commit_msg>Getting orientation is not working properly. VideoCaptureImpl::RotationFromDegrees returns -1 in case fails not 0. So we need to change the if statement.<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/video_capture/android/device_info_android.h"

#include <algorithm>
#include <sstream>
#include <vector>

#include "json/json.h"
#include "third_party/icu/source/common/unicode/unistr.h"
#include "webrtc/modules/video_capture/android/video_capture_android.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/ref_count.h"
#include "webrtc/system_wrappers/interface/trace.h"

namespace webrtc {

namespace videocapturemodule {

// Helper for storing lists of pairs of ints.  Used e.g. for resolutions & FPS
// ranges.
typedef std::pair<int, int> IntPair;
typedef std::vector<IntPair> IntPairs;

static std::string IntPairsToString(const IntPairs& pairs, char separator) {
  std::stringstream stream;
  for (size_t i = 0; i < pairs.size(); ++i) {
    if (i > 0)
      stream << ", ";
    stream << "(" << pairs[i].first << separator << pairs[i].second << ")";
  }
  return stream.str();
}

struct AndroidCameraInfo {
  std::string name;
  bool front_facing;
  int orientation;
  IntPairs resolutions;  // Pairs are: (width,height).
  // Pairs are (min,max) in units of FPS*1000 ("milli-frame-per-second").
  IntPairs mfpsRanges;

  std::string ToString() {
    std::stringstream stream;
    stream << "Name: [" << name << "], MFPS ranges: ["
           << IntPairsToString(mfpsRanges, ':')
           << "], front_facing: " << front_facing
           << ", orientation: " << orientation << ", resolutions: ["
           << IntPairsToString(resolutions, 'x') << "]";
    return stream.str();
  }
};

// Camera info; populated during DeviceInfoAndroid::Initialize() and immutable
// thereafter.
static std::vector<AndroidCameraInfo>* g_camera_info = NULL;

// Set |*index| to the index of |name| in g_camera_info or return false if no
// match found.
static bool FindCameraIndexByName(const std::string& name, size_t* index) {
  for (size_t i = 0; i < g_camera_info->size(); ++i) {
    if (g_camera_info->at(i).name == name) {
      *index = i;
      return true;
    }
  }
  return false;
}

// Returns a pointer to the named member of g_camera_info, or NULL if no match
// is found.
static AndroidCameraInfo* FindCameraInfoByName(const std::string& name) {
  size_t index = 0;
  if (FindCameraIndexByName(name, &index))
    return &g_camera_info->at(index);
  return NULL;
}

// static
void DeviceInfoAndroid::Initialize(JNIEnv* jni) {
  // TODO(henrike): this "if" would make a lot more sense as an assert, but
  // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine() and
  // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_Terminate() conspire to
  // prevent this.  Once that code is made to only
  // VideoEngine::SetAndroidObjects() once per process, this can turn into an
  // assert.
  if (g_camera_info)
    return;

  g_camera_info = new std::vector<AndroidCameraInfo>();
  jclass j_info_class =
      jni->FindClass("org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid");
  assert(j_info_class);
  jmethodID j_initialize = jni->GetStaticMethodID(
      j_info_class, "getDeviceInfo", "()Ljava/lang/String;");
  jstring j_json_info = static_cast<jstring>(
      jni->CallStaticObjectMethod(j_info_class, j_initialize));

  const jchar* jchars = jni->GetStringChars(j_json_info, NULL);
  icu::UnicodeString ustr(jchars, jni->GetStringLength(j_json_info));
  jni->ReleaseStringChars(j_json_info, jchars);
  std::string json_info;
  ustr.toUTF8String(json_info);

  Json::Value cameras;
  Json::Reader reader(Json::Features::strictMode());
  bool parsed = reader.parse(json_info, cameras);
  if (!parsed) {
    std::stringstream stream;
    stream << "Failed to parse configuration:\n"
           << reader.getFormattedErrorMessages();
    assert(false);
    return;
  }
  for (Json::ArrayIndex i = 0; i < cameras.size(); ++i) {
    const Json::Value& camera = cameras[i];
    AndroidCameraInfo info;
    info.name = camera["name"].asString();
    info.front_facing = camera["front_facing"].asBool();
    info.orientation = camera["orientation"].asInt();
    Json::Value sizes = camera["sizes"];
    for (Json::ArrayIndex j = 0; j < sizes.size(); ++j) {
      const Json::Value& size = sizes[j];
      info.resolutions.push_back(std::make_pair(
          size["width"].asInt(), size["height"].asInt()));
    }
    Json::Value mfpsRanges = camera["mfpsRanges"];
    for (Json::ArrayIndex j = 0; j < mfpsRanges.size(); ++j) {
      const Json::Value& mfpsRange = mfpsRanges[j];
      info.mfpsRanges.push_back(std::make_pair(mfpsRange["min_mfps"].asInt(),
                                               mfpsRange["max_mfps"].asInt()));
    }
    g_camera_info->push_back(info);
  }
}

void DeviceInfoAndroid::DeInitialize() {
  if (g_camera_info) {
    delete g_camera_info;
    g_camera_info = NULL;
  }
}

VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo(
    const int32_t id) {
  return new videocapturemodule::DeviceInfoAndroid(id);
}

DeviceInfoAndroid::DeviceInfoAndroid(const int32_t id) :
    DeviceInfoImpl(id) {
}

DeviceInfoAndroid::~DeviceInfoAndroid() {
}

bool DeviceInfoAndroid::FindCameraIndex(const char* deviceUniqueIdUTF8,
                                        size_t* index) {
  return FindCameraIndexByName(deviceUniqueIdUTF8, index);
}

int32_t DeviceInfoAndroid::Init() {
  return 0;
}

uint32_t DeviceInfoAndroid::NumberOfDevices() {
  return g_camera_info->size();
}

int32_t DeviceInfoAndroid::GetDeviceName(
    uint32_t deviceNumber,
    char* deviceNameUTF8,
    uint32_t deviceNameLength,
    char* deviceUniqueIdUTF8,
    uint32_t deviceUniqueIdUTF8Length,
    char* /*productUniqueIdUTF8*/,
    uint32_t /*productUniqueIdUTF8Length*/) {
  if (deviceNumber >= g_camera_info->size())
    return -1;
  const AndroidCameraInfo& info = g_camera_info->at(deviceNumber);
  if (info.name.length() + 1 > deviceNameLength ||
      info.name.length() + 1 > deviceUniqueIdUTF8Length) {
    return -1;
  }
  memcpy(deviceNameUTF8, info.name.c_str(), info.name.length() + 1);
  memcpy(deviceUniqueIdUTF8, info.name.c_str(), info.name.length() + 1);
  return 0;
}

int32_t DeviceInfoAndroid::CreateCapabilityMap(
    const char* deviceUniqueIdUTF8) {
  _captureCapabilities.clear();
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL)
    return -1;

  for (size_t i = 0; i < info->resolutions.size(); ++i) {
    for (size_t j = 0; j < info->mfpsRanges.size(); ++j) {
      const IntPair& size = info->resolutions[i];
      const IntPair& mfpsRange = info->mfpsRanges[j];
      VideoCaptureCapability cap;
      cap.width = size.first;
      cap.height = size.second;
      cap.maxFPS = mfpsRange.second / 1000;
      cap.expectedCaptureDelay = kExpectedCaptureDelay;
      cap.rawType = kVideoNV21;
      _captureCapabilities.push_back(cap);
    }
  }
  return _captureCapabilities.size();
}

int32_t DeviceInfoAndroid::GetOrientation(
    const char* deviceUniqueIdUTF8,
    VideoCaptureRotation& orientation) {
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL ||
      VideoCaptureImpl::RotationFromDegrees(info->orientation,
                                            &orientation) != 0) {
    return -1;
  }
  return 0;
}

void DeviceInfoAndroid::GetMFpsRange(const char* deviceUniqueIdUTF8,
                                     int max_fps_to_match,
                                     int* min_mfps, int* max_mfps) {
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL)
    return;
  int desired_mfps = max_fps_to_match * 1000;
  int best_diff_mfps = 0;
  LOG(LS_INFO) << "Search for best target mfps " << desired_mfps;
  // Search for best fps range with preference shifted to constant fps modes.
  for (size_t i = 0; i < info->mfpsRanges.size(); ++i) {
    int diff_mfps = abs(info->mfpsRanges[i].first - desired_mfps) +
        abs(info->mfpsRanges[i].second - desired_mfps) +
        (info->mfpsRanges[i].second - info->mfpsRanges[i].first) / 2;
    LOG(LS_INFO) << "Fps range " << info->mfpsRanges[i].first << ":" <<
        info->mfpsRanges[i].second << ". Distance: " << diff_mfps;
    if (i == 0 || diff_mfps < best_diff_mfps) {
      best_diff_mfps = diff_mfps;
      *min_mfps = info->mfpsRanges[i].first;
      *max_mfps = info->mfpsRanges[i].second;
    }
  }
}

}  // namespace videocapturemodule
}  // namespace webrtc
<|endoftext|>


<commit_before>#include <Arduino.h>
#include "TestRunner.h"

extern HardwareSerial Serial;

// Test callback returns -1 if in progress, 0 if failed, 1 if passed
void runTest(const char *name, long timeout, char (*test)(char))
{
   int result = -1;
   Serial.print("  \"");
   Serial.print(name);
   Serial.print("\" : { ");

   // setup test
   test(SETUP);

   // run test
   unsigned long start = millis();
   while((result = test(RUN)) == -1) {
      if(millis() - start > timeout)
      {
         break;
      }
   }

   unsigned long done = millis();

   // teardown test
   test(TEARDOWN);

   // result
   Serial.print("\"result\": ");
   if(done - start > timeout || result == 0)
   {
      Serial.print("\"fail\", ");
   }
   else
   {
      Serial.print("\"pass\", ");
   }
   Serial.print("\"duration\": ");
   Serial.print(done - start);
   Serial.println(" },");
}<commit_msg>Each test is a single JSON object<commit_after>#include <Arduino.h>
#include "TestRunner.h"

extern HardwareSerial Serial;

// Test callback returns -1 if in progress, 0 if failed, 1 if passed
void runTest(const char *name, long timeout, char (*test)(char))
{
   int result = -1;
   Serial.print("{ name: \"");
   Serial.print(name);
   Serial.print("\", ");

   // setup test
   test(SETUP);

   // run test
   unsigned long start = millis();
   while((result = test(RUN)) == -1) {
      if(millis() - start > timeout)
      {
         break;
      }
   }

   unsigned long done = millis();

   // teardown test
   test(TEARDOWN);

   // result
   Serial.print("\"result\": ");
   if(done - start > timeout || result == 0)
   {
      Serial.print("\"fail\", ");
   }
   else
   {
      Serial.print("\"pass\", ");
   }
   Serial.print("\"duration\": ");
   Serial.print(done - start);
   Serial.println(" }");
}<|endoftext|>


<commit_before>/*
** AUTOGENERATED CODE, DO NOT EDIT
**
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010 Aldebaran Robotics
*/

#ifndef  AL_MESSAGING_MAKE_FUNCTOR_HPP_
# define AL_MESSAGING_MAKE_FUNCTOR_HPP_

#include <alcommon-ng/functor/functor.hpp>

#include <boost/function_types/function_type.hpp>
#include <boost/function_types/is_member_function_pointer.hpp>
#include <boost/type_traits/is_member_function_pointer.hpp>

namespace AL
{
//  template <typename F>
//  Functor *makeFun(F f) {
//    boost::is_member_pointer<F>::type t;
//    boost::function_types::function_type<F>::arity
//  }
//  is_function
//  is_function_pointer
//  is_function_reference
//  is_member_pointer
//  is_member_object_pointer
//  is_member_function_pointer
//  is_callable_builtin
//  is_nonmember_callable_builtin

  template <typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) ()) {
    return new MemberFunctor_0<C, R>(obj, f);
  }

  template <typename R>
  Functor *makeFunctor(R (*f) ()) {
    return new Functor_0<R>(f);
  }

  template <typename P0, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0)) {
    return new MemberFunctor_1<P0, C, R>(obj, f);
  }

  template <typename P0, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0)) {
    return new Functor_1<P0, R>(f);
  }

  template <typename P0, typename P1, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0, const P1 &p1)) {
    return new MemberFunctor_2<P0, P1, C, R>(obj, f);
  }

  template <typename P0, typename P1, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0, const P1 &p1)) {
    return new Functor_2<P0, P1, R>(f);
  }

  template <typename P0, typename P1, typename P2, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0, const P1 &p1, const P2 &p2)) {
    return new MemberFunctor_3<P0, P1, P2, C, R>(obj, f);
  }

  template <typename P0, typename P1, typename P2, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0, const P1 &p1, const P2 &p2)) {
    return new Functor_3<P0, P1, P2, R>(f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3)) {
    return new MemberFunctor_4<P0, P1, P2, P3, C, R>(obj, f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3)) {
    return new Functor_4<P0, P1, P2, P3, R>(f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename P4, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4)) {
    return new MemberFunctor_5<P0, P1, P2, P3, P4, C, R>(obj, f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename P4, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4)) {
    return new Functor_5<P0, P1, P2, P3, P4, R>(f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5)) {
    return new MemberFunctor_6<P0, P1, P2, P3, P4, P5, C, R>(obj, f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5)) {
    return new Functor_6<P0, P1, P2, P3, P4, P5, R>(f);
  }

}
#endif
<commit_msg>cleanup<commit_after>/*
** AUTOGENERATED CODE, DO NOT EDIT
**
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010 Aldebaran Robotics
*/

#ifndef  AL_MESSAGING_MAKE_FUNCTOR_HPP_
# define AL_MESSAGING_MAKE_FUNCTOR_HPP_

#include <alcommon-ng/functor/functor.hpp>

namespace AL
{

  template <typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) ()) {
    return new MemberFunctor_0<C, R>(obj, f);
  }

  template <typename R>
  Functor *makeFunctor(R (*f) ()) {
    return new Functor_0<R>(f);
  }

  template <typename P0, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0)) {
    return new MemberFunctor_1<P0, C, R>(obj, f);
  }

  template <typename P0, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0)) {
    return new Functor_1<P0, R>(f);
  }

  template <typename P0, typename P1, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0, const P1 &p1)) {
    return new MemberFunctor_2<P0, P1, C, R>(obj, f);
  }

  template <typename P0, typename P1, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0, const P1 &p1)) {
    return new Functor_2<P0, P1, R>(f);
  }

  template <typename P0, typename P1, typename P2, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0, const P1 &p1, const P2 &p2)) {
    return new MemberFunctor_3<P0, P1, P2, C, R>(obj, f);
  }

  template <typename P0, typename P1, typename P2, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0, const P1 &p1, const P2 &p2)) {
    return new Functor_3<P0, P1, P2, R>(f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3)) {
    return new MemberFunctor_4<P0, P1, P2, P3, C, R>(obj, f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3)) {
    return new Functor_4<P0, P1, P2, P3, R>(f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename P4, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4)) {
    return new MemberFunctor_5<P0, P1, P2, P3, P4, C, R>(obj, f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename P4, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4)) {
    return new Functor_5<P0, P1, P2, P3, P4, R>(f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename C, typename R>
  Functor *makeFunctor(C *obj, R (C::*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5)) {
    return new MemberFunctor_6<P0, P1, P2, P3, P4, P5, C, R>(obj, f);
  }

  template <typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename R>
  Functor *makeFunctor(R (*f) (const P0 &p0, const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5)) {
    return new Functor_6<P0, P1, P2, P3, P4, P5, R>(f);
  }

}
#endif
<|endoftext|>


<commit_before>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium 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 3
of the License, or (at your option) any later version.

Bohrium 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 Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/
#include <bh.h>
#include <bh_dag.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <boost/foreach.hpp>
#include <boost/graph/topological_sort.hpp>
#include <vector>
#include <map>
#include <iterator>

#define VERBOSE

using namespace std;
using namespace boost;
using namespace bohrium::dag;

pair<int64_t,bool> fuse_mask(int64_t best_cost, const vector<EdgeW> &edges2explore,
                             const GraphDW graph, const vector<bool> &mask, GraphD &dag)
{
    bool fusibility=true;
    vector<EdgeW> edges2merge;
    unsigned int i=0;
    BOOST_FOREACH(const EdgeW &e, edges2explore)
    {
        if(mask[i++])
        {
            edges2merge.push_back(e);
        }
    }
//    cout << "size: " << edges2merge.size() << " of " << edges2explore.size() << endl;

    //Help function to find the new location
    struct find_new_location
    {
        Vertex operator()(map<Vertex, Vertex> &loc_map, Vertex v)
        {
            Vertex v_mapped = loc_map[v];
            if(v_mapped == v)
                return v;
            else
                return (*this)(loc_map, v_mapped);
        }
    }find_loc;

    //'loc_map' maps a vertex before the merge to the corresponding vertex after the merge
    map<Vertex, Vertex> loc_map;
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        loc_map[v] = v;
    }

    BOOST_FOREACH(const EdgeW &e, edges2merge)
    {
        Vertex v1 = find_loc(loc_map, source(e, graph.bglW()));
        Vertex v2 = find_loc(loc_map, target(e, graph.bglW()));
        loc_map[v1] = v2;
    }

    map<Vertex, bh_ir_kernel> new_vertices;
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        if(loc_map[v] == v)
            new_vertices[v] = bh_ir_kernel();
    }

    vector<Vertex> topological_order;
    topological_sort(dag, back_inserter(topological_order));
    BOOST_REVERSE_FOREACH(Vertex vertex, topological_order)
    {
        Vertex v = find_loc(loc_map, vertex);
        bh_ir_kernel &k = new_vertices.at(v);
        BOOST_FOREACH(const bh_instruction &i, dag[vertex].instr_list())
        {
            if(not k.fusible(i))
                fusibility = false;
            k.add_instr(i);
        }
    }

    int64_t cost=0;
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        if(loc_map[v] == v)
            cost += new_vertices[v].cost();
    }

    if(cost > best_cost or not fusibility)
        return make_pair(cost,fusibility);

    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        Vertex loc_v = loc_map[v];
        if(loc_v == v)
        {
            dag[v] = new_vertices[v];
        }
        else//Lets merge 'v' into 'loc_v'
        {
            BOOST_FOREACH(Vertex a, adjacent_vertices(v, dag))
            {
                if(a != loc_v)
                    add_edge(loc_v, a, dag);
            }
            BOOST_FOREACH(Vertex a, inv_adjacent_vertices(v, dag))
            {
                if(a != loc_v)
                    add_edge(a, loc_v, dag);
            }
            clear_vertex(v, dag);
            dag[v] = bh_ir_kernel();
        }
    }
    if(cycles(dag))
    {
        return make_pair(cost,false);
    }

    if(cost != (int64_t)dag_cost(dag))
    {
        cout << "cost: " << cost << ", dag_cost: " << dag_cost(dag) << endl;
        GraphDW tmp(dag);
        pprint(tmp, "what.dot");
        assert(1 == 2);
    }

    return make_pair(cost,true);
}
#ifdef VERBOSE
double  purge_count=0;
uint64_t explore_count=0;
int fuser_count=0;
#endif
int64_t best_cost;
int64_t one_cost;
GraphD best_dag;
void fuse(const GraphDW &dag, const vector<EdgeW> &edges2explore,
          vector<bool> mask, unsigned int offset, bool merge_next)
{
    if(not merge_next)
    {
        GraphD new_dag(dag.bglD());
        mask[offset] = merge_next;
        bool fusibility;
        int64_t cost;
        tie(cost, fusibility) = fuse_mask(best_cost, edges2explore, dag, mask, new_dag);

#ifdef VERBOSE
        if(explore_count%1000 == 0)
        {
            cout << "[" << explore_count << "] " << "purge count: " << purge_count << " / " << pow(2.0,mask.size()) << endl;
            cout << "cost: " << cost << ", best_cost: " << best_cost << ", fusibility: " << fusibility << endl;
        }
        ++explore_count;
#endif

        if(cost > best_cost)
        {
#ifdef VERBOSE
            purge_count += pow(2.0, mask.size()-offset-1);
#endif
            return;
        }
        if(fusibility)
        {
            best_cost = cost;
            best_dag = new_dag;
#ifdef VERBOSE
            std::stringstream ss;
            ss << "new_best_dag-" << fuser_count << "-" << dag_cost(new_dag) << ".dot";
            printf("write file: %s\n", ss.str().c_str());
            pprint(GraphDW(new_dag), ss.str().c_str());
            purge_count += pow(2.0, mask.size()-offset-1);
#endif
            return;
        }
    }
    if(offset+1 < mask.size())
    {
        fuse(dag, edges2explore, mask, offset+1, false);
        fuse(dag, edges2explore, mask, offset+1, true);
        fuse(dag, edges2explore, mask, offset+1, false);
    }
}

void fuser(bh_ir &bhir)
{
#ifdef VERBOSE
    ++fuser_count;
#endif

    GraphDW dag;
    from_bhir(bhir, dag);
    fuse_gentle(dag);
    dag.transitive_reduction();

    //The list of edges that we should try to merge
    vector<EdgeW> edges2explore;
    BOOST_FOREACH(const EdgeW &e, edges(dag.bglW()))
    {
        edges2explore.push_back(e);
    }
    sort_weights(dag.bglW(), edges2explore);
    //reverse(edges2explore.begin(), edges2explore.end());

    if(edges2explore.size() == 0)
    {
        fill_kernels(dag.bglD(), bhir.kernel_list);
        return;
    }

    //First we check the trivial case where all kernels are merged
    vector<bool> mask(edges2explore.size(), true);
    {
        GraphD new_dag(dag.bglD());
        bool fuse;
        tie(one_cost, fuse) = fuse_mask(numeric_limits<int64_t>::max(), edges2explore, dag, mask, new_dag);
        if(fuse)
        {
            fill_kernels(new_dag, bhir.kernel_list);
            return;
        }
    }

    //Then we use the greedy algorithm to find a good initial guess
    {
        GraphDW new_dag(dag);
        fuse_greedy(new_dag);
        best_dag = new_dag.bglD();
        best_cost = dag_cost(best_dag);
    }

    if(mask.size() > 100)
    {
        cout << "FUSER-OPTIMAL: ABORT the size of the search space is too large: 2^";
        cout << mask.size() << "!" << endl;
        fill_kernels(best_dag, bhir.kernel_list);
        return;
    }
    else if(mask.size() > 10)
    {
        cout << "FUSER-OPTIMAL: the size of the search space is 2^" << mask.size() << "!" << endl;
    }

    fuse(dag, edges2explore, mask, 0, false);
    fuse(dag, edges2explore, mask, 0, true);
    fill_kernels(best_dag, bhir.kernel_list);
}

<commit_msg>bhir: fixed bug in the optimal fuser<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium 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 3
of the License, or (at your option) any later version.

Bohrium 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 Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/
#include <bh.h>
#include <bh_dag.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <boost/foreach.hpp>
#include <boost/graph/topological_sort.hpp>
#include <vector>
#include <map>
#include <iterator>

#define VERBOSE

using namespace std;
using namespace boost;
using namespace bohrium::dag;

pair<int64_t,bool> fuse_mask(int64_t best_cost, const vector<EdgeW> &edges2explore,
                             const GraphDW graph, const vector<bool> &mask, GraphD &dag)
{
    bool fusibility=true;
    vector<EdgeW> edges2merge;
    unsigned int i=0;
    BOOST_FOREACH(const EdgeW &e, edges2explore)
    {
        if(mask[i++])
        {
            edges2merge.push_back(e);
        }
    }

    //Help function to find the new location
    struct find_new_location
    {
        Vertex operator()(map<Vertex, Vertex> &loc_map, Vertex v)
        {
            Vertex v_mapped = loc_map[v];
            if(v_mapped == v)
                return v;
            else
                return (*this)(loc_map, v_mapped);
        }
    }find_loc;

    //'loc_map' maps a vertex before the merge to the corresponding vertex after the merge
    map<Vertex, Vertex> loc_map;
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        loc_map[v] = v;
    }

    BOOST_FOREACH(const EdgeW &e, edges2merge)
    {
        Vertex v1 = find_loc(loc_map, source(e, graph.bglW()));
        Vertex v2 = find_loc(loc_map, target(e, graph.bglW()));
        loc_map[v1] = v2;
    }

    map<Vertex, bh_ir_kernel> new_vertices;
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        if(loc_map[v] == v)
            new_vertices[v] = bh_ir_kernel();
    }

    vector<Vertex> topological_order;
    topological_sort(dag, back_inserter(topological_order));
    BOOST_REVERSE_FOREACH(Vertex vertex, topological_order)
    {
        Vertex v = find_loc(loc_map, vertex);
        bh_ir_kernel &k = new_vertices.at(v);
        BOOST_FOREACH(const bh_instruction &i, dag[vertex].instr_list())
        {
            if(not k.fusible(i))
                fusibility = false;
            k.add_instr(i);
        }
    }

    int64_t cost=0;
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        if(loc_map[v] == v)
            cost += new_vertices[v].cost();
    }

    if(cost >= best_cost or not fusibility)
        return make_pair(cost,fusibility);

    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        Vertex loc_v = loc_map[v];
        if(loc_v == v)
        {
            dag[v] = new_vertices[v];
        }
        else//Lets merge 'v' into 'loc_v'
        {
            BOOST_FOREACH(Vertex a, adjacent_vertices(v, dag))
            {
                if(a != loc_v)
                    add_edge(loc_v, a, dag);
            }
            BOOST_FOREACH(Vertex a, inv_adjacent_vertices(v, dag))
            {
                if(a != loc_v)
                    add_edge(a, loc_v, dag);
            }
            clear_vertex(v, dag);
            dag[v] = bh_ir_kernel();
        }
    }
    if(cycles(dag))
    {
        return make_pair(cost,false);
    }

    if(cost != (int64_t)dag_cost(dag))
    {
        cout << "cost: " << cost << ", dag_cost: " << dag_cost(dag) << endl;
        GraphDW tmp(dag);
        pprint(tmp, "what.dot");
        assert(1 == 2);
    }

    return make_pair(cost,true);
}
#ifdef VERBOSE
double  purge_count=0;
uint64_t explore_count=0;
int fuser_count=0;
#endif
int64_t best_cost;
int64_t one_cost;
GraphD best_dag;
void fuse(const GraphDW &dag, const vector<EdgeW> &edges2explore,
          vector<bool> mask, unsigned int offset, bool merge_next)
{
    if(not merge_next)
    {
        GraphD new_dag(dag.bglD());
        mask[offset] = merge_next;
        bool fusibility;
        int64_t cost;
        tie(cost, fusibility) = fuse_mask(best_cost, edges2explore, dag, mask, new_dag);

#ifdef VERBOSE
        if(explore_count%1000 == 0)
        {
            cout << "[" << explore_count << "] " << "purge count: " << purge_count << " / " << pow(2.0,mask.size()) << endl;
            cout << "cost: " << cost << ", best_cost: " << best_cost << ", fusibility: " << fusibility << endl;
        }
        ++explore_count;
#endif

        if(cost >= best_cost)
        {
#ifdef VERBOSE
            purge_count += pow(2.0, mask.size()-offset-1);
#endif
            return;
        }
        if(fusibility)
        {
            best_cost = cost;
            best_dag = new_dag;
#ifdef VERBOSE
            std::stringstream ss;
            ss << "new_best_dag-" << fuser_count << "-" << dag_cost(new_dag) << ".dot";
            printf("write file: %s\n", ss.str().c_str());
            pprint(GraphDW(new_dag), ss.str().c_str());
            purge_count += pow(2.0, mask.size()-offset-1);
#endif
            return;
        }
    }
    if(offset+1 < mask.size())
    {
        fuse(dag, edges2explore, mask, offset+1, false);
        fuse(dag, edges2explore, mask, offset+1, true);
    }
}

void fuser(bh_ir &bhir)
{
#ifdef VERBOSE
    ++fuser_count;
#endif

    GraphDW dag;
    from_bhir(bhir, dag);
    fuse_gentle(dag);
    dag.transitive_reduction();

    //The list of edges that we should try to merge
    vector<EdgeW> edges2explore;
    BOOST_FOREACH(const EdgeW &e, edges(dag.bglW()))
    {
        edges2explore.push_back(e);
    }
    sort_weights(dag.bglW(), edges2explore);
    //reverse(edges2explore.begin(), edges2explore.end());

    if(edges2explore.size() == 0)
    {
        fill_kernels(dag.bglD(), bhir.kernel_list);
        return;
    }

    //First we check the trivial case where all kernels are merged
    vector<bool> mask(edges2explore.size(), true);
    {
        GraphD new_dag(dag.bglD());
        bool fuse;
        tie(one_cost, fuse) = fuse_mask(numeric_limits<int64_t>::max(), edges2explore, dag, mask, new_dag);
        if(fuse)
        {
            fill_kernels(new_dag, bhir.kernel_list);
            return;
        }
    }

    //Then we use the greedy algorithm to find a good initial guess
    {
        GraphDW new_dag(dag);
        fuse_greedy(new_dag);
        best_dag = new_dag.bglD();
        best_cost = dag_cost(best_dag);
    }

    if(mask.size() > 100)
    {
        cout << "FUSER-OPTIMAL: ABORT the size of the search space is too large: 2^";
        cout << mask.size() << "!" << endl;
        fill_kernels(best_dag, bhir.kernel_list);
        return;
    }
    else if(mask.size() > 10)
    {
        cout << "FUSER-OPTIMAL: the size of the search space is 2^" << mask.size() << "!" << endl;
    }

    fuse(dag, edges2explore, mask, 0, false);
    fuse(dag, edges2explore, mask, 0, true);
    fill_kernels(best_dag, bhir.kernel_list);
}

<|endoftext|>


<commit_before>#include "control.hpp"
#include "model/ply.hpp"

#include <GLFW/glfw3.h>
#include <GL/glu.h>
#include <SOIL/SOIL.h>

#include <sstream>
#include <cmath>

#include "omp.h"
#include <chrono>
#include <memory>

namespace Control {
	void control::init(std::atomic_bool &alive) {
		//using namespace Util;
		// Task 1: view before model (splash)
		using namespace View;
		glfwSetInputMode(viewer.win, GLFW_STICKY_KEYS, 1);
		glfwMakeContextCurrent(viewer.win);

		// Task 2: wavefront obj model loading
		using namespace Model;
		obj_t object;
		auto status = obj_t::load(this -> mpath, object);
		if(status != obj_t::e_ok) {
			std::cout << "The model failed to load." << std::endl;
			return;
		}

		glGenBuffers(1, &viewer.ids[view::e_id_vbuf]);
		glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
		glBufferData(GL_ARRAY_BUFFER, object.floats.size(),
				(void*)(&object.floats[0]), GL_STATIC_DRAW);

		glGenBuffers(1, &viewer.ids[view::e_id_ibuf]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
				viewer.ids[view::e_id_ibuf]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, object.ints.size(),
				(void*)(&object.ints[0]), GL_STATIC_DRAW);
		viewer.nTriangles = object.ints.size()/3;
		glUseProgram(viewer.ids[view::e_id_prog]);

		/*
		// Task 2: model loading
		using namespace Model::Ply;
 		Header model(this -> mpath);
 		if(model.status) {
			std::cout << model.statusContext << std::endl;
			return;
		}
		auto start = begin(model.elements),
				 stop = end(model.elements);
		auto vertices = std::find_if(start, stop,
			[](Element const& el) -> bool {
				// TODO Change behavior based on the number of elements
				return el.name == "vertex" && !el.has_list;
		}), indices = std::find_if(start, stop,
			[](Element const& el) -> bool {
				int sz = el.properties.size();
				return el.name == "face"
					&& (el.has_list ? sz==1 : sz==3);
		});
		if(vertices == stop || indices == stop) {
			std::cout << "The model is valid, but does not match "
				"the anticipated structure." << std::endl;
			return;
		Task 3: view after model
		glGenBuffers(1, &viewer.ids[view::e_id_vbuf]);
		glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
		glBufferData(GL_ARRAY_BUFFER, vertices->data.size(),
				(void*)(&vertices->data[0]), GL_STATIC_DRAW);

		glGenBuffers(1, &viewer.ids[view::e_id_ibuf]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
				viewer.ids[view::e_id_ibuf]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices->data.size(),
				(void*)(&indices->data[0]), GL_STATIC_DRAW);
		viewer.nTriangles = indices -> instances;
		glUseProgram(viewer.ids[view::e_id_prog]);*/
	}

	void control::poll(std::atomic_bool &alive) {
		std::ostringstream oss;
		if(alive)
			viewer.poll(alive);
		if(alive) {
			if(glfwGetKey(viewer.win, GLFW_KEY_ESCAPE) == GLFW_PRESS)
				alive = false;
			int nButtons;
			const uint8_t *buttons =
				glfwGetJoystickButtons(GLFW_JOYSTICK_1, &nButtons);
			bool once = false;
			for(int i = 0; i < nButtons; i++) {
				bool pressed = buttons[i] == GLFW_PRESS;
				if(once && pressed) oss << ", " << i;
				if(!once && pressed) {
					once = true;
					oss << i;
				}
				if(i==8 && pressed)
					alive = false;
			}
			if(once)
				std::cout << "\nPressed: " << oss.str() << std::endl;

			once = false;
			int nAxes;
			const GLfloat *axes =
				glfwGetJoystickAxes(GLFW_JOYSTICK_1, &nAxes);
			for(int i = 0; i < nAxes; i++) {
				if(i == 0) {
					viewer.theta = axes[i]*2 + 1.5;
				} else if(i == 1) {
					viewer.phi = axes[i];
				}
				//std::cout << "Axis " << i << " = " << axes[i] << std::endl;
			}
			//endl(std::cout);
		}
	}

	void control::run(std::atomic_bool &alive) {
		using namespace Model::Ply;
		auto delay = std::chrono::milliseconds(150);

		int frame = 0, dFrames = 0, fps = 0;
		auto kill = [&alive] {alive = false;};
		double t1 = glfwGetTime(), t2;
		while(true) {
			poll(alive);
			if(alive) viewer.run(alive);
			t2 = glfwGetTime() - t1;
			frame++;
			dFrames++;
			if(t2 > 1.0) {
				std::cout << "FPS: " << int(dFrames/t2) << std::endl;
				t1 += t2;
				dFrames = 0;
			}
			if(!alive) break;
		}
	}

	control::control(std::atomic_bool &alive, const char *mpath,
			const char *vert, const char *frag):
		supertask(), mpath(mpath), viewer(alive, vert, frag) {}
}
<commit_msg>Changed path back to icosahedron; TODO parse other formats of indices (a, a/b, a//b, a/b/c)<commit_after>#include "control.hpp"
#include "model/ply.hpp"

#include <GLFW/glfw3.h>
#include <GL/glu.h>
#include <SOIL/SOIL.h>

#include <sstream>
#include <cmath>

#include "omp.h"
#include <chrono>
#include <memory>

namespace Control {
	void control::init(std::atomic_bool &alive) {
		//using namespace Util;
		// Task 1: view before model (splash)
		using namespace View;
		glfwSetInputMode(viewer.win, GLFW_STICKY_KEYS, 1);
		glfwMakeContextCurrent(viewer.win);

		// Task 2: wavefront obj model loading
		using namespace Model;
		obj_t object;
		std::cout << "Loading model " << this -> mpath << std::endl;
		auto status = obj_t::load(this -> mpath, object);
		if(status != obj_t::e_ok) {
			std::cout << "The model failed to load." << std::endl;
			return;
		}

		glGenBuffers(1, &viewer.ids[view::e_id_vbuf]);
		glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
		glBufferData(GL_ARRAY_BUFFER, object.floats.size(),
				(void*)(&object.floats[0]), GL_STATIC_DRAW);

		glGenBuffers(1, &viewer.ids[view::e_id_ibuf]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
				viewer.ids[view::e_id_ibuf]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, object.ints.size(),
				(void*)(&object.ints[0]), GL_STATIC_DRAW);
		viewer.nTriangles = object.ints.size()/3;
		glUseProgram(viewer.ids[view::e_id_prog]);

		/*
		// Task 2: model loading
		using namespace Model::Ply;
 		Header model(this -> mpath);
 		if(model.status) {
			std::cout << model.statusContext << std::endl;
			return;
		}
		auto start = begin(model.elements),
				 stop = end(model.elements);
		auto vertices = std::find_if(start, stop,
			[](Element const& el) -> bool {
				// TODO Change behavior based on the number of elements
				return el.name == "vertex" && !el.has_list;
		}), indices = std::find_if(start, stop,
			[](Element const& el) -> bool {
				int sz = el.properties.size();
				return el.name == "face"
					&& (el.has_list ? sz==1 : sz==3);
		});
		if(vertices == stop || indices == stop) {
			std::cout << "The model is valid, but does not match "
				"the anticipated structure." << std::endl;
			return;
		Task 3: view after model
		glGenBuffers(1, &viewer.ids[view::e_id_vbuf]);
		glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
		glBufferData(GL_ARRAY_BUFFER, vertices->data.size(),
				(void*)(&vertices->data[0]), GL_STATIC_DRAW);

		glGenBuffers(1, &viewer.ids[view::e_id_ibuf]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
				viewer.ids[view::e_id_ibuf]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices->data.size(),
				(void*)(&indices->data[0]), GL_STATIC_DRAW);
		viewer.nTriangles = indices -> instances;
		glUseProgram(viewer.ids[view::e_id_prog]);*/
	}

	void control::poll(std::atomic_bool &alive) {
		std::ostringstream oss;
		if(alive)
			viewer.poll(alive);
		if(alive) {
			if(glfwGetKey(viewer.win, GLFW_KEY_ESCAPE) == GLFW_PRESS)
				alive = false;
			int nButtons;
			const uint8_t *buttons =
				glfwGetJoystickButtons(GLFW_JOYSTICK_1, &nButtons);
			bool once = false;
			for(int i = 0; i < nButtons; i++) {
				bool pressed = buttons[i] == GLFW_PRESS;
				if(once && pressed) oss << ", " << i;
				if(!once && pressed) {
					once = true;
					oss << i;
				}
				if(i==8 && pressed)
					alive = false;
			}
			if(once)
				std::cout << "\nPressed: " << oss.str() << std::endl;

			once = false;
			int nAxes;
			const GLfloat *axes =
				glfwGetJoystickAxes(GLFW_JOYSTICK_1, &nAxes);
			for(int i = 0; i < nAxes; i++) {
				if(i == 0) {
					viewer.theta = axes[i]*2 + 1.5;
				} else if(i == 1) {
					viewer.phi = axes[i];
				}
				//std::cout << "Axis " << i << " = " << axes[i] << std::endl;
			}
			//endl(std::cout);
		}
	}

	void control::run(std::atomic_bool &alive) {
		using namespace Model::Ply;
		auto delay = std::chrono::milliseconds(150);

		int frame = 0, dFrames = 0, fps = 0;
		auto kill = [&alive] {alive = false;};
		double t1 = glfwGetTime(), t2;
		while(true) {
			poll(alive);
			if(alive) viewer.run(alive);
			t2 = glfwGetTime() - t1;
			frame++;
			dFrames++;
			if(t2 > 1.0) {
				std::cout << "FPS: " << int(dFrames/t2) << std::endl;
				t1 += t2;
				dFrames = 0;
			}
			if(!alive) break;
		}
	}

	control::control(std::atomic_bool &alive, const char *mpath,
			const char *vert, const char *frag):
		supertask(), mpath(mpath), viewer(alive, vert, frag) {}
}
<|endoftext|>


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

#include "base/cpu.h"

#include "testing/gtest/include/gtest/gtest.h"

// Tests whether we can run extended instructions represented by the CPU
// information. This test actually executes some extended instructions (such as
// MMX, SSE, etc.) supported by the CPU and sees we can run them without
// "undefined instruction" exceptions. That is, this test succeeds when this
// test finishes without a crash.
TEST(CPU, RunExtendedInstructions) {
#if defined(ARCH_CPU_X86_FAMILY)
  // Retrieve the CPU information.
  base::CPU cpu;

#if defined(OS_WIN)
  ASSERT_TRUE(cpu.has_mmx());

  // Execute an MMX instruction.
  __asm emms;

  if (cpu.has_sse()) {
    // Execute an SSE instruction.
    __asm xorps xmm0, xmm0;
  }

  if (cpu.has_sse2()) {
    // Execute an SSE 2 instruction.
    __asm psrldq xmm0, 0;
  }

  if (cpu.has_sse3()) {
    // Execute an SSE 3 instruction.
    __asm addsubpd xmm0, xmm0;
  }

  if (cpu.has_ssse3()) {
    // Execute a Supplimental SSE 3 instruction.
    __asm psignb xmm0, xmm0;
  }

  if (cpu.has_sse41()) {
    // Execute an SSE 4.1 instruction.
    __asm pmuldq xmm0, xmm0;
  }

  if (cpu.has_sse42()) {
    // Execute an SSE 4.2 instruction.
    __asm crc32 eax, eax;
  }
#elif defined(OS_POSIX)
  ASSERT_TRUE(cpu.has_mmx());

  // Execute an MMX instruction.
  __asm__ __volatile__("emms\n" : : : "mm0");

  if (cpu.has_sse()) {
    // Execute an SSE instruction.
    __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0");
  }

  if (cpu.has_sse2()) {
    // Execute an SSE 2 instruction.
    __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0");
  }

  if (cpu.has_sse3()) {
    // Execute an SSE 3 instruction.
    __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0");
  }

  if (cpu.has_ssse3()) {
    // Execute a Supplimental SSE 3 instruction.
    __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0");
  }

  if (cpu.has_sse41()) {
    // Execute an SSE 4.1 instruction.
    __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0");
  }

  if (cpu.has_sse42()) {
    // Execute an SSE 4.2 instruction.
    __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax");
  }
#endif
#endif
}
<commit_msg>Prevent compiling cpu_unittest on i386. This change prevents compiling cpu_unittest on 32-bit GCC since some builders does not compile with SSE support.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/cpu.h"

#include "testing/gtest/include/gtest/gtest.h"

// Tests whether we can run extended instructions represented by the CPU
// information. This test actually executes some extended instructions (such as
// MMX, SSE, etc.) supported by the CPU and sees we can run them without
// "undefined instruction" exceptions. That is, this test succeeds when this
// test finishes without a crash.
TEST(CPU, RunExtendedInstructions) {
#if defined(ARCH_CPU_X86_FAMILY)
  // Retrieve the CPU information.
  base::CPU cpu;

#if defined(OS_WIN)
  ASSERT_TRUE(cpu.has_mmx());

  // Execute an MMX instruction.
  __asm emms;

  if (cpu.has_sse()) {
    // Execute an SSE instruction.
    __asm xorps xmm0, xmm0;
  }

  if (cpu.has_sse2()) {
    // Execute an SSE 2 instruction.
    __asm psrldq xmm0, 0;
  }

  if (cpu.has_sse3()) {
    // Execute an SSE 3 instruction.
    __asm addsubpd xmm0, xmm0;
  }

  if (cpu.has_ssse3()) {
    // Execute a Supplimental SSE 3 instruction.
    __asm psignb xmm0, xmm0;
  }

  if (cpu.has_sse41()) {
    // Execute an SSE 4.1 instruction.
    __asm pmuldq xmm0, xmm0;
  }

  if (cpu.has_sse42()) {
    // Execute an SSE 4.2 instruction.
    __asm crc32 eax, eax;
  }
#elif defined(OS_POSIX) || defined(__x86_64__)
  ASSERT_TRUE(cpu.has_mmx());

  // Execute an MMX instruction.
  __asm__ __volatile__("emms\n" : : : "mm0");

  if (cpu.has_sse()) {
    // Execute an SSE instruction.
    __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0");
  }

  if (cpu.has_sse2()) {
    // Execute an SSE 2 instruction.
    __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0");
  }

  if (cpu.has_sse3()) {
    // Execute an SSE 3 instruction.
    __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0");
  }

  if (cpu.has_ssse3()) {
    // Execute a Supplimental SSE 3 instruction.
    __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0");
  }

  if (cpu.has_sse41()) {
    // Execute an SSE 4.1 instruction.
    __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0");
  }

  if (cpu.has_sse42()) {
    // Execute an SSE 4.2 instruction.
    __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax");
  }
#endif
#endif
}
<|endoftext|>