<commit_before>#include <bts/blockchain/chain_interface.hpp>
#include <bts/blockchain/operation_factory.hpp>
#include <bts/blockchain/transaction_evaluation_state.hpp>

#include <bts/blockchain/fork_blocks.hpp>

namespace bts { namespace blockchain {

   transaction_evaluation_state::transaction_evaluation_state( const chain_interface_ptr& current_state, digest_type chain_id )
   :_current_state( current_state ),_chain_id(chain_id),_skip_signature_check(false)
   {
   }

   transaction_evaluation_state::~transaction_evaluation_state()
   {
   }

   void transaction_evaluation_state::reset()
   {
      signed_keys.clear();
      balance.clear();
      deposits.clear();
      withdraws.clear();
      net_delegate_votes.clear();
      required_deposits.clear();
      validation_error.reset();
   }

   bool transaction_evaluation_state::check_signature( const address& a )const
   {
      return  _skip_signature_check || signed_keys.find( a ) != signed_keys.end();
   }

   void transaction_evaluation_state::verify_delegate_id( account_id_type id )const
   {
      auto current_account = _current_state->get_account_record( id );
      if( !current_account ) FC_CAPTURE_AND_THROW( unknown_account_id, (id) );
      if( !current_account->is_delegate() ) FC_CAPTURE_AND_THROW( not_a_delegate, (id) );
   }

   void transaction_evaluation_state::add_required_deposit( const address& owner_key, const asset& amount )
   {
      FC_ASSERT( trx.delegate_slate_id );
      balance_id_type balance_id = withdraw_condition(
                                       withdraw_with_signature( owner_key ),
                                       amount.asset_id, *trx.delegate_slate_id ).get_address();

      auto itr = required_deposits.find( balance_id );
      if( itr == required_deposits.end() )
      {
         required_deposits[balance_id] = amount;
      }
      else
      {
         required_deposits[balance_id] += amount;
      }
   }

   void transaction_evaluation_state::update_delegate_votes()
   {
      auto asset_rec = _current_state->get_asset_record( asset_id_type() );

      for( const auto& del_vote : net_delegate_votes )
      {
         auto del_rec = _current_state->get_account_record( del_vote.first );
         FC_ASSERT( !!del_rec );
         del_rec->adjust_votes_for( del_vote.second.votes_for );

         _current_state->store_account_record( *del_rec );
      }
   }

   void transaction_evaluation_state::validate_required_fee()
   { try {
      asset xts_fees;
      auto fee_itr = balance.find( 0 );
      if( fee_itr != balance.end() ) xts_fees += asset( fee_itr->second, 0);

      xts_fees += alt_fees_paid;

      if( required_fees > xts_fees )
      {
         FC_CAPTURE_AND_THROW( insufficient_fee, (required_fees)(alt_fees_paid)(xts_fees)  )
      }
   } FC_RETHROW_EXCEPTIONS( warn, "" ) }

   /**
    *  Process all fees and update the asset records.
    */
   void transaction_evaluation_state::post_evaluate()
   { try {
      // NOTE:  this line was removed in favor of trusting delegates to set the required fees rather
      // than charging per byte. This allows the network to scale without hard fork.
      //
      // By removing this check I am reducing restrictions so the current blockchain should still validate
      if( _current_state->get_head_block_num() < BTS_BLOCKCHAIN_FORK_MARKET_BLOCK_NUM )
          required_fees += asset( _current_state->calculate_data_fee( fc::raw::pack_size( trx ) ), 0 );

      // Should this be here? We may not have fees in XTS now...
      balance[0]; // make sure we have something for this.
      for( const auto& fee : balance )
      {
         if( fee.second < 0 ) FC_CAPTURE_AND_THROW( negative_fee, (fee) );
         // if the fee is already in XTS or the fee balance is zero, move along...
         if( fee.first == 0 || fee.second == 0 )
           continue;

         // lowest ask is someone with XTS offered at a price of USD / XTS, fee.first
         // is an amount of USD which can be converted to price*USD XTS provided we
         // send lowest_ask.index.owner the USD
         omarket_order lowest_ask = _current_state->get_lowest_ask_record( fee.first, 0 );
         if( lowest_ask )
         {
            // fees paid in something other than XTS are discounted 50%
            alt_fees_paid += asset( fee.second/2, fee.first ) * lowest_ask->market_index.order_price;
         }
      }

      for( const auto& fee : balance )
      {
         if( fee.second < 0 ) FC_CAPTURE_AND_THROW( negative_fee, (fee) );
         if( fee.second > 0 ) // if a fee was paid...
         {
            auto asset_record = _current_state->get_asset_record( fee.first );
            if( !asset_record )
              FC_CAPTURE_AND_THROW( unknown_asset_id, (fee.first) );

            asset_record->collected_fees += fee.second;
            // collecting fees should not decrease share supply.
            // asset_record->current_share_supply -= fee.second;
            _current_state->store_asset_record( *asset_record );
         }
      }

      for( const auto& required_deposit : required_deposits )
      {
         auto provided_itr = provided_deposits.find( required_deposit.first );

         if( provided_itr->second < required_deposit.second )
            FC_CAPTURE_AND_THROW( missing_deposit, (required_deposit) );
      }

   } FC_RETHROW_EXCEPTIONS( warn, "" ) }

   void transaction_evaluation_state::evaluate( const signed_transaction& trx_arg, bool skip_signature_check )
   { try {
      reset();
      _skip_signature_check = skip_signature_check;
      try {
        if( trx_arg.expiration < _current_state->now() )
        {
           auto expired_by_sec = (trx_arg.expiration - _current_state->now()).to_seconds();
           FC_CAPTURE_AND_THROW( expired_transaction, (trx_arg)(_current_state->now())(expired_by_sec) );
        }
        if( trx_arg.expiration > (_current_state->now() + BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC) )
           FC_CAPTURE_AND_THROW( invalid_transaction_expiration, (trx_arg)(_current_state->now()) );

        /**
         * Removing transaction size limit from chain validation rules.
         *
         * Note: this is to give delegates maximum flexibility without having to
         * introduce hard forks to support larger transaction sizes.
         */
        if( _current_state->get_head_block_num() < BTS_BLOCKCHAIN_FORK_MARKET_BLOCK_NUM )
        {
            auto trx_size = fc::raw::pack_size( trx_arg );
            if( trx_size > 1280 )
               FC_CAPTURE_AND_THROW( oversized_transaction, (trx_size ) );
        }

        auto trx_id = trx_arg.id();

        if( _current_state->is_known_transaction( trx_id ) )
           FC_CAPTURE_AND_THROW( duplicate_transaction, (trx_id) );

        trx = trx_arg;
        if( !_skip_signature_check )
        {
           auto digest = trx_arg.digest( _chain_id );
           for( const auto& sig : trx.signatures )
           {
              auto key = fc::ecc::public_key( sig, digest ).serialize();
              signed_keys.insert( address(key) );
              signed_keys.insert( address(pts_address(key,false,56) ) );
              signed_keys.insert( address(pts_address(key,true,56) )  );
              signed_keys.insert( address(pts_address(key,false,0) )  );
              signed_keys.insert( address(pts_address(key,true,0) )   );
           }
        }
        for( const auto& op : trx.operations )
        {
           evaluate_operation( op );
        }
        post_evaluate();
        validate_required_fee();
        update_delegate_votes();
      }
      catch ( const fc::exception& e )
      {
         validation_error = e;
         throw;
      }
   } FC_RETHROW_EXCEPTIONS( warn, "", ("trx",trx_arg) ) }

   void transaction_evaluation_state::evaluate_operation( const operation& op )
   {
      operation_factory::instance().evaluate( *this, op );
   }

   void transaction_evaluation_state::adjust_vote( slate_id_type slate_id, share_type amount )
   {
      if( slate_id )
      {
         auto slate = _current_state->get_delegate_slate( slate_id );
         if( !slate ) FC_CAPTURE_AND_THROW( unknown_delegate_slate, (slate_id) );
         for( const auto& delegate_id : slate->supported_delegates )
         {
            if( BTS_BLOCKCHAIN_ENABLE_NEGATIVE_VOTES && delegate_id < signed_int(0) )
               net_delegate_votes[abs(delegate_id)].votes_for -= amount;
            else
               net_delegate_votes[abs(delegate_id)].votes_for += amount;
         }
      }
   }

   share_type transaction_evaluation_state::get_fees( asset_id_type id )const
   {
      auto itr = balance.find(id);
      if( itr != balance.end() )
         return itr->second;
      return 0;
   }

   /**
    *
    */
   void transaction_evaluation_state::sub_balance( const balance_id_type& balance_id, const asset& amount )
   {
      auto provided_deposit_itr = provided_deposits.find( balance_id );
      if( provided_deposit_itr == provided_deposits.end() )
      {
         provided_deposits[balance_id] = amount;
      }
      else
      {
         provided_deposit_itr->second += amount;
      }

      auto deposit_itr = deposits.find(amount.asset_id);
      if( deposit_itr == deposits.end()  )
      {
         deposits[amount.asset_id] = amount;
      }
      else
      {
         deposit_itr->second += amount;
      }

      auto balance_itr = balance.find(amount.asset_id);
      if( balance_itr != balance.end()  )
      {
          balance_itr->second -= amount.amount;
      }
      else
      {
          balance[amount.asset_id] =  -amount.amount;
      }
   }

   void transaction_evaluation_state::add_balance( const asset& amount )
   {
      auto withdraw_itr = withdraws.find( amount.asset_id );
      if( withdraw_itr == withdraws.end() )
         withdraws[amount.asset_id] = amount;
      else
         withdraw_itr->second += amount;

      auto balance_itr = balance.find( amount.asset_id );
      if( balance_itr == balance.end() )
         balance[amount.asset_id] = amount.amount;
      else
         balance_itr->second += amount.amount;
   }

   /**
    *  Throws if the asset is not known to the blockchain.
    */
   void transaction_evaluation_state::validate_asset( const asset& asset_to_validate )const
   {
      auto asset_rec = _current_state->get_asset_record( asset_to_validate.asset_id );
      if( NOT asset_rec )
         FC_CAPTURE_AND_THROW( unknown_asset_id, (asset_to_validate) );
   }

} } // bts::blockchain
<commit_msg>Fix build<commit_after>#include <bts/blockchain/chain_interface.hpp>
#include <bts/blockchain/operation_factory.hpp>
#include <bts/blockchain/transaction_evaluation_state.hpp>

#include <bts/blockchain/fork_blocks.hpp>

namespace bts { namespace blockchain {

   transaction_evaluation_state::transaction_evaluation_state( const chain_interface_ptr& current_state, digest_type chain_id )
   :_current_state( current_state ),_chain_id(chain_id),_skip_signature_check(false)
   {
   }

   transaction_evaluation_state::~transaction_evaluation_state()
   {
   }

   void transaction_evaluation_state::reset()
   {
      signed_keys.clear();
      balance.clear();
      deposits.clear();
      withdraws.clear();
      net_delegate_votes.clear();
      required_deposits.clear();
      validation_error.reset();
   }

   bool transaction_evaluation_state::check_signature( const address& a )const
   {
      return  _skip_signature_check || signed_keys.find( a ) != signed_keys.end();
   }

   void transaction_evaluation_state::verify_delegate_id( account_id_type id )const
   {
      auto current_account = _current_state->get_account_record( id );
      if( !current_account ) FC_CAPTURE_AND_THROW( unknown_account_id, (id) );
      if( !current_account->is_delegate() ) FC_CAPTURE_AND_THROW( not_a_delegate, (id) );
   }

   void transaction_evaluation_state::add_required_deposit( const address& owner_key, const asset& amount )
   {
      FC_ASSERT( trx.delegate_slate_id );
      balance_id_type balance_id = withdraw_condition(
                                       withdraw_with_signature( owner_key ),
                                       amount.asset_id, *trx.delegate_slate_id ).get_address();

      auto itr = required_deposits.find( balance_id );
      if( itr == required_deposits.end() )
      {
         required_deposits[balance_id] = amount;
      }
      else
      {
         required_deposits[balance_id] += amount;
      }
   }

   void transaction_evaluation_state::update_delegate_votes()
   {
      auto asset_rec = _current_state->get_asset_record( asset_id_type() );

      for( const auto& del_vote : net_delegate_votes )
      {
         auto del_rec = _current_state->get_account_record( del_vote.first );
         FC_ASSERT( !!del_rec );
         del_rec->adjust_votes_for( del_vote.second.votes_for );

         _current_state->store_account_record( *del_rec );
      }
   }

   void transaction_evaluation_state::validate_required_fee()
   { try {
      asset xts_fees;
      auto fee_itr = balance.find( 0 );
      if( fee_itr != balance.end() ) xts_fees += asset( fee_itr->second, 0);

      xts_fees += alt_fees_paid;

      if( required_fees > xts_fees )
      {
         FC_CAPTURE_AND_THROW( insufficient_fee, (required_fees)(alt_fees_paid)(xts_fees)  )
      }
   } FC_RETHROW_EXCEPTIONS( warn, "" ) }

   /**
    *  Process all fees and update the asset records.
    */
   void transaction_evaluation_state::post_evaluate()
   { try {
      // Should this be here? We may not have fees in XTS now...
      balance[0]; // make sure we have something for this.
      for( const auto& fee : balance )
      {
         if( fee.second < 0 ) FC_CAPTURE_AND_THROW( negative_fee, (fee) );
         // if the fee is already in XTS or the fee balance is zero, move along...
         if( fee.first == 0 || fee.second == 0 )
           continue;

         // lowest ask is someone with XTS offered at a price of USD / XTS, fee.first
         // is an amount of USD which can be converted to price*USD XTS provided we
         // send lowest_ask.index.owner the USD
         omarket_order lowest_ask = _current_state->get_lowest_ask_record( fee.first, 0 );
         if( lowest_ask )
         {
            // fees paid in something other than XTS are discounted 50%
            alt_fees_paid += asset( fee.second/2, fee.first ) * lowest_ask->market_index.order_price;
         }
      }

      for( const auto& fee : balance )
      {
         if( fee.second < 0 ) FC_CAPTURE_AND_THROW( negative_fee, (fee) );
         if( fee.second > 0 ) // if a fee was paid...
         {
            auto asset_record = _current_state->get_asset_record( fee.first );
            if( !asset_record )
              FC_CAPTURE_AND_THROW( unknown_asset_id, (fee.first) );

            asset_record->collected_fees += fee.second;
            // collecting fees should not decrease share supply.
            // asset_record->current_share_supply -= fee.second;
            _current_state->store_asset_record( *asset_record );
         }
      }

      for( const auto& required_deposit : required_deposits )
      {
         auto provided_itr = provided_deposits.find( required_deposit.first );

         if( provided_itr->second < required_deposit.second )
            FC_CAPTURE_AND_THROW( missing_deposit, (required_deposit) );
      }

   } FC_RETHROW_EXCEPTIONS( warn, "" ) }

   void transaction_evaluation_state::evaluate( const signed_transaction& trx_arg, bool skip_signature_check )
   { try {
      reset();
      _skip_signature_check = skip_signature_check;
      try {
        if( trx_arg.expiration < _current_state->now() )
        {
           auto expired_by_sec = (trx_arg.expiration - _current_state->now()).to_seconds();
           FC_CAPTURE_AND_THROW( expired_transaction, (trx_arg)(_current_state->now())(expired_by_sec) );
        }
        if( trx_arg.expiration > (_current_state->now() + BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC) )
           FC_CAPTURE_AND_THROW( invalid_transaction_expiration, (trx_arg)(_current_state->now()) );

        /**
         * Removing transaction size limit from chain validation rules.
         *
         * Note: this is to give delegates maximum flexibility without having to
         * introduce hard forks to support larger transaction sizes.
         */
        if( _current_state->get_head_block_num() < BTS_BLOCKCHAIN_FORK_MARKET_BLOCK_NUM )
        {
            auto trx_size = fc::raw::pack_size( trx_arg );
            if( trx_size > 1280 )
               FC_CAPTURE_AND_THROW( oversized_transaction, (trx_size ) );
        }

        auto trx_id = trx_arg.id();

        if( _current_state->is_known_transaction( trx_id ) )
           FC_CAPTURE_AND_THROW( duplicate_transaction, (trx_id) );

        trx = trx_arg;
        if( !_skip_signature_check )
        {
           auto digest = trx_arg.digest( _chain_id );
           for( const auto& sig : trx.signatures )
           {
              auto key = fc::ecc::public_key( sig, digest ).serialize();
              signed_keys.insert( address(key) );
              signed_keys.insert( address(pts_address(key,false,56) ) );
              signed_keys.insert( address(pts_address(key,true,56) )  );
              signed_keys.insert( address(pts_address(key,false,0) )  );
              signed_keys.insert( address(pts_address(key,true,0) )   );
           }
        }
        for( const auto& op : trx.operations )
        {
           evaluate_operation( op );
        }
        post_evaluate();
        validate_required_fee();
        update_delegate_votes();
      }
      catch ( const fc::exception& e )
      {
         validation_error = e;
         throw;
      }
   } FC_RETHROW_EXCEPTIONS( warn, "", ("trx",trx_arg) ) }

   void transaction_evaluation_state::evaluate_operation( const operation& op )
   {
      operation_factory::instance().evaluate( *this, op );
   }

   void transaction_evaluation_state::adjust_vote( slate_id_type slate_id, share_type amount )
   {
      if( slate_id )
      {
         auto slate = _current_state->get_delegate_slate( slate_id );
         if( !slate ) FC_CAPTURE_AND_THROW( unknown_delegate_slate, (slate_id) );
         for( const auto& delegate_id : slate->supported_delegates )
         {
            if( BTS_BLOCKCHAIN_ENABLE_NEGATIVE_VOTES && delegate_id < signed_int(0) )
               net_delegate_votes[abs(delegate_id)].votes_for -= amount;
            else
               net_delegate_votes[abs(delegate_id)].votes_for += amount;
         }
      }
   }

   share_type transaction_evaluation_state::get_fees( asset_id_type id )const
   {
      auto itr = balance.find(id);
      if( itr != balance.end() )
         return itr->second;
      return 0;
   }

   /**
    *
    */
   void transaction_evaluation_state::sub_balance( const balance_id_type& balance_id, const asset& amount )
   {
      auto provided_deposit_itr = provided_deposits.find( balance_id );
      if( provided_deposit_itr == provided_deposits.end() )
      {
         provided_deposits[balance_id] = amount;
      }
      else
      {
         provided_deposit_itr->second += amount;
      }

      auto deposit_itr = deposits.find(amount.asset_id);
      if( deposit_itr == deposits.end()  )
      {
         deposits[amount.asset_id] = amount;
      }
      else
      {
         deposit_itr->second += amount;
      }

      auto balance_itr = balance.find(amount.asset_id);
      if( balance_itr != balance.end()  )
      {
          balance_itr->second -= amount.amount;
      }
      else
      {
          balance[amount.asset_id] =  -amount.amount;
      }
   }

   void transaction_evaluation_state::add_balance( const asset& amount )
   {
      auto withdraw_itr = withdraws.find( amount.asset_id );
      if( withdraw_itr == withdraws.end() )
         withdraws[amount.asset_id] = amount;
      else
         withdraw_itr->second += amount;

      auto balance_itr = balance.find( amount.asset_id );
      if( balance_itr == balance.end() )
         balance[amount.asset_id] = amount.amount;
      else
         balance_itr->second += amount.amount;
   }

   /**
    *  Throws if the asset is not known to the blockchain.
    */
   void transaction_evaluation_state::validate_asset( const asset& asset_to_validate )const
   {
      auto asset_rec = _current_state->get_asset_record( asset_to_validate.asset_id );
      if( NOT asset_rec )
         FC_CAPTURE_AND_THROW( unknown_asset_id, (asset_to_validate) );
   }

} } // bts::blockchain
<|endoftext|>


<commit_before>#include "IMMHandler.h"

#include <cstdlib>
#include <sstream>
#include <unistd.h>
#include <iostream>
#include <utility>
#include <folly/futures/Future.h>
#include <thrift/lib/cpp2/async/HeaderClientChannel.h>
#include <thrift/lib/cpp2/server/ThriftServer.h>
#include <thrift/lib/cpp2/async/HeaderClientChannel.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>

using namespace std;
using namespace folly;
using namespace apache::thrift;
using namespace apache::thrift::async;
using namespace cv;
using namespace mongo;

using std::cout;
using std::endl;
using std::string;
using std::unique_ptr;
using std::shared_ptr;
using std::getenv;

// cout lock.
std::mutex cout_lock_cpp;

namespace cpp2 {
IMMHandler::IMMHandler() {
		// Initialize MongoDB C++ driver.
		client::initialize();
		string mongo_addr;
		try {
				if (const char* env_p = getenv("MONGO_PORT_27017_TCP_ADDR")) {
					print("MongoDB: " << env_p);
					mongo_addr = env_p;
				} else {
					print("MongoDB: localhost");
					mongo_addr = "localhost";
				}
				conn.connect(mongo_addr);
				print("Connection is ok");
		} catch (const DBException &e) {
				print("Caught " << e.what());
		}
}

folly::Future<folly::Unit> IMMHandler::future_create
(unique_ptr<string> LUCID, unique_ptr< ::cpp2::QuerySpec> spec) {
	folly::MoveWrapper<folly::Promise<folly::Unit > > promise;
	auto future = promise->getFuture();
	promise->setValue(Unit{});
	return future;
}

folly::Future<folly::Unit> IMMHandler::future_learn
(unique_ptr<string> LUCID, unique_ptr< ::cpp2::QuerySpec> knowledge) {
	print("Learn");
	// Save LUCID and knowledge.
	string LUCID_save = *LUCID;
	::cpp2::QuerySpec knowledge_save = *knowledge;
	folly::MoveWrapper<folly::Promise<folly::Unit>> promise;
	auto future = promise->getFuture();
	// Async.
	folly::RequestEventBase::get()->runInEventBaseThread(
			[=]() mutable {
		try {
			// Go through all images and store their descriptors matices
			// into MongoDB GridFS.
			for (const QueryInput &query_input : knowledge_save.content) {
				for (int i = 0; i < (int) query_input.data.size(); ++i) {
					this->addImage(LUCID_save, query_input.tags[i],
							query_input.data[i]);
				}
			}
		} catch (Exception &e) {
			print(e.what());
		}
		promise->setValue(Unit{});
	}
	);
	return future;
}

folly::Future<unique_ptr<string>> IMMHandler::future_infer
(unique_ptr<string> LUCID, unique_ptr< ::cpp2::QuerySpec> query) {
	print("Infer");
	// Save LUCID and query.
	string LUCID_save = *LUCID;
	::cpp2::QuerySpec query_save = *query;
	folly::MoveWrapper<folly::Promise<unique_ptr<string>>> promise;
	auto future = promise->getFuture();
	// Async.
	folly::RequestEventBase::get()->runInEventBaseThread(
			[=]() mutable {
		try {
			if (query_save.content.empty()
					|| query_save.content[0].data.empty()) {
				throw runtime_error("IMM received empty infer query");
			}
			vector<unique_ptr<StoredImage>> images = getImages(LUCID_save);
			int best_index = Image::match(images,
					unique_ptr<QueryImage>(new QueryImage(
							move(Image::imageToMatObj(
									query_save.content[0].data[0])))));
			print("Result: " << images[best_index]->getLabel());
			// Check if the query needs to be further sent to QA.
			if (!query_save.content[0].tags.empty() &&
					query_save.content[0].tags[0] != "") {
				if (query_save.content.size() == 1
						|| query_save.content[1].data.empty()) {
					throw runtime_error("IMM wants to further request"
							" to QA but no text query");
				}
				vector<string> words;
				boost::split(words,query_save.content[0].tags[0],
						boost::is_any_of(", "), boost::token_compress_on);
				if (words.size() != 2) {
					throw runtime_error("tags[0] must have the following format"
							": localhost, 8083");
				}
				EventBase event_base;
				string QA_addr = "127.0.0.1"; // cannot be "localhost"
				int QA_port = stoi(words[1], nullptr);
				if (const char* env_p = getenv("QA_PORT_8083_TCP_ADDR")) {
					QA_addr = env_p;
				}
				print("Sending request to QA at " << QA_addr << " " << QA_port);
				std::shared_ptr<TAsyncSocket> socket(
						TAsyncSocket::newSocket(&event_base, QA_addr, QA_port));
				unique_ptr<HeaderClientChannel, DelayedDestruction::Destructor>
				channel(new HeaderClientChannel(socket));
				channel->setClientType(THRIFT_FRAMED_DEPRECATED);
				LucidaServiceAsyncClient client(std::move(channel));
				QuerySpec qa_query_spec;
				// Pop the front QueryInput from the current content
				// to get the new QuerySpec content for QA.
				qa_query_spec.content.assign(query_save.content.begin() + 1,
						query_save.content.end());
				// Append the result of IMM to the end of the text query.
				string IMM_result = images[best_index]->getLabel();
				qa_query_spec.content[0].data[0].append(" " + IMM_result);
				print("Query to QA " << qa_query_spec.content[0].data[0]);
				client.future_infer(LUCID_save, qa_query_spec).then(
						[promise, IMM_result](folly::Try<string>&& t) mutable {
					print("QA result: " << t.value());
					unique_ptr<string> result = folly::make_unique<std::string>(
							"IMM: " + IMM_result
							+ "; QA: " + t.value());
					promise->setValue(std::move(result)); // exit
				});
				event_base.loop();
			} else {
				promise->setValue(unique_ptr<string>(
						new string(images[best_index]->getLabel()))); // exit
			}
		} catch (Exception &e) {
			print(e.what());
			promise->setValue(unique_ptr<string>(new string())); // exit
		}
	}
	);
	return future;
}

void IMMHandler::addImage(const string &LUCID,
		const string &label, const string &data) {
	print("@@@ Label: " << label);
	print("@@@ Size: " << data.size());
	// Insert the descriptors matrix into MongoDB.
	string mat_str = Image::imageToMatString(data); // written to file system
	GridFS grid(conn, "lucida");
	BSONObj result = grid.storeFile(mat_str.c_str(), mat_str.size(),
			"opencv_" + LUCID + "/" + label);
}

vector<unique_ptr<StoredImage>> IMMHandler::getImages(const string &LUCID) {
	vector<unique_ptr<StoredImage>> rtn;
	// Retrieve all images of the user from MongoDB.
	auto_ptr<DBClientCursor> cursor = conn.query(
			"lucida.images_" + LUCID, BSONObj()); // retrieve desc, NOT data
	GridFS grid(conn, "lucida");
	while (cursor->more()) {
		string label = cursor->next().getStringField("label");
		ostringstream out;
		GridFile gf = grid.findFileByName("opencv_" + LUCID + "/" + label);
		if (!gf.exists()) {
			print("opencv_" + LUCID + "/" + label + " not found!");
			continue;
		}
		gf.write(out);
		rtn.push_back(unique_ptr<StoredImage>(new StoredImage(
				label,
				move(Image::matStringToMatObj(out.str())))));
	}
	return rtn;
}
}
<commit_msg>IMM: fix style<commit_after>#include "IMMHandler.h"

#include <cstdlib>
#include <sstream>
#include <unistd.h>
#include <iostream>
#include <utility>
#include <folly/futures/Future.h>
#include <thrift/lib/cpp2/async/HeaderClientChannel.h>
#include <thrift/lib/cpp2/server/ThriftServer.h>
#include <thrift/lib/cpp2/async/HeaderClientChannel.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>

using namespace std;
using namespace folly;
using namespace apache::thrift;
using namespace apache::thrift::async;
using namespace cv;
using namespace mongo;

using std::cout;
using std::endl;
using std::string;
using std::unique_ptr;
using std::shared_ptr;
using std::getenv;

// cout lock.
std::mutex cout_lock_cpp;

namespace cpp2 {
IMMHandler::IMMHandler() {
		// Initialize MongoDB C++ driver.
		client::initialize();
		string mongo_addr;
		try {
			if (const char* env_p = getenv("MONGO_PORT_27017_TCP_ADDR")) {
				print("MongoDB: " << env_p);
				mongo_addr = env_p;
			} else {
				print("MongoDB: localhost");
				mongo_addr = "localhost";
			}
			conn.connect(mongo_addr);
			print("Connection is ok");
		} catch (const DBException &e) {
			print("Caught " << e.what());
		}
}

folly::Future<folly::Unit> IMMHandler::future_create
(unique_ptr<string> LUCID, unique_ptr< ::cpp2::QuerySpec> spec) {
	folly::MoveWrapper<folly::Promise<folly::Unit > > promise;
	auto future = promise->getFuture();
	promise->setValue(Unit{});
	return future;
}

folly::Future<folly::Unit> IMMHandler::future_learn
(unique_ptr<string> LUCID, unique_ptr< ::cpp2::QuerySpec> knowledge) {
	print("Learn");
	// Save LUCID and knowledge.
	string LUCID_save = *LUCID;
	::cpp2::QuerySpec knowledge_save = *knowledge;
	folly::MoveWrapper<folly::Promise<folly::Unit>> promise;
	auto future = promise->getFuture();
	// Async.
	folly::RequestEventBase::get()->runInEventBaseThread(
			[=]() mutable {
		try {
			// Go through all images and store their descriptors matices
			// into MongoDB GridFS.
			for (const QueryInput &query_input : knowledge_save.content) {
				for (int i = 0; i < (int) query_input.data.size(); ++i) {
					this->addImage(LUCID_save, query_input.tags[i],
							query_input.data[i]);
				}
			}
		} catch (Exception &e) {
			print(e.what());
		}
		promise->setValue(Unit{});
	}
	);
	return future;
}

folly::Future<unique_ptr<string>> IMMHandler::future_infer
(unique_ptr<string> LUCID, unique_ptr< ::cpp2::QuerySpec> query) {
	print("Infer");
	// Save LUCID and query.
	string LUCID_save = *LUCID;
	::cpp2::QuerySpec query_save = *query;
	folly::MoveWrapper<folly::Promise<unique_ptr<string>>> promise;
	auto future = promise->getFuture();
	// Async.
	folly::RequestEventBase::get()->runInEventBaseThread(
			[=]() mutable {
		try {
			if (query_save.content.empty()
					|| query_save.content[0].data.empty()) {
				throw runtime_error("IMM received empty infer query");
			}
			vector<unique_ptr<StoredImage>> images = getImages(LUCID_save);
			int best_index = Image::match(images,
					unique_ptr<QueryImage>(new QueryImage(
							move(Image::imageToMatObj(
									query_save.content[0].data[0])))));
			print("Result: " << images[best_index]->getLabel());
			// Check if the query needs to be further sent to QA.
			if (!query_save.content[0].tags.empty() &&
					query_save.content[0].tags[0] != "") {
				if (query_save.content.size() == 1
						|| query_save.content[1].data.empty()) {
					throw runtime_error("IMM wants to further request"
							" to QA but no text query");
				}
				vector<string> words;
				boost::split(words,query_save.content[0].tags[0],
						boost::is_any_of(", "), boost::token_compress_on);
				if (words.size() != 2) {
					throw runtime_error("tags[0] must have the following format"
							": localhost, 8083");
				}
				EventBase event_base;
				string QA_addr = "127.0.0.1"; // cannot be "localhost"
				int QA_port = stoi(words[1], nullptr);
				if (const char* env_p = getenv("QA_PORT_8083_TCP_ADDR")) {
					QA_addr = env_p;
				}
				print("Sending request to QA at " << QA_addr << " " << QA_port);
				std::shared_ptr<TAsyncSocket> socket(
						TAsyncSocket::newSocket(&event_base, QA_addr, QA_port));
				unique_ptr<HeaderClientChannel, DelayedDestruction::Destructor>
				channel(new HeaderClientChannel(socket));
				channel->setClientType(THRIFT_FRAMED_DEPRECATED);
				LucidaServiceAsyncClient client(std::move(channel));
				QuerySpec qa_query_spec;
				// Pop the front QueryInput from the current content
				// to get the new QuerySpec content for QA.
				qa_query_spec.content.assign(query_save.content.begin() + 1,
						query_save.content.end());
				// Append the result of IMM to the end of the text query.
				string IMM_result = images[best_index]->getLabel();
				qa_query_spec.content[0].data[0].append(" " + IMM_result);
				print("Query to QA " << qa_query_spec.content[0].data[0]);
				client.future_infer(LUCID_save, qa_query_spec).then(
						[promise, IMM_result](folly::Try<string>&& t) mutable {
					print("QA result: " << t.value());
					unique_ptr<string> result = folly::make_unique<std::string>(
							"IMM: " + IMM_result
							+ "; QA: " + t.value());
					promise->setValue(std::move(result)); // exit
				});
				event_base.loop();
			} else {
				promise->setValue(unique_ptr<string>(
						new string(images[best_index]->getLabel()))); // exit
			}
		} catch (Exception &e) {
			print(e.what());
			promise->setValue(unique_ptr<string>(new string())); // exit
		}
	}
	);
	return future;
}

void IMMHandler::addImage(const string &LUCID,
		const string &label, const string &data) {
	print("@@@ Label: " << label);
	print("@@@ Size: " << data.size());
	// Insert the descriptors matrix into MongoDB.
	string mat_str = Image::imageToMatString(data); // written to file system
	GridFS grid(conn, "lucida");
	BSONObj result = grid.storeFile(mat_str.c_str(), mat_str.size(),
			"opencv_" + LUCID + "/" + label);
}

vector<unique_ptr<StoredImage>> IMMHandler::getImages(const string &LUCID) {
	vector<unique_ptr<StoredImage>> rtn;
	// Retrieve all images of the user from MongoDB.
	auto_ptr<DBClientCursor> cursor = conn.query(
			"lucida.images_" + LUCID, BSONObj()); // retrieve desc, NOT data
	GridFS grid(conn, "lucida");
	while (cursor->more()) {
		string label = cursor->next().getStringField("label");
		ostringstream out;
		GridFile gf = grid.findFileByName("opencv_" + LUCID + "/" + label);
		if (!gf.exists()) {
			print("opencv_" + LUCID + "/" + label + " not found!");
			continue;
		}
		gf.write(out);
		rtn.push_back(unique_ptr<StoredImage>(new StoredImage(
				label,
				move(Image::matStringToMatObj(out.str())))));
	}
	return rtn;
}
}
<|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <thread>

namespace tp
{

/**
 * @brief The ThreadPoolOptions class provides creation options for
 * ThreadPool.
 */
class ThreadPoolOptions
{
public:
    /**
     * @brief ThreadPoolOptions Construct default options for thread pool.
     */
    ThreadPoolOptions();

    /**
     * @brief setThreadCount Set thread count.
     * @param count Number of threads to be created.
     */
    void setThreadCount(size_t count);

    /**
     * @brief setQueueSize Set single worker queue size.
     * @param count Maximum length of queue of single worker.
     */
    void setQueueSize(size_t size);

    /**
     * @brief threadCount Return thread count.
     */
    size_t threadCount() const;

    /**
     * @brief queueSize Return single worker queue size.
     */
    size_t queueSize() const;

private:
    size_t m_thread_count;
    size_t m_queue_size;
};

/// Implementation

inline ThreadPoolOptions::ThreadPoolOptions()
    : m_thread_count(std::max<size_t>(1u, std::thread::hardware_concurrency()))
    , m_queue_size(1024u)
{
}

inline void ThreadPoolOptions::setThreadCount(size_t count)
{
    m_thread_count = std::max<size_t>(1u, count);
}

inline void ThreadPoolOptions::setQueueSize(size_t size)
{
    m_queue_size = std::max<size_t>(1u, size);
}

inline size_t ThreadPoolOptions::threadCount() const
{
    return m_thread_count;
}

inline size_t ThreadPoolOptions::queueSize() const
{
    return m_queue_size;
}

}
<commit_msg>threadpool should do hw concurrency -1 to give main thread chance to process relays<commit_after>#pragma once

#include <algorithm>
#include <thread>

namespace tp
{

/**
 * @brief The ThreadPoolOptions class provides creation options for
 * ThreadPool.
 */
class ThreadPoolOptions
{
public:
    /**
     * @brief ThreadPoolOptions Construct default options for thread pool.
     */
    ThreadPoolOptions();

    /**
     * @brief setThreadCount Set thread count.
     * @param count Number of threads to be created.
     */
    void setThreadCount(size_t count);

    /**
     * @brief setQueueSize Set single worker queue size.
     * @param count Maximum length of queue of single worker.
     */
    void setQueueSize(size_t size);

    /**
     * @brief threadCount Return thread count.
     */
    size_t threadCount() const;

    /**
     * @brief queueSize Return single worker queue size.
     */
    size_t queueSize() const;

private:
    size_t m_thread_count;
    size_t m_queue_size;
};

/// Implementation

inline ThreadPoolOptions::ThreadPoolOptions()
    : m_thread_count(std::max<size_t>(1u, std::thread::hardware_concurrency()-1))
    , m_queue_size(1024u)
{
}

inline void ThreadPoolOptions::setThreadCount(size_t count)
{
    m_thread_count = std::max<size_t>(1u, count);
}

inline void ThreadPoolOptions::setQueueSize(size_t size)
{
    m_queue_size = std::max<size_t>(1u, size);
}

inline size_t ThreadPoolOptions::threadCount() const
{
    return m_thread_count;
}

inline size_t ThreadPoolOptions::queueSize() const
{
    return m_queue_size;
}

}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/pldm/extended/pldm_entity_ids.C $                     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2020                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/* @file pldm_entity_ids.C
 *
 * @brief Implementation for interface in pldm_entity_ids.H
 */

// Targeting
#include <targeting/common/targetservice.H>
#include <targeting/common/utilFilter.H>

// PLDM
#include "../common/pldmtrace.H"
#include <pldm/extended/pldm_entity_ids.H>
#include <pldm/extended/pdr_manager.H>
#include <pldm/extended/hb_pdrs.H>
#include <pldm/extended/pldm_fru.H>
#include <pldm/pldm_reasoncodes.H>
#include <pldm/pldm_errl.H>

// libpldm
#include "../extern/pdr.h"

using namespace ERRORLOG;

namespace
{

using namespace PLDM;
using namespace TARGETING;

// These are entities whose RSID is generated by Hostboot. We encode the RSID so
// that we can retrieve the Target instance associated with the entity.
const entity_type hb_entity_types[] =
{
    ENTITY_TYPE_PROCESSOR_MODULE,
    ENTITY_TYPE_DIMM
};

// These are entities whose RSID is NOT generated by Hostboot. We don't have a
// strategy yet to associate them with the right Target instance, so we are
// relying on them having one and only one instance and associating them that
// way.
struct unique_entity_info
{
    TARGETING::CLASS target_class;
    TARGETING::TYPE target_type;
    entity_type ent_type;
};

const unique_entity_info foreign_entity_types[] =
{
    { CLASS_ENC, TYPE_NODE, ENTITY_TYPE_BACKPLANE },
    //TODO RTC: 246066 Enable when TPMs are detected by hostboot
//     { CLASS_CHIP, TYPE_TPM, ENTITY_TYPE_TPM }
};

/* @brief Update the given target's PLDM_ENTITY_ID_INFO attribute
 *        with a PLDM entity ID
 *
 * @param[in] i_target  The target to update
 * @param[in] i_rsid    FRU Record Set ID to use for Entity ID info
 * @return errlHndl_t   Error if any, otherwise nullptr
 */
errlHndl_t updateTargetEntityIdAttribute(Target* const i_target,
                                         const fru_record_set_id_t i_rsid)
{
    errlHndl_t errl = nullptr;

    do
    {

    pldm_entity ent { };

    if (!thePdrManager().findEntityByFruRecordSetId(i_rsid, ent))
    {
        PLDM_ERR("Cannot find entity by FRU RSID 0x%04x", i_rsid);

        /*
         * @errortype  ERRL_SEV_UNRECOVERABLE
         * @moduleid   MOD_PLDM_ENTITY_IDS
         * @reasoncode RC_NO_ENTITY_FROM_RSID
         * @userdata1  The Target HUID
         * @userdata2  The FRU Record Set ID
         * @devdesc    Software problem, cannot find Entity from FRU Record Set ID
         * @custdesc   A software error occurred during system boot
         */
        errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                             MOD_PLDM_ENTITY_IDS,
                             RC_NO_ENTITY_FROM_RSID,
                             get_huid(i_target),
                             i_rsid,
                             ErrlEntry::ADD_SW_CALLOUT);

        addBmcErrorCallouts(errl);
        break;
    }

    // @TODO RTC 256140: Remove this function call when the BMC normalizes all
    // PDRs
    if (!thePdrManager().findEntityByTypeAndId(ent))
    {
        PLDM_ERR("Cannot find normalized entity container ID in entity "
                 "assocation PDRs from the BMC on target HUID = 0x%08x"
                 "(RSID = 0x%08x, type = 0x%x, instance number = 0x%x)",
                 get_huid(i_target),
                 i_rsid,
                 ent.entity_type,
                 ent.entity_instance_num);

        /*
         * @errortype  ERRL_SEV_UNRECOVERABLE
         * @moduleid   MOD_PLDM_ENTITY_IDS
         * @reasoncode RC_MISSING_ENTITY_ID
         * @userdata1  The Target HUID
         * @userdata2[0:15]   Entity type
         * @userdata2[16:31]  Entity instance number
         * @userdata2[32:63]  The FRU Record Set ID
         * @devdesc    Software problem, cannot find Entity from FRU Record Set ID
         * @custdesc   A software error occurred during system boot
         */
        errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                             MOD_PLDM_ENTITY_IDS,
                             RC_MISSING_ENTITY_ID,
                             get_huid(i_target),
                             TWO_UINT16_ONE_UINT32_TO_UINT64(ent.entity_type,
                                                             ent.entity_instance_num,
                                                             i_rsid),
                             ErrlEntry::ADD_SW_CALLOUT);

        addBmcErrorCallouts(errl);
        break;
    }

    PLDM_INF("Set PLDM_ENTITY_ID for HUID 0x%08x (%s) to 0x%04x/0x%04x/0x%04x",
             get_huid(i_target),
             attrToString<ATTR_TYPE>(i_target->getAttr<ATTR_TYPE>()),
             ent.entity_type,
             ent.entity_instance_num,
             ent.entity_container_id);

    const TARGETING::ATTR_PLDM_ENTITY_ID_INFO_type entity_info =
    {
        // The attribute stores its values in little-endian
        .entityType = static_cast<uint16_t>(htole16(ent.entity_type)),
        .entityInstanceNumber = static_cast<uint16_t>(htole16(ent.entity_instance_num)),
        .containerId = static_cast<uint16_t>(htole16(ent.entity_container_id))
    };

    i_target->setAttr<ATTR_PLDM_ENTITY_ID_INFO>(entity_info);

    } while (false);

    return errl;
}

}

errlHndl_t PLDM::assignTargetEntityIds()
{
    PLDM_ENTER("assignTargetEntityIds");

    errlHndl_t errl = nullptr;

    do
    {

    // These RSIDs are not produced by Hostboot so we can't decode them to
    // determine which Target it corresponds to. Instead we rely on the fact
    // that there is only one Target object on single-node machines. This block
    // deals with that.
    for (const auto& entity_info : foreign_entity_types)
    {
        const auto target_rsid = thePdrManager().findFruRecordSetIdsByType(entity_info.ent_type);

        // We don't have a way to associate multiple backplane RSIDs (which is
        // created by the BMC) with Targets at this point, so throw an error
        if (target_rsid.size() > 1)
        {
            PLDM_ERR("Got %llu targets of type %s, expected 0 or 1",
                     target_rsid.size(),
                     attrToString<ATTR_TYPE>(entity_info.target_type));

            /*
             * @errortype  ERRL_SEV_UNRECOVERABLE
             * @moduleid   MOD_PLDM_ENTITY_IDS
             * @reasoncode RC_EXPECTED_UNIQUE_ENTITY
             * @userdata1  The number of targets found
             * @userdata2[0:31]  The class of target
             * @userdata2[32:63] The type of target
             * @devdesc    Software problem, wanted 0 or 1 target, got multiple
             * @custdesc   A software error occurred during system boot
             */
            errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                 MOD_PLDM_ENTITY_IDS,
                                 RC_EXPECTED_UNIQUE_ENTITY,
                                 target_rsid.size(),
                                 TWO_UINT32_TO_UINT64(entity_info.target_class,
                                                      entity_info.target_type),
                                 ErrlEntry::ADD_SW_CALLOUT);

            addBmcErrorCallouts(errl);
            break;
        }

        TargetHandleList target;

        getClassResources(target,
                          entity_info.target_class,
                          entity_info.target_type,
                          UTIL_FILTER_PRESENT);

        if (target.size() != target_rsid.size())
        {
            /*
             * @errortype  ERRL_SEV_UNRECOVERABLE
             * @moduleid   MOD_PLDM_ENTITY_IDS
             * @reasoncode RC_EXPECTED_UNIQUE_TARGET
             * @userdata1  The number of targets found
             * @userdata2  The number of PLDM entities found
             * @devdesc    Software problem, mismatching number of Targets and Entities
             * @custdesc   A software error occurred during system boot
             */
            errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                 MOD_PLDM_ENTITY_IDS,
                                 RC_EXPECTED_UNIQUE_TARGET,
                                 target.size(),
                                 target_rsid.size(),
                                 ErrlEntry::ADD_SW_CALLOUT);

            addBmcErrorCallouts(errl);
            break;
        }

        if (!target.empty())
        {
            errl = updateTargetEntityIdAttribute(target[0], target_rsid[0]);

            if (errl)
            {
                break;
            }
        }
    }

    if (errl)
    {
        break;
    }

    // Now deal with records whose RSIDs Hostboot did encode with the
    // corresponding Target's class/type/instance.
    for (const entity_type ent_type : hb_entity_types)
    {
        const auto fru_rsids = thePdrManager().findFruRecordSetIdsByType(ent_type);

        for (const auto rsid : fru_rsids)
        {
            Target* const target = getTargetFromHostbootFruRecordSetID(rsid);

            // This means that either there was a programming error, or else the
            // BMC did not preserve our RSIDs when we sent our PDRs to them and
            // refetched them at the end of the PDR exchange.
            if (!target)
            {
                PLDM_ERR("Cannot find target from RSID 0x%04x", rsid);

                /*
                 * @errortype  ERRL_SEV_UNRECOVERABLE
                 * @moduleid   MOD_PLDM_ENTITY_IDS
                 * @reasoncode RC_NO_TARGET_FROM_RSID
                 * @userdata1  The FRU Record Set ID that does not correspond to a Target
                 * @userdata2  The entity type of the corresponding Record Set
                 * @devdesc    Software problem, cannot find the Target from FRU Record Set ID
                 * @custdesc   A software error occurred during system boot
                 */
                errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                     MOD_PLDM_ENTITY_IDS,
                                     RC_NO_TARGET_FROM_RSID,
                                     rsid,
                                     ent_type,
                                     ErrlEntry::ADD_SW_CALLOUT);

                addBmcErrorCallouts(errl);
                break;
            }

            errl = updateTargetEntityIdAttribute(target, rsid);

            if (errl)
            {
                break;
            }
        }

        if (errl)
        {
            break;
        }
    }

    } while (false);

    PLDM_EXIT("assignTargetEntityIds");

    return errl;
}
<commit_msg>Write PLDM entity ID information to sys and chassis attributes<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/pldm/extended/pldm_entity_ids.C $                     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2020                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/* @file pldm_entity_ids.C
 *
 * @brief Implementation for interface in pldm_entity_ids.H
 */

// Targeting
#include <targeting/common/targetservice.H>
#include <targeting/common/utilFilter.H>

// PLDM
#include "../common/pldmtrace.H"
#include <pldm/extended/pldm_entity_ids.H>
#include <pldm/extended/pdr_manager.H>
#include <pldm/extended/hb_pdrs.H>
#include <pldm/extended/pldm_fru.H>
#include <pldm/pldm_reasoncodes.H>
#include <pldm/pldm_errl.H>

// libpldm
#include "../extern/pdr.h"

using namespace ERRORLOG;

namespace
{

using namespace PLDM;
using namespace TARGETING;

// These are entities whose RSID is generated by Hostboot. We encode the RSID so
// that we can retrieve the Target instance associated with the entity.
const entity_type hb_entity_types[] =
{
    ENTITY_TYPE_PROCESSOR_MODULE,
    ENTITY_TYPE_DIMM
};

// These are entities whose RSID is NOT generated by Hostboot. We don't have a
// strategy yet to associate them with the right Target instance, so we are
// relying on them having one and only one instance and associating them that
// way.
struct unique_entity_info
{
    TARGETING::CLASS target_class;
    TARGETING::TYPE target_type;
    entity_type ent_type;
};

const unique_entity_info foreign_entity_types[] =
{
    { CLASS_ENC, TYPE_NODE, ENTITY_TYPE_BACKPLANE },
    { CLASS_SYS, TYPE_SYS,  ENTITY_TYPE_CHASSIS },
    { CLASS_SYS, TYPE_SYS,  ENTITY_TYPE_LOGICAL_SYSTEM }
    //TODO RTC: 246066 Enable when TPMs are detected by hostboot
//     { CLASS_CHIP, TYPE_TPM, ENTITY_TYPE_TPM }
};

/* @brief Update the given target's PLDM_ENTITY_ID_INFO attribute
 *        with a PLDM entity ID
 *
 * @param[in] i_target  The target to update
 * @param[in] i_rsid    FRU Record Set ID to use for Entity ID info
 * @return errlHndl_t   Error if any, otherwise nullptr
 */
errlHndl_t updateTargetEntityIdAttribute(Target* const i_target,
                                         const fru_record_set_id_t i_rsid)
{
    errlHndl_t errl = nullptr;

    do
    {

    pldm_entity ent { };

    if (!thePdrManager().findEntityByFruRecordSetId(i_rsid, ent))
    {
        PLDM_ERR("Cannot find entity by FRU RSID 0x%04x", i_rsid);

        /*
         * @errortype  ERRL_SEV_UNRECOVERABLE
         * @moduleid   MOD_PLDM_ENTITY_IDS
         * @reasoncode RC_NO_ENTITY_FROM_RSID
         * @userdata1  The Target HUID
         * @userdata2  The FRU Record Set ID
         * @devdesc    Software problem, cannot find Entity from FRU Record Set ID
         * @custdesc   A software error occurred during system boot
         */
        errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                             MOD_PLDM_ENTITY_IDS,
                             RC_NO_ENTITY_FROM_RSID,
                             get_huid(i_target),
                             i_rsid,
                             ErrlEntry::ADD_SW_CALLOUT);

        addBmcErrorCallouts(errl);
        break;
    }

    // @TODO RTC 256140: Remove this function call when the BMC normalizes all
    // PDRs
    if (!thePdrManager().findEntityByTypeAndId(ent))
    {
        PLDM_ERR("Cannot find normalized entity container ID in entity "
                 "assocation PDRs from the BMC on target HUID = 0x%08x"
                 "(RSID = 0x%08x, type = 0x%x, instance number = 0x%x)",
                 get_huid(i_target),
                 i_rsid,
                 ent.entity_type,
                 ent.entity_instance_num);

        /*
         * @errortype  ERRL_SEV_UNRECOVERABLE
         * @moduleid   MOD_PLDM_ENTITY_IDS
         * @reasoncode RC_MISSING_ENTITY_ID
         * @userdata1  The Target HUID
         * @userdata2[0:15]   Entity type
         * @userdata2[16:31]  Entity instance number
         * @userdata2[32:63]  The FRU Record Set ID
         * @devdesc    Software problem, cannot find Entity from FRU Record Set ID
         * @custdesc   A software error occurred during system boot
         */
        errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                             MOD_PLDM_ENTITY_IDS,
                             RC_MISSING_ENTITY_ID,
                             get_huid(i_target),
                             TWO_UINT16_ONE_UINT32_TO_UINT64(ent.entity_type,
                                                             ent.entity_instance_num,
                                                             i_rsid),
                             ErrlEntry::ADD_SW_CALLOUT);

        addBmcErrorCallouts(errl);
        break;
    }

    PLDM_INF("Set PLDM_ENTITY_ID for HUID 0x%08x (%s) to 0x%04x/0x%04x/0x%04x",
             get_huid(i_target),
             attrToString<ATTR_TYPE>(i_target->getAttr<ATTR_TYPE>()),
             ent.entity_type,
             ent.entity_instance_num,
             ent.entity_container_id);

    // This union groups all PLDM entity ID information attributes into the
    // same storage location to be exploited below.  All PLDM entity ID
    // information attribute flavors need to move in lock step if they are ever
    // changed
    const union {
        TARGETING::ATTR_PLDM_ENTITY_ID_INFO_type         generic;
        TARGETING::ATTR_CHASSIS_PLDM_ENTITY_ID_INFO_type chassis;
        TARGETING::ATTR_SYSTEM_PLDM_ENTITY_ID_INFO_type  system;

    } entity_info = {

        // The attribute stores its values in little-endian
        .generic = {
            .entityType = static_cast<uint16_t>(htole16(ent.entity_type)),
            .entityInstanceNumber = static_cast<uint16_t>(htole16(ent.entity_instance_num)),
            .containerId = static_cast<uint16_t>(htole16(ent.entity_container_id))
         }
    };

    switch(ent.entity_type)
    {
        // System and chassis PLDM entity ID information map to specially named
        // attributes (with the same format as PLDM_ENTITY_ID_INFO) that reside
        // on the system target
        case ENTITY_TYPE_LOGICAL_SYSTEM:
            PLDM_INF("Writing logical system PLDM entity ID info");
            i_target->setAttr<ATTR_SYSTEM_PLDM_ENTITY_ID_INFO>(entity_info.system);
            break;
        case ENTITY_TYPE_CHASSIS:
            PLDM_INF("Writing chassis PLDM entity ID info");
            i_target->setAttr<ATTR_CHASSIS_PLDM_ENTITY_ID_INFO>(entity_info.chassis);
            break;
        default:
            i_target->setAttr<ATTR_PLDM_ENTITY_ID_INFO>(entity_info.generic);
            break;
    }

    } while (false);

    return errl;
}

}

errlHndl_t PLDM::assignTargetEntityIds()
{
    PLDM_ENTER("assignTargetEntityIds");

    errlHndl_t errl = nullptr;

    do
    {

    // These RSIDs are not produced by Hostboot so we can't decode them to
    // determine which Target it corresponds to. Instead we rely on the fact
    // that there is only one Target object on single-node machines. This block
    // deals with that.
    for (const auto& entity_info : foreign_entity_types)
    {
        const auto target_rsid = thePdrManager().findFruRecordSetIdsByType(entity_info.ent_type);

        // We don't have a way to associate multiple backplane RSIDs (which is
        // created by the BMC) with Targets at this point, so throw an error
        if (target_rsid.size() > 1)
        {
            PLDM_ERR("Got %llu targets of type %s, expected 0 or 1",
                     target_rsid.size(),
                     attrToString<ATTR_TYPE>(entity_info.target_type));

            /*
             * @errortype  ERRL_SEV_UNRECOVERABLE
             * @moduleid   MOD_PLDM_ENTITY_IDS
             * @reasoncode RC_EXPECTED_UNIQUE_ENTITY
             * @userdata1  The number of targets found
             * @userdata2[0:31]  The class of target
             * @userdata2[32:63] The type of target
             * @devdesc    Software problem, wanted 0 or 1 target, got multiple
             * @custdesc   A software error occurred during system boot
             */
            errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                 MOD_PLDM_ENTITY_IDS,
                                 RC_EXPECTED_UNIQUE_ENTITY,
                                 target_rsid.size(),
                                 TWO_UINT32_TO_UINT64(entity_info.target_class,
                                                      entity_info.target_type),
                                 ErrlEntry::ADD_SW_CALLOUT);

            addBmcErrorCallouts(errl);
            break;
        }

        TargetHandleList target;

        getClassResources(target,
                          entity_info.target_class,
                          entity_info.target_type,
                          UTIL_FILTER_PRESENT);

        if (target.size() != target_rsid.size())
        {
            /*
             * @errortype  ERRL_SEV_UNRECOVERABLE
             * @moduleid   MOD_PLDM_ENTITY_IDS
             * @reasoncode RC_EXPECTED_UNIQUE_TARGET
             * @userdata1  The number of targets found
             * @userdata2  The number of PLDM entities found
             * @devdesc    Software problem, mismatching number of Targets and Entities
             * @custdesc   A software error occurred during system boot
             */
            errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                 MOD_PLDM_ENTITY_IDS,
                                 RC_EXPECTED_UNIQUE_TARGET,
                                 target.size(),
                                 target_rsid.size(),
                                 ErrlEntry::ADD_SW_CALLOUT);

            addBmcErrorCallouts(errl);
            break;
        }

        if (!target.empty())
        {
            errl = updateTargetEntityIdAttribute(target[0], target_rsid[0]);

            if (errl)
            {
                break;
            }
        }
    }

    if (errl)
    {
        break;
    }

    // Now deal with records whose RSIDs Hostboot did encode with the
    // corresponding Target's class/type/instance.
    for (const entity_type ent_type : hb_entity_types)
    {
        const auto fru_rsids = thePdrManager().findFruRecordSetIdsByType(ent_type);

        for (const auto rsid : fru_rsids)
        {
            Target* const target = getTargetFromHostbootFruRecordSetID(rsid);

            // This means that either there was a programming error, or else the
            // BMC did not preserve our RSIDs when we sent our PDRs to them and
            // refetched them at the end of the PDR exchange.
            if (!target)
            {
                PLDM_ERR("Cannot find target from RSID 0x%04x", rsid);

                /*
                 * @errortype  ERRL_SEV_UNRECOVERABLE
                 * @moduleid   MOD_PLDM_ENTITY_IDS
                 * @reasoncode RC_NO_TARGET_FROM_RSID
                 * @userdata1  The FRU Record Set ID that does not correspond to a Target
                 * @userdata2  The entity type of the corresponding Record Set
                 * @devdesc    Software problem, cannot find the Target from FRU Record Set ID
                 * @custdesc   A software error occurred during system boot
                 */
                errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                     MOD_PLDM_ENTITY_IDS,
                                     RC_NO_TARGET_FROM_RSID,
                                     rsid,
                                     ent_type,
                                     ErrlEntry::ADD_SW_CALLOUT);

                addBmcErrorCallouts(errl);
                break;
            }

            errl = updateTargetEntityIdAttribute(target, rsid);

            if (errl)
            {
                break;
            }
        }

        if (errl)
        {
            break;
        }
    }

    } while (false);

    PLDM_EXIT("assignTargetEntityIds");

    return errl;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2013 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 <stdio.h>

#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
#include "webrtc/modules/video_coding/main/test/rtp_file_reader.h"
#include "webrtc/modules/video_coding/main/test/rtp_player.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"

using namespace webrtc::rtpplayer;

const uint32_t kMaxPacketSize = 1500;
const int kDefaultTransmissionTimeOffsetExtensionId = 2;

int main(int argc, char** argv) {
  if (argc < 2) {
    printf("Usage: rtp_to_text <input_file.rtp> <output_file.rtp>\n")
    return -1;
  }
  webrtc::scoped_ptr<RtpPacketSourceInterface> rtp_reader(
      CreateRtpFileReader(argv[1]));
  if (!rtp_reader.get()) {
    printf("Cannot open input file %s\n", argv[1]);
    return -1;
  }
  uint8_t packet_buffer[kMaxPacketSize];
  uint8_t* packet = packet_buffer;
  uint32_t packet_length = kMaxPacketSize;
  uint32_t time_ms = 0;
  FILE* out_file = fopen(argv[2], "wt");
  if (!out_file) {
    printf("Cannot open output file %s\n", argv[2]);
    return -1;
  }
  printf("Input file: %s, Output file: %s\n\n", argv[1], argv[2]);
  fprintf(out_file, "seqnum timestamp ts_offset abs_sendtime recvtime "
          "markerbit ssrc size\n");
  webrtc::scoped_ptr<webrtc::RtpHeaderParser> parser(
      webrtc::RtpHeaderParser::Create());
  parser->RegisterRtpHeaderExtension(
      webrtc::kRtpExtensionTransmissionTimeOffset,
      kDefaultTransmissionTimeOffsetExtensionId);
  int packet_counter = 0;
  while (rtp_reader->NextPacket(packet, &packet_length, &time_ms) == 0) {
    webrtc::RTPHeader header;
    parser->Parse(packet, packet_length, &header);
    fprintf(out_file, "%u %u %d %u %u %d %u %u\n", header.sequenceNumber,
            header.timestamp, header.extension.transmissionTimeOffset,
            header.extension.absoluteSendTime, time_ms, header.markerBit,
            header.ssrc, packet_length);
    packet_length = kMaxPacketSize;
    ++packet_counter;
  }
  printf("Parsed %d packets\n", packet_counter);
  return 0;
}
<commit_msg>Fix build error in r4934.<commit_after>/*
 *  Copyright (c) 2013 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 <stdio.h>

#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
#include "webrtc/modules/video_coding/main/test/rtp_file_reader.h"
#include "webrtc/modules/video_coding/main/test/rtp_player.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"

using namespace webrtc::rtpplayer;

const uint32_t kMaxPacketSize = 1500;
const int kDefaultTransmissionTimeOffsetExtensionId = 2;

int main(int argc, char** argv) {
  if (argc < 2) {
    printf("Usage: rtp_to_text <input_file.rtp> <output_file.rtp>\n");
    return -1;
  }
  webrtc::scoped_ptr<RtpPacketSourceInterface> rtp_reader(
      CreateRtpFileReader(argv[1]));
  if (!rtp_reader.get()) {
    printf("Cannot open input file %s\n", argv[1]);
    return -1;
  }
  uint8_t packet_buffer[kMaxPacketSize];
  uint8_t* packet = packet_buffer;
  uint32_t packet_length = kMaxPacketSize;
  uint32_t time_ms = 0;
  FILE* out_file = fopen(argv[2], "wt");
  if (!out_file) {
    printf("Cannot open output file %s\n", argv[2]);
    return -1;
  }
  printf("Input file: %s, Output file: %s\n\n", argv[1], argv[2]);
  fprintf(out_file, "seqnum timestamp ts_offset abs_sendtime recvtime "
          "markerbit ssrc size\n");
  webrtc::scoped_ptr<webrtc::RtpHeaderParser> parser(
      webrtc::RtpHeaderParser::Create());
  parser->RegisterRtpHeaderExtension(
      webrtc::kRtpExtensionTransmissionTimeOffset,
      kDefaultTransmissionTimeOffsetExtensionId);
  int packet_counter = 0;
  while (rtp_reader->NextPacket(packet, &packet_length, &time_ms) == 0) {
    webrtc::RTPHeader header;
    parser->Parse(packet, packet_length, &header);
    fprintf(out_file, "%u %u %d %u %u %d %u %u\n", header.sequenceNumber,
            header.timestamp, header.extension.transmissionTimeOffset,
            header.extension.absoluteSendTime, time_ms, header.markerBit,
            header.ssrc, packet_length);
    packet_length = kMaxPacketSize;
    ++packet_counter;
  }
  printf("Parsed %d packets\n", packet_counter);
  return 0;
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_MAT_FUN_ADJ_JAC_APPLY_HPP
#define STAN_MATH_REV_MAT_FUN_ADJ_JAC_APPLY_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat.hpp>
#include <stan/math/rev/core.hpp>
#include <limits>
#include <vector>

namespace stan {
namespace math {

/*
 * adj_jac_vari interfaces a user supplied functor  with the reverse mode
 * autodiff. It allows someone to implement functions with custom reverse mode
 * autodiff without having to deal with autodiff types.
 *
 * The requirements on the functor F are described in the documentation for
 * adj_jac_apply
 *
 * @tparam F class of functor
 */
template <typename F>
struct adj_jac_vari : public vari {
  F f_;
  int N_;
  vari** x_vi_;
  int M_;
  vari** y_vi_;

  /**
   * The adj_jac_vari constructor
   *  1. Initializes an instance of the user defined functor F
   *  2. Calls operator() on the F instance with the double values from the
   * input x
   *  3. Saves copies of the varis pointed to by the input vars for subsequent
   * calls to chain
   *  4. Allocates varis for the output of the functor F
   *
   * @param x Input as vars
   */
  explicit adj_jac_vari(const Eigen::Matrix<var, Eigen::Dynamic, 1>& x)
      : vari(std::numeric_limits<double>::quiet_NaN()),  // The val_ in this
                                                         // vari is unused
        N_(x.size()),
        x_vi_(build_vari_array(x)) {
    Eigen::Matrix<double, Eigen::Dynamic, 1> val_x = value_of(x);
    Eigen::Matrix<double, Eigen::Dynamic, 1> val_y = f_(val_x);

    M_ = val_y.size();
    y_vi_ = ChainableStack::instance().memalloc_.alloc_array<vari*>(M_);
    for (int m = 0; m < M_; ++m) {
      y_vi_[m] = new vari(val_y(m), false);
    }
  }

  /**
   * chain propagates the adjoints at the output varis (y_vi_) back to the input
   * varis (x_vi_) by using the multiply_adjoint_jacobian function of the user
   * defined functor
   *
   * Unlike the constructor, this operation may be called multiple times during
   * the life of the vari
   */
  void chain() {
    Eigen::Matrix<double, Eigen::Dynamic, 1> y_adj(M_);
    for (int m = 0; m < M_; ++m)
      y_adj(m) = y_vi_[m]->adj_;
    Eigen::Matrix<double, Eigen::Dynamic, 1> y_adj_jac
        = f_.multiply_adjoint_jacobian(y_adj);
    for (int n = 0; n < N_; ++n)
      x_vi_[n]->adj_ += y_adj_jac(n);
  }
};

/*
 * Return the result of applying the function defined by a nullary construction
 * of F to the specified input argument
 *
 * adj_jac_apply makes it possible to write efficient reverse-mode
 * autodiff code without ever touching Stan's autodiff internals
 *
 * Mathematically, to use a function in reverse mode autodiff, you need to be
 * able to evaluate the function (y = f(x)) and multiply the Jacobian of that
 * function (df(x)/dx) by a vector.
 *
 * As an example, pretend there exists some large, complicated function, L(x),
 * which contains our smaller function f(x). The goal of autodiff is to compute
 * dL/dx. If we break the large function into pieces:
 *
 * y = f(x)
 * L = g(y)
 *
 * If we were given dL/dy we could compute dL/dx by the product dL/dy * dy/dx
 *
 * Because y = f(x), dy/dx is just df(x)/dx, the Jacobian of the function we're
 * trying to define. In vector form,
 *
 * dL/dx = (dL/dy)' * df(x)/dx
 *
 * So implementing f(x) and the product above is all that is required
 * mathematically to implement reverse-mode autodiff for a function.
 *
 * adj_jac_apply takes as a template argument a functor F that supplies the
 * non-static member functions: (required) Eigen::VectorXd operator()(const
 * Eigen::VectorXd& x), (required) Eigen::VectorXd
 * multiply_adjoint_jacobian(const Eigen::VectorXd& adj) and, (optional) a
 * nullary constructor
 *
 * operator() is responsible for computing f(x) and multiply_adjoint_jacobian is
 * responsible for computing the adjoint transpose Jacobian product (which
 * frequently does not require the calculation of the full Jacobian).
 *
 * operator() will be called before multiply_adjoint_jacobian is called, and is
 * only called once in the lifetime of the functor multiply_adjoint_jacobian is
 * called after operator() and may be called multiple times for any single
 * functor
 *
 * The functor supplied to adj_jac_apply must be careful to allocate any
 * variables it defines in the autodiff arena because its destructor will
 * never be called and memory will leak if allocated anywhere else.
 *
 * @tparam F functor to be connected to the autodiff stack
 * @param x input to the functor
 * @return the result of the specified operation wrapped up in vars
 */
template <class F>
Eigen::Matrix<var, Eigen::Dynamic, 1> adj_jac_apply(
    const Eigen::Matrix<var, Eigen::Dynamic, 1>& x) {
  adj_jac_vari<F>* vi = new adj_jac_vari<F>(x);
  Eigen::Matrix<var, Eigen::Dynamic, 1> y(vi->M_);

  for (int m = 0; m < y.size(); ++m)
    y(m) = (vi->y_vi_)[m];
  return y;
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>add ben's fixes<commit_after>#ifndef STAN_MATH_REV_MAT_FUN_ADJ_JAC_APPLY_HPP
#define STAN_MATH_REV_MAT_FUN_ADJ_JAC_APPLY_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/fun/value_of.hpp>
#include <stan/math/rev/scal/fun/value_of.hpp>
#include <limits>
#include <vector>

namespace stan {
namespace math {

/*
 * adj_jac_vari interfaces a user supplied functor  with the reverse mode
 * autodiff. It allows someone to implement functions with custom reverse mode
 * autodiff without having to deal with autodiff types.
 *
 * The requirements on the functor F are described in the documentation for
 * adj_jac_apply
 *
 * @tparam F class of functor
 */
template <typename F>
struct adj_jac_vari : public vari {
  F f_;
  int N_;
  vari** x_vi_;
  int M_;
  vari** y_vi_;

  /**
   * The adj_jac_vari constructor
   *  1. Initializes an instance of the user defined functor F
   *  2. Calls operator() on the F instance with the double values from the
   * input x
   *  3. Saves copies of the varis pointed to by the input vars for subsequent
   * calls to chain
   *  4. Allocates varis for the output of the functor F
   *
   * @param x Input as vars
   */
  explicit adj_jac_vari(const Eigen::Matrix<var, Eigen::Dynamic, 1>& x)
      : vari(std::numeric_limits<double>::quiet_NaN()),  // The val_ in this
                                                         // vari is unused
        N_(x.size()),
        x_vi_(build_vari_array(x)) {
    Eigen::Matrix<double, Eigen::Dynamic, 1> val_x = value_of(x);
    Eigen::Matrix<double, Eigen::Dynamic, 1> val_y = f_(val_x);

    M_ = val_y.size();
    y_vi_ = ChainableStack::instance().memalloc_.alloc_array<vari*>(M_);
    for (int m = 0; m < M_; ++m) {
      y_vi_[m] = new vari(val_y(m), false);
    }
  }

  /**
   * chain propagates the adjoints at the output varis (y_vi_) back to the input
   * varis (x_vi_) by using the multiply_adjoint_jacobian function of the user
   * defined functor
   *
   * Unlike the constructor, this operation may be called multiple times during
   * the life of the vari
   */
  void chain() {
    Eigen::Matrix<double, Eigen::Dynamic, 1> y_adj(M_);
    for (int m = 0; m < M_; ++m)
      y_adj(m) = y_vi_[m]->adj_;
    Eigen::Matrix<double, Eigen::Dynamic, 1> y_adj_jac
        = f_.multiply_adjoint_jacobian(y_adj);
    for (int n = 0; n < N_; ++n)
      x_vi_[n]->adj_ += y_adj_jac(n);
  }
};

/*
 * Return the result of applying the function defined by a nullary construction
 * of F to the specified input argument
 *
 * adj_jac_apply makes it possible to write efficient reverse-mode
 * autodiff code without ever touching Stan's autodiff internals
 *
 * Mathematically, to use a function in reverse mode autodiff, you need to be
 * able to evaluate the function (y = f(x)) and multiply the Jacobian of that
 * function (df(x)/dx) by a vector.
 *
 * As an example, pretend there exists some large, complicated function, L(x),
 * which contains our smaller function f(x). The goal of autodiff is to compute
 * dL/dx. If we break the large function into pieces:
 *
 * y = f(x)
 * L = g(y)
 *
 * If we were given dL/dy we could compute dL/dx by the product dL/dy * dy/dx
 *
 * Because y = f(x), dy/dx is just df(x)/dx, the Jacobian of the function we're
 * trying to define. In vector form,
 *
 * dL/dx = (dL/dy)' * df(x)/dx
 *
 * So implementing f(x) and the product above is all that is required
 * mathematically to implement reverse-mode autodiff for a function.
 *
 * adj_jac_apply takes as a template argument a functor F that supplies the
 * non-static member functions: (required) Eigen::VectorXd operator()(const
 * Eigen::VectorXd& x), (required) Eigen::VectorXd
 * multiply_adjoint_jacobian(const Eigen::VectorXd& adj) and, (optional) a
 * nullary constructor
 *
 * operator() is responsible for computing f(x) and multiply_adjoint_jacobian is
 * responsible for computing the adjoint transpose Jacobian product (which
 * frequently does not require the calculation of the full Jacobian).
 *
 * operator() will be called before multiply_adjoint_jacobian is called, and is
 * only called once in the lifetime of the functor multiply_adjoint_jacobian is
 * called after operator() and may be called multiple times for any single
 * functor
 *
 * The functor supplied to adj_jac_apply must be careful to allocate any
 * variables it defines in the autodiff arena because its destructor will
 * never be called and memory will leak if allocated anywhere else.
 *
 * @tparam F functor to be connected to the autodiff stack
 * @param x input to the functor
 * @return the result of the specified operation wrapped up in vars
 */
template <class F>
Eigen::Matrix<var, Eigen::Dynamic, 1> adj_jac_apply(
    const Eigen::Matrix<var, Eigen::Dynamic, 1>& x) {
  adj_jac_vari<F>* vi = new adj_jac_vari<F>(x);
  Eigen::Matrix<var, Eigen::Dynamic, 1> y(vi->M_);

  for (int m = 0; m < y.size(); ++m)
    y(m) = (vi->y_vi_)[m];
  return y;
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>#include "defs.h"

#include "pixbuf.h"
#include <wincodec.h>

#pragma comment(lib, "WindowsCodecs.lib")

static int
sg_pixbuf_loadwincodec(struct sg_pixbuf *pbuf, const void *data, size_t len,
                       struct sg_error **err)
{
    HRESULT hr;
    IWICImagingFactory *fac = NULL;
    IWICStream *stream = NULL;
    IWICBitmapDecoder *decoder = NULL;
    IWICBitmapFrameDecode *frame = NULL;
    WICPixelFormatGUID pixelFormat, targetFormat;
    IWICComponentInfo *cinfo = NULL;
    IWICPixelFormatInfo *pinfo = NULL;
    IWICFormatConverter *converter = NULL;
    UINT chanCount, iwidth, iheight;
    sg_pixbuf_format_t pfmt;
    int r;

    hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&fac));
    if (hr != S_OK)
        goto failed;
    hr = fac->CreateStream(&stream);
    if (hr != S_OK)
        goto failed;
    hr = stream->InitializeFromMemory((BYTE *) data, len);
    if (hr != S_OK)
        goto failed;
    hr = fac->CreateDecoderFromStream(stream, NULL, WICDecodeMetadataCacheOnDemand, &decoder);
    if (hr != S_OK)
        goto failed;
    hr = decoder->GetFrame(0, &frame);
    if (hr != S_OK)
        goto failed;
    hr = frame->GetPixelFormat(&pixelFormat);
    if (hr != S_OK)
        goto failed;
    hr = fac->CreateComponentInfo(pixelFormat, &cinfo);
    if (hr != S_OK)
        goto failed;
    hr = cinfo->QueryInterface(IID_IWICPixelFormatInfo, (void **) &pinfo);
    if (hr != S_OK)
        goto failed;
    hr = pinfo->GetChannelCount(&chanCount);
    if (hr != S_OK)
        goto failed;

    switch (chanCount) {
    case 1:
        pfmt = SG_Y;
        targetFormat = GUID_WICPixelFormat8bppGray;
        break;

    case 3:
    case 4:
        pfmt = SG_RGBA;
        targetFormat = GUID_WICPixelFormat32bppRGBA;
        break;

    default:
        goto failed;
    }

    hr = fac->CreateFormatConverter(&converter);
    if (hr != S_OK)
        goto failed;
    hr = converter->Initialize(frame, targetFormat, WICBitmapDitherTypeNone, NULL, 0, WICBitmapPaletteTypeCustom);
    if (hr != S_OK)
        goto failed;
    hr = converter->GetSize(&iwidth, &iheight);
    if (hr != S_OK)
        goto failed;

    r = sg_pixbuf_set(pbuf, pfmt, iwidth, iheight, err);
    if (r)
        goto done;
    r = sg_pixbuf_alloc(pbuf, err);
    if (r)
        goto done;
    converter->CopyPixels(NULL, pbuf->rowbytes, pbuf->rowbytes * pbuf->pheight, (BYTE *) pbuf->data);
    r = 0;

done:
    if (converter) converter->Release();
    if (pinfo) pinfo->Release();
    if (cinfo) cinfo->Release();
    if (frame) frame->Release();
    if (decoder) decoder->Release();
    if (stream) stream->Release();
    if (fac) fac->Release();
    return r;

failed:
    r = -1;
    goto done;
}

int
sg_pixbuf_loadpng(struct sg_pixbuf *pbuf, const void *data, size_t len,
                  struct sg_error **err)
{
    return sg_pixbuf_loadwincodec(pbuf, data, len, err);
}

int
sg_pixbuf_loadjpeg(struct sg_pixbuf *pbuf, const void *data, size_t len,
                   struct sg_error **err)
{
    return sg_pixbuf_loadwincodec(pbuf, data, len, err);
}
<commit_msg>Make wincodec decoder generate errors properly<commit_after>#include "defs.h"

#include "error.h"
#include "log.h"
#include "pixbuf.h"
#include <wincodec.h>

#pragma comment(lib, "WindowsCodecs.lib")

static int
sg_pixbuf_loadwincodec(struct sg_pixbuf *pbuf, const void *data, size_t len,
                       struct sg_error **err)
{
    HRESULT hr;
    IWICImagingFactory *fac = NULL;
    IWICStream *stream = NULL;
    IWICBitmapDecoder *decoder = NULL;
    IWICBitmapFrameDecode *frame = NULL;
    WICPixelFormatGUID pixelFormat, targetFormat;
    IWICComponentInfo *cinfo = NULL;
    IWICPixelFormatInfo *pinfo = NULL;
    IWICFormatConverter *converter = NULL;
    UINT chanCount, iwidth, iheight;
    sg_pixbuf_format_t pfmt;
    int r;

    hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&fac));
    if (hr != S_OK)
        goto failed;
    hr = fac->CreateStream(&stream);
    if (hr != S_OK)
        goto failed;
    hr = stream->InitializeFromMemory((BYTE *) data, len);
    if (hr != S_OK)
        goto failed;
    hr = fac->CreateDecoderFromStream(stream, NULL, WICDecodeMetadataCacheOnDemand, &decoder);
    if (hr != S_OK)
        goto failed;
    hr = decoder->GetFrame(0, &frame);
    if (hr != S_OK)
        goto failed;
    hr = frame->GetPixelFormat(&pixelFormat);
    if (hr != S_OK)
        goto failed;
    hr = fac->CreateComponentInfo(pixelFormat, &cinfo);
    if (hr != S_OK)
        goto failed;
    hr = cinfo->QueryInterface(IID_IWICPixelFormatInfo, (void **) &pinfo);
    if (hr != S_OK)
        goto failed;
    hr = pinfo->GetChannelCount(&chanCount);
    if (hr != S_OK)
        goto failed;

    switch (chanCount) {
    case 1:
        pfmt = SG_Y;
        targetFormat = GUID_WICPixelFormat8bppGray;
        break;

    case 3:
    case 4:
        pfmt = SG_RGBA;
        targetFormat = GUID_WICPixelFormat32bppRGBA;
        break;

    default:
        sg_logf(sg_logger_get("image"), LOG_ERROR,
                "Unsupported channel count: %u", chanCount);
        sg_error_data(err, "Wincodec");
        goto failed;
    }

    hr = fac->CreateFormatConverter(&converter);
    if (hr != S_OK)
        goto failed;
    hr = converter->Initialize(frame, targetFormat, WICBitmapDitherTypeNone, NULL, 0, WICBitmapPaletteTypeCustom);
    if (hr != S_OK)
        goto failed;
    hr = converter->GetSize(&iwidth, &iheight);
    if (hr != S_OK)
        goto failed;

    r = sg_pixbuf_set(pbuf, pfmt, iwidth, iheight, err);
    if (r)
        goto done;
    r = sg_pixbuf_alloc(pbuf, err);
    if (r)
        goto done;
    converter->CopyPixels(NULL, pbuf->rowbytes, pbuf->rowbytes * pbuf->pheight, (BYTE *) pbuf->data);
    r = 0;

done:
    if (converter) converter->Release();
    if (pinfo) pinfo->Release();
    if (cinfo) cinfo->Release();
    if (frame) frame->Release();
    if (decoder) decoder->Release();
    if (stream) stream->Release();
    if (fac) fac->Release();
    return r;

failed:
    sg_error_hresult(err, hr);
    r = -1;
    goto done;
}

int
sg_pixbuf_loadpng(struct sg_pixbuf *pbuf, const void *data, size_t len,
                  struct sg_error **err)
{
    return sg_pixbuf_loadwincodec(pbuf, data, len, err);
}

int
sg_pixbuf_loadjpeg(struct sg_pixbuf *pbuf, const void *data, size_t len,
                   struct sg_error **err)
{
    return sg_pixbuf_loadwincodec(pbuf, data, len, err);
}
<|endoftext|>