// // Copyright 2012 Josh Blum // // This program 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. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with io_sig program. If not, see <http://www.gnu.org/licenses/>. #include "element_impl.hpp" #include <boost/bind.hpp> #include <boost/foreach.hpp> #include <boost/math/common_factor.hpp> using namespace gnuradio; const size_t AT_LEAST_DEFAULT_ITEMS = 1 << 14; const size_t AHH_TOO_MANY_BYTES = 1 << 16; //TODO const size_t THIS_MANY_BUFFERS = 32; const double EDGE_CASE_MITIGATION = 8.0; //edge case mitigation constant //TODO will need more complicated later void ElementImpl::buffer_returner(const size_t index, SBuffer &buffer) { //reset offset and length buffer.offset = 0; buffer.length = 0; BufferReturnMessage message; message.index = index; message.buffer = buffer; this->block.post_msg(message); } static size_t recommend_length( const std::vector<BufferHintMessage> &hints, const size_t output_multiple_bytes, const size_t at_least_bytes ){ //step 1) find the LCM of all reserves to create a super-reserve size_t lcm_bytes = output_multiple_bytes; BOOST_FOREACH(const BufferHintMessage &hint, hints) { lcm_bytes = boost::math::lcm(lcm_bytes, hint.reserve_bytes); } //step 2) N x super reserve to minimize history edge case size_t Nlcm_bytes = lcm_bytes; BOOST_FOREACH(const BufferHintMessage &hint, hints) { while (hint.history_bytes*EDGE_CASE_MITIGATION > Nlcm_bytes) { Nlcm_bytes += lcm_bytes; } } while (at_least_bytes > Nlcm_bytes) { Nlcm_bytes += lcm_bytes; } return std::min(Nlcm_bytes, AHH_TOO_MANY_BYTES); } void ElementImpl::handle_allocation(const tsbe::TaskInterface &task_iface) { //allocate output buffers which will also wake up the task const size_t num_outputs = task_iface.get_num_outputs(); this->output_buffer_tokens.resize(num_outputs); for (size_t i = 0; i < num_outputs; i++) { size_t at_least_items = this->hint; if (at_least_items == 0) at_least_items = AT_LEAST_DEFAULT_ITEMS; const size_t bytes = recommend_length( this->output_allocation_hints[i], this->output_multiple_items[i]*this->output_items_sizes[i], at_least_items*this->output_items_sizes[i] ); SBufferDeleter deleter = boost::bind(&ElementImpl::buffer_returner, this, i, _1); SBufferToken token = SBufferToken(new SBufferDeleter(deleter)); this->output_buffer_tokens[i] = block_ptr->output_buffer_allocator(i, token, bytes); InputAllocatorMessage message; message.token = SBufferToken(new SBufferDeleter(deleter)); message.recommend_length = bytes; task_iface.post_downstream(i, message); } } SBufferToken Block::output_buffer_allocator( const size_t, const SBufferToken &token, const size_t recommend_length ){ for (size_t j = 0; j < THIS_MANY_BUFFERS; j++) { SBufferConfig config; config.memory = NULL; config.length = recommend_length; config.affinity = (*this)->buffer_affinity; config.token = token; SBuffer buff(config); std::memset(buff.get_actual_memory(), 0, buff.get_actual_length()); //buffer derefs here and the token messages it back to the block } return token; } SBufferToken Block::input_buffer_allocator( const size_t, const SBufferToken &, const size_t ){ return SBufferToken(); //null }