usrp-e100: replaced safe managed buffers in usrp-e100 mmap with custom ones

the buffers are reusable and the overhead is reduced (nothing to malloc)

also removed the zero_copy.cpp (not needed anymore)

need to test on device...
This commit is contained in:
Josh Blum 2011-02-15 17:07:34 -08:00
parent 153f2575bb
commit 8ffd7e04c4
4 changed files with 112 additions and 193 deletions

View file

@ -21,7 +21,6 @@
#include <uhd/config.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
namespace uhd{ namespace transport{
@ -33,20 +32,6 @@ namespace uhd{ namespace transport{
class UHD_API managed_recv_buffer{
public:
typedef boost::shared_ptr<managed_recv_buffer> sptr;
typedef boost::function<void(void)> release_fcn_t;
/*!
* Make a safe managed receive buffer:
* A safe managed buffer ensures that release is called once,
* either by the user or automatically upon deconstruction.
* \param buff a pointer into read-only memory
* \param size the length of the buffer in bytes
* \param release_fcn callback to release the memory
* \return a new managed receive buffer
*/
static sptr make_safe(
const void *buff, size_t size, const release_fcn_t &release_fcn
);
/*!
* Signal to the transport that we are done with the buffer.
@ -84,21 +69,6 @@ namespace uhd{ namespace transport{
class UHD_API managed_send_buffer{
public:
typedef boost::shared_ptr<managed_send_buffer> sptr;
typedef boost::function<void(size_t)> commit_fcn_t;
/*!
* Make a safe managed send buffer:
* A safe managed buffer ensures that commit is called once,
* either by the user or automatically upon deconstruction.
* In the later case, the deconstructor will call commit(0).
* \param buff a pointer into writable memory
* \param size the length of the buffer in bytes
* \param commit_fcn callback to commit the memory
* \return a new managed send buffer
*/
static sptr make_safe(
void *buff, size_t size, const commit_fcn_t &commit_fcn
);
/*!
* Signal to the transport that we are done with the buffer.

View file

@ -77,5 +77,4 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp
${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy_asio.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vrt_packet_handler.hpp
${CMAKE_CURRENT_SOURCE_DIR}/zero_copy.cpp
)

View file

@ -1,114 +0,0 @@
//
// Copyright 2010-2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <uhd/transport/zero_copy.hpp>
using namespace uhd::transport;
/***********************************************************************
* Safe managed receive buffer
**********************************************************************/
static void release_nop(void){
/* NOP */
}
class safe_managed_receive_buffer : public managed_recv_buffer{
public:
safe_managed_receive_buffer(
const void *buff, size_t size, const release_fcn_t &release_fcn
):
_buff(buff), _size(size), _release_fcn(release_fcn)
{
/* NOP */
}
~safe_managed_receive_buffer(void){
_release_fcn();
}
void release(void){
release_fcn_t release_fcn = _release_fcn;
_release_fcn = &release_nop;
return release_fcn();
}
private:
const void *get_buff(void) const{
return _buff;
}
size_t get_size(void) const{
return _size;
}
const void *_buff;
size_t _size;
release_fcn_t _release_fcn;
};
managed_recv_buffer::sptr managed_recv_buffer::make_safe(
const void *buff, size_t size, const release_fcn_t &release_fcn
){
return sptr(new safe_managed_receive_buffer(buff, size, release_fcn));
}
/***********************************************************************
* Safe managed send buffer
**********************************************************************/
static void commit_nop(size_t){
/* NOP */
}
class safe_managed_send_buffer : public managed_send_buffer{
public:
safe_managed_send_buffer(
void *buff, size_t size, const commit_fcn_t &commit_fcn
):
_buff(buff), _size(size), _commit_fcn(commit_fcn)
{
/* NOP */
}
~safe_managed_send_buffer(void){
_commit_fcn(0);
}
void commit(size_t num_bytes){
commit_fcn_t commit_fcn = _commit_fcn;
_commit_fcn = &commit_nop;
return commit_fcn(num_bytes);
}
private:
void *get_buff(void) const{
return _buff;
}
size_t get_size(void) const{
return _size;
}
void *_buff;
size_t _size;
commit_fcn_t _commit_fcn;
};
safe_managed_send_buffer::sptr managed_send_buffer::make_safe(
void *buff, size_t size, const commit_fcn_t &commit_fcn
){
return sptr(new safe_managed_send_buffer(buff, size, commit_fcn));
}

View file

@ -22,7 +22,7 @@
#include <sys/mman.h> //mmap
#include <unistd.h> //getpagesize
#include <poll.h> //poll
#include <boost/bind.hpp>
#include <vector>
#include <iostream>
using namespace uhd;
@ -32,6 +32,82 @@ static const bool fp_verbose = false; //fast-path verbose
static const bool sp_verbose = false; //slow-path verbose
static const size_t poll_breakout = 10; //how many poll timeouts constitute a full timeout
/***********************************************************************
* Reusable managed receiver buffer:
* - The buffer knows how to claim and release a frame.
**********************************************************************/
class usrp_e100_mmap_zero_copy_mrb : public managed_recv_buffer{
public:
usrp_e100_mmap_zero_copy_mrb(void *mem, ring_buffer_info *info):
_mem(mem), _info(info) { /* NOP */ }
void release(void){
if (_info->flags != RB_USER_PROCESS) return;
if (fp_verbose) std::cout << "recv buff: release" << std::endl;
_info->flags = RB_KERNEL; //release the frame
}
bool ready(void){return _info->flags & RB_USER;}
sptr get_new(void){
if (fp_verbose) std::cout << " make_recv_buff: " << get_size() << std::endl;
_info->flags = RB_USER_PROCESS; //claim the frame
return sptr(this, &usrp_e100_mmap_zero_copy_mrb::fake_deleter);
}
private:
static void fake_deleter(void *obj){
static_cast<usrp_e100_mmap_zero_copy_mrb *>(obj)->release();
}
const void *get_buff(void) const{return _mem;}
size_t get_size(void) const{return _info->len;}
void *_mem;
ring_buffer_info *_info;
};
/***********************************************************************
* Reusable managed send buffer:
* - The buffer knows how to claim and release a frame.
**********************************************************************/
class usrp_e100_mmap_zero_copy_msb : public managed_send_buffer{
public:
usrp_e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd):
_mem(mem), _info(info), _len(len), _fd(fd) { /* NOP */ }
void commit(size_t len){
if (_info->flags != RB_USER_PROCESS) return;
if (fp_verbose) std::cout << "send buff: commit " << len << std::endl;
_info->len = len;
_info->flags = RB_USER; //release the frame
if (::write(_fd, NULL, 0) < 0){ //notifies the kernel
std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl;
}
}
bool ready(void){return _info->flags & RB_KERNEL;}
sptr get_new(void){
if (fp_verbose) std::cout << " make_send_buff: " << get_size() << std::endl;
_info->flags = RB_USER_PROCESS; //claim the frame
return sptr(this, &usrp_e100_mmap_zero_copy_msb::fake_deleter);
}
private:
static void fake_deleter(void *obj){
static_cast<usrp_e100_mmap_zero_copy_msb *>(obj)->commit(0);
}
void *get_buff(void) const{return _mem;}
size_t get_size(void) const{return _len;}
void *_mem;
ring_buffer_info *_info;
size_t _len;
int _fd;
};
/***********************************************************************
* The zero copy interface implementation
**********************************************************************/
@ -81,13 +157,32 @@ public:
std::cout << "send_buff_off: " << send_buff_off << std::endl;
}
//pointers to sections in the mapped memory
ring_buffer_info (*recv_info)[], (*send_info)[];
char *recv_buff, *send_buff;
//set the internal pointers for info and buffers
typedef ring_buffer_info (*rbi_pta)[];
char *rb_ptr = reinterpret_cast<char *>(_mapped_mem);
_recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off);
_recv_buff = rb_ptr + recv_buff_off;
_send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off);
_send_buff = rb_ptr + send_buff_off;
recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off);
recv_buff = rb_ptr + recv_buff_off;
send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off);
send_buff = rb_ptr + send_buff_off;
//initialize the managed receive buffers
for (size_t i = 0; i < get_num_recv_frames(); i++){
_mrb_pool.push_back(usrp_e100_mmap_zero_copy_mrb(
recv_buff + get_recv_frame_size()*i, (*recv_info) + i
));
}
//initialize the managed send buffers
for (size_t i = 0; i < get_num_recv_frames(); i++){
_msb_pool.push_back(usrp_e100_mmap_zero_copy_msb(
send_buff + get_send_frame_size()*i, (*send_info) + i,
get_send_frame_size(), _fd
));
}
}
~usrp_e100_mmap_zero_copy_impl(void){
@ -97,13 +192,10 @@ public:
managed_recv_buffer::sptr get_recv_buff(double timeout){
if (fp_verbose) std::cout << "get_recv_buff: " << _recv_index << std::endl;
//grab pointers to the info and buffer
ring_buffer_info *info = (*_recv_info) + _recv_index;
void *mem = _recv_buff + _frame_size*_recv_index;
usrp_e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index];
//poll/wait for a ready frame
if (not (info->flags & RB_USER)){
if (not mrb.ready()){
for (size_t i = 0; i < poll_breakout; i++){
pollfd pfd;
pfd.fd = _fd;
@ -115,18 +207,11 @@ public:
return managed_recv_buffer::sptr(); //timed-out for real
} found_user_frame:
//the process has claimed the frame
info->flags = RB_USER_PROCESS;
//increment the index for the next call
if (++_recv_index == size_t(_rb_size.num_rx_frames)) _recv_index = 0;
if (++_recv_index == get_num_recv_frames()) _recv_index = 0;
//return the managed buffer for this frame
if (fp_verbose) std::cout << " make_recv_buff: " << info->len << std::endl;
return managed_recv_buffer::make_safe(
mem, info->len,
boost::bind(&usrp_e100_mmap_zero_copy_impl::release, this, info)
);
return mrb.get_new();
}
size_t get_num_recv_frames(void) const{
@ -139,13 +224,10 @@ public:
managed_send_buffer::sptr get_send_buff(double timeout){
if (fp_verbose) std::cout << "get_send_buff: " << _send_index << std::endl;
//grab pointers to the info and buffer
ring_buffer_info *info = (*_send_info) + _send_index;
void *mem = _send_buff + _frame_size*_send_index;
usrp_e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index];
//poll/wait for a ready frame
if (not (info->flags & RB_KERNEL)){
if (not msb.ready()){
pollfd pfd;
pfd.fd = _fd;
pfd.events = POLLOUT;
@ -155,14 +237,10 @@ public:
}
//increment the index for the next call
if (++_send_index == size_t(_rb_size.num_tx_frames)) _send_index = 0;
if (++_send_index == get_num_send_frames()) _send_index = 0;
//return the managed buffer for this frame
if (fp_verbose) std::cout << " make_send_buff: " << _frame_size << std::endl;
return managed_send_buffer::make_safe(
mem, _frame_size,
boost::bind(&usrp_e100_mmap_zero_copy_impl::commit, this, info, _1)
);
return msb.get_new();
}
size_t get_num_send_frames(void) const{
@ -174,21 +252,7 @@ public:
}
private:
void release(ring_buffer_info *info){
if (fp_verbose) std::cout << "recv buff: release" << std::endl;
info->flags = RB_KERNEL;
}
void commit(ring_buffer_info *info, size_t len){
if (fp_verbose) std::cout << "send buff: commit " << len << std::endl;
info->len = len;
info->flags = RB_USER;
if (::write(_fd, NULL, 0) < 0){
std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl;
}
}
//file descriptor for mmap
int _fd;
//the mapped memory itself
@ -198,9 +262,9 @@ private:
usrp_e_ring_buffer_size_t _rb_size;
size_t _frame_size, _map_size;
//pointers to sections in the mapped memory
ring_buffer_info (*_recv_info)[], (*_send_info)[];
char *_recv_buff, *_send_buff;
//re-usable managed buffers
std::vector<usrp_e100_mmap_zero_copy_mrb> _mrb_pool;
std::vector<usrp_e100_mmap_zero_copy_msb> _msb_pool;
//indexes into sub-sections of mapped memory
size_t _recv_index, _send_index;