From ed6a2941f8e144e5f02a7a34c9d4764c65174617 Mon Sep 17 00:00:00 2001
From: Josh Blum <josh@joshknows.com>
Date: Mon, 3 Jan 2011 01:43:48 -0800
Subject: uhd: created buffer pool to allocate aligned memory, and implemented
 in transports

---
 host/lib/transport/CMakeLists.txt         |  1 +
 host/lib/transport/buffer_pool.cpp        | 80 +++++++++++++++++++++++++++++++
 host/lib/transport/libusb1_zero_copy.cpp  | 10 ++--
 host/lib/transport/udp_zero_copy_asio.cpp | 12 ++---
 4 files changed, 92 insertions(+), 11 deletions(-)
 create mode 100644 host/lib/transport/buffer_pool.cpp

(limited to 'host/lib')

diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index 0d6226e4c..4bfe03b10 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -109,6 +109,7 @@ SET_SOURCE_FILES_PROPERTIES(
 )
 
 LIBUHD_APPEND_SOURCES(
+    ${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy_asio.cpp
diff --git a/host/lib/transport/buffer_pool.cpp b/host/lib/transport/buffer_pool.cpp
new file mode 100644
index 000000000..9a9ddfedf
--- /dev/null
+++ b/host/lib/transport/buffer_pool.cpp
@@ -0,0 +1,80 @@
+//
+// Copyright 2010 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/buffer_pool.hpp>
+#include <boost/shared_array.hpp>
+#include <vector>
+
+using namespace uhd::transport;
+
+//! pad the byte count to a multiple of alignment
+static size_t pad_to_boundary(const size_t bytes, const size_t alignment){
+    return bytes + (alignment - bytes)%alignment;
+}
+
+/***********************************************************************
+ * Buffer pool implementation
+ **********************************************************************/
+class buffer_pool_impl : public buffer_pool{
+public:
+    buffer_pool_impl(
+        const std::vector<buffer_pool::ptr_type> &ptrs,
+        boost::shared_array<char> mem
+    ): _ptrs(ptrs), _mem(mem){
+        /* NOP */
+    }
+
+    ptr_type at(const size_t index) const{
+        return _ptrs.at(index);
+    }
+
+    size_t size(void) const{
+        return _ptrs.size();
+    }
+
+private:
+    std::vector<void *> _ptrs;
+    boost::shared_array<char> _mem;
+};
+
+/***********************************************************************
+ * Buffer pool factor function
+ **********************************************************************/
+buffer_pool::sptr buffer_pool::make(
+    const size_t num_buffs,
+    const size_t buff_size,
+    const size_t alignment
+){
+    //1) pad the buffer size to be a multiple of alignment
+    //2) pad the overall memory size for room after alignment
+    //3) allocate the memory in one block of sufficient size
+    const size_t padded_buff_size = pad_to_boundary(buff_size, alignment);
+    boost::shared_array<char> mem(new char[padded_buff_size*num_buffs + alignment]);
+
+    //Fill a vector with boundary-aligned points in the memory
+    const size_t mem_start = pad_to_boundary(size_t(mem.get()), alignment);
+    std::vector<ptr_type> ptrs(num_buffs);
+    for (size_t i = 0; i < num_buffs; i++){
+        ptrs[i] = ptr_type(mem_start + padded_buff_size*i);
+    }
+
+    //Create a new buffer pool implementation with:
+    // - the pre-computed pointers, and
+    // - the reference to allocated memory.
+    return sptr(new buffer_pool_impl(ptrs, mem));
+}
+
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index f589d7c77..5dc230527 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -18,9 +18,9 @@
 #include "libusb1_base.hpp"
 #include <uhd/transport/usb_zero_copy.hpp>
 #include <uhd/transport/bounded_buffer.hpp>
+#include <uhd/transport/buffer_pool.hpp>
 #include <uhd/utils/thread_priority.hpp>
 #include <uhd/utils/assert.hpp>
-#include <boost/shared_array.hpp>
 #include <boost/foreach.hpp>
 #include <boost/thread.hpp>
 #include <boost/enable_shared_from_this.hpp>
@@ -105,8 +105,8 @@ private:
     //! a list of all transfer structs we allocated
     std::vector<libusb_transfer *> _all_luts;
 
-    //! a block of memory for the transfer buffers
-    boost::shared_array<char> _buffer;
+    //! memory allocated for the transfer buffers
+    buffer_pool::sptr _buffer_pool;
 
     // Calls for processing asynchronous I/O
     libusb_transfer *allocate_transfer(void *mem, size_t len);
@@ -157,9 +157,9 @@ usb_endpoint::usb_endpoint(
     _input(input)
 {
     _completed_list = lut_buff_type::make(num_transfers);
-    _buffer = boost::shared_array<char>(new char[num_transfers*transfer_size]);
+    _buffer_pool = buffer_pool::make(num_transfers, transfer_size);
     for (size_t i = 0; i < num_transfers; i++){
-        _all_luts.push_back(allocate_transfer(_buffer.get() + i*transfer_size, transfer_size));
+        _all_luts.push_back(allocate_transfer(_buffer_pool->at(i), transfer_size));
 
         //input luts are immediately submitted to be filled
         //output luts go into the completed list as free buffers
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index c758fa894..d979f4377 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -18,10 +18,10 @@
 #include <uhd/transport/udp_zero_copy.hpp>
 #include <uhd/transport/udp_simple.hpp> //mtu
 #include <uhd/transport/bounded_buffer.hpp>
+#include <uhd/transport/buffer_pool.hpp>
 #include <uhd/utils/thread_priority.hpp>
 #include <uhd/utils/assert.hpp>
 #include <uhd/utils/warning.hpp>
-#include <boost/shared_array.hpp>
 #include <boost/asio.hpp>
 #include <boost/format.hpp>
 #include <boost/thread.hpp>
@@ -123,16 +123,16 @@ public:
     void init(void){
         //allocate all recv frames and release them to begin xfers
         _pending_recv_buffs = pending_buffs_type::make(_num_recv_frames);
-        _recv_buffer = boost::shared_array<char>(new char[_num_recv_frames*_recv_frame_size]);
+        _recv_buffer_pool = buffer_pool::make(_num_recv_frames, _recv_frame_size);
         for (size_t i = 0; i < _num_recv_frames; i++){
-            release(_recv_buffer.get() + i*_recv_frame_size);
+            release(_recv_buffer_pool->at(i));
         }
 
         //allocate all send frames and push them into the fifo
         _pending_send_buffs = pending_buffs_type::make(_num_send_frames);
-        _send_buffer = boost::shared_array<char>(new char[_num_send_frames*_send_frame_size]);
+        _send_buffer_pool = buffer_pool::make(_num_send_frames, _send_frame_size);
         for (size_t i = 0; i < _num_send_frames; i++){
-            handle_send(_send_buffer.get() + i*_send_frame_size);
+            handle_send(_send_buffer_pool->at(i));
         }
 
         //spawn the service threads that will run the io service
@@ -302,7 +302,7 @@ public:
 private:
     //memory management -> buffers and fifos
     boost::thread_group _thread_group;
-    boost::shared_array<char> _send_buffer, _recv_buffer;
+    buffer_pool::sptr _send_buffer_pool, _recv_buffer_pool;
     typedef bounded_buffer<asio::mutable_buffer> pending_buffs_type;
     pending_buffs_type::sptr _pending_recv_buffs, _pending_send_buffs;
     const size_t _recv_frame_size, _num_recv_frames;
-- 
cgit v1.2.3