diff options
author | Josh Blum <josh@joshknows.com> | 2011-01-19 22:23:46 -0800 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2011-01-19 22:23:46 -0800 |
commit | 9239878b0b81c3a368bf11cfc2fe48bfb05ff902 (patch) | |
tree | f41a5e58eac89b35cb99537a0a0b64662384a9f2 /host/lib/transport | |
parent | fc138381ee4bd8d191795230b7447071a85e1f28 (diff) | |
parent | 7d918c5f6acc9a5d2c8ae03e2e67b403f7efd5ff (diff) | |
download | uhd-9239878b0b81c3a368bf11cfc2fe48bfb05ff902.tar.gz uhd-9239878b0b81c3a368bf11cfc2fe48bfb05ff902.tar.bz2 uhd-9239878b0b81c3a368bf11cfc2fe48bfb05ff902.zip |
Merge branch 'next'
Conflicts:
host/lib/usrp/usrp2/codec_impl.cpp
Diffstat (limited to 'host/lib/transport')
-rw-r--r-- | host/lib/transport/CMakeLists.txt | 42 | ||||
-rw-r--r-- | host/lib/transport/buffer_pool.cpp | 80 | ||||
-rw-r--r-- | host/lib/transport/convert_types_impl.hpp | 345 | ||||
-rwxr-xr-x | host/lib/transport/gen_convert_types.py | 211 | ||||
-rw-r--r-- | host/lib/transport/libusb1_zero_copy.cpp | 29 | ||||
-rw-r--r-- | host/lib/transport/msvc/stdint.h | 35 | ||||
-rw-r--r-- | host/lib/transport/udp_zero_copy_asio.cpp | 26 | ||||
-rw-r--r-- | host/lib/transport/vrt_packet_handler.hpp | 46 |
8 files changed, 140 insertions, 674 deletions
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 0d6226e4c..8765c6703 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010 Ettus Research LLC +# 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 @@ -23,7 +23,7 @@ # Setup libusb ######################################################################## MESSAGE(STATUS "") -FIND_PACKAGE(USB1 REQUIRED) +FIND_PACKAGE(USB1) LIBUHD_REGISTER_COMPONENT("USB" ENABLE_USB ON "ENABLE_LIBUHD;LIBUSB_FOUND" OFF) @@ -37,9 +37,6 @@ IF(ENABLE_USB) ${CMAKE_CURRENT_SOURCE_DIR}/libusb1_base.cpp ${CMAKE_CURRENT_SOURCE_DIR}/libusb1_base.hpp ) - IF(MSVC) #include our custom stdint for libusb - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/msvc) - ENDIF(MSVC) ELSE(ENABLE_USB) LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/usb_dummy_impl.cpp @@ -47,25 +44,6 @@ ELSE(ENABLE_USB) ENDIF(ENABLE_USB) ######################################################################## -# Check for SIMD headers -######################################################################## -MESSAGE(STATUS "") - -INCLUDE(CheckIncludeFileCXX) -CHECK_INCLUDE_FILE_CXX(emmintrin.h HAVE_EMMINTRIN_H) - -IF(HAVE_EMMINTRIN_H) - ADD_DEFINITIONS(-DHAVE_EMMINTRIN_H) -ENDIF(HAVE_EMMINTRIN_H) - -INCLUDE(CheckIncludeFileCXX) -CHECK_INCLUDE_FILE_CXX(arm_neon.h HAVE_ARM_NEON_H) - -IF(HAVE_ARM_NEON_H) - ADD_DEFINITIONS(-DHAVE_ARM_NEON_H) -ENDIF(HAVE_ARM_NEON_H) - -######################################################################## # Setup defines for interface address discovery ######################################################################## MESSAGE(STATUS "") @@ -93,22 +71,8 @@ LIBUHD_PYTHON_GEN_SOURCE( ${CMAKE_CURRENT_BINARY_DIR}/vrt_if_packet.cpp ) -LIBUHD_PYTHON_GEN_SOURCE( - ${CMAKE_CURRENT_SOURCE_DIR}/gen_convert_types.py - ${CMAKE_CURRENT_BINARY_DIR}/convert_types.cpp -) - -# append this directory to the include path so the generated convert types -# can include the implementation convert types file in the source directory -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -# make the generated convert types depend on the implementation header -SET_SOURCE_FILES_PROPERTIES( - ${CMAKE_CURRENT_BINARY_DIR}/convert_types.cpp PROPERTIES - OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/convert_types_impl.hpp -) - 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..971bbb75a --- /dev/null +++ b/host/lib/transport/buffer_pool.cpp @@ -0,0 +1,80 @@ +// +// Copyright 2011-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/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<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<ptr_type> _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-1]); + + //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/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp deleted file mode 100644 index 48ff99725..000000000 --- a/host/lib/transport/convert_types_impl.hpp +++ /dev/null @@ -1,345 +0,0 @@ -// -// 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/>. -// - -#ifndef INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP -#define INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP - -#include <uhd/config.hpp> -#include <uhd/utils/byteswap.hpp> -#include <boost/cstdint.hpp> -#include <cstring> -#include <complex> - -#ifdef HAVE_EMMINTRIN_H - #define USE_EMMINTRIN_H //use sse2 intrinsics -#endif - -#if defined(USE_EMMINTRIN_H) - #include <emmintrin.h> -#endif - -#ifdef HAVE_ARM_NEON_H - #define USE_ARM_NEON_H -#endif - -#if defined(USE_ARM_NEON_H) - #include <arm_neon.h> -#endif - -/*********************************************************************** - * Typedefs - **********************************************************************/ -typedef std::complex<float> fc32_t; -typedef std::complex<boost::int16_t> sc16_t; -typedef boost::uint32_t item32_t; - -/*********************************************************************** - * Convert complex short buffer to items32 - **********************************************************************/ -static UHD_INLINE item32_t sc16_to_item32(sc16_t num){ - boost::uint16_t real = num.real(); - boost::uint16_t imag = num.imag(); - return (item32_t(real) << 16) | (item32_t(imag) << 0); -} - -static UHD_INLINE void sc16_to_item32_nswap( - const sc16_t *input, item32_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = sc16_to_item32(input[i]); - } -} - -static UHD_INLINE void sc16_to_item32_bswap( - const sc16_t *input, item32_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = uhd::byteswap(sc16_to_item32(input[i])); - } -} - -/*********************************************************************** - * Convert items32 buffer to complex short - **********************************************************************/ -static UHD_INLINE sc16_t item32_to_sc16(item32_t item){ - return sc16_t( - boost::int16_t(item >> 16), - boost::int16_t(item >> 0) - ); -} - -static UHD_INLINE void item32_to_sc16_nswap( - const item32_t *input, sc16_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = item32_to_sc16(input[i]); - } -} - -static UHD_INLINE void item32_to_sc16_bswap( - const item32_t *input, sc16_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = item32_to_sc16(uhd::byteswap(input[i])); - } -} - -/*********************************************************************** - * Convert complex float buffer to items32 (no swap) - **********************************************************************/ -static const float shorts_per_float = float(32767); - -static UHD_INLINE item32_t fc32_to_item32(fc32_t num){ - boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float); - boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float); - return (item32_t(real) << 16) | (item32_t(imag) << 0); -} - -//////////////////////////////////// -// none-swap -//////////////////////////////////// -#if defined(USE_EMMINTRIN_H) -static UHD_INLINE void fc32_to_item32_nswap( - const fc32_t *input, item32_t *output, size_t nsamps -){ - __m128 scalar = _mm_set_ps1(shorts_per_float); - - //convert blocks of samples with intrinsics - size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ - //load from input - __m128 tmplo = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+0)); - __m128 tmphi = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+2)); - - //convert and scale - __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); - __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); - - //pack + swap 16-bit pairs - __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); - tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); - tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); - - //store to output - _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); - } - - //convert remainder - for (; i < nsamps; i++){ - output[i] = fc32_to_item32(input[i]); - } -} - -#elif defined(USE_ARM_NEON_H) -static UHD_INLINE void fc32_to_item32_nswap( - const fc32_t *input, item32_t *output, size_t nsamps) -{ - size_t i; - - float32x4_t Q0 = vdupq_n_f32(shorts_per_float); - for (i=0; i < (nsamps & ~0x03); i+=2) { - float32x4_t Q1 = vld1q_f32(reinterpret_cast<const float *>(&input[i])); - float32x4_t Q2 = vmulq_f32(Q1, Q0); - int32x4_t Q3 = vcvtq_s32_f32(Q2); - int16x4_t D8 = vmovn_s32(Q3); - int16x4_t D9 = vrev32_s16(D8); - vst1_s16((reinterpret_cast<int16_t *>(&output[i])), D9); - } - - for (; i < nsamps; i++) - output[i] = fc32_to_item32(input[i]); -} - -#else -static UHD_INLINE void fc32_to_item32_nswap( - const fc32_t *input, item32_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = fc32_to_item32(input[i]); - } -} - -#endif - -//////////////////////////////////// -// byte-swap -//////////////////////////////////// -#if defined(USE_EMMINTRIN_H) -static UHD_INLINE void fc32_to_item32_bswap( - const fc32_t *input, item32_t *output, size_t nsamps -){ - __m128 scalar = _mm_set_ps1(shorts_per_float); - - //convert blocks of samples with intrinsics - size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ - //load from input - __m128 tmplo = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+0)); - __m128 tmphi = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+2)); - - //convert and scale - __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); - __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); - - //pack + byteswap -> byteswap 16 bit words - __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); - tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); - - //store to output - _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); - } - - //convert remainder - for (; i < nsamps; i++){ - output[i] = uhd::byteswap(fc32_to_item32(input[i])); - } -} - -#else -static UHD_INLINE void fc32_to_item32_bswap( - const fc32_t *input, item32_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = uhd::byteswap(fc32_to_item32(input[i])); - } -} - -#endif - -/*********************************************************************** - * Convert items32 buffer to complex float - **********************************************************************/ -static const float floats_per_short = float(1.0/shorts_per_float); - -static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ - return fc32_t( - float(boost::int16_t(item >> 16)*floats_per_short), - float(boost::int16_t(item >> 0)*floats_per_short) - ); -} - -//////////////////////////////////// -// none-swap -//////////////////////////////////// -#if defined(USE_EMMINTRIN_H) -static UHD_INLINE void item32_to_fc32_nswap( - const item32_t *input, fc32_t *output, size_t nsamps -){ - __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); - __m128i zeroi = _mm_setzero_si128(); - - //convert blocks of samples with intrinsics - size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ - //load from input - __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); - - //unpack + swap 16-bit pairs - tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); - tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); - __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits - __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); - - //convert and scale - __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); - __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); - - //store to output - _mm_storeu_ps(reinterpret_cast<float *>(output+i+0), tmplo); - _mm_storeu_ps(reinterpret_cast<float *>(output+i+2), tmphi); - } - - //convert remainder - for (; i < nsamps; i++){ - output[i] = item32_to_fc32(input[i]); - } -} - -#elif defined(USE_ARM_NEON_H) -static UHD_INLINE void item32_to_fc32_nswap( - const item32_t *input, fc32_t *output, size_t nsamps) -{ - size_t i; - - float32x4_t Q1 = vdupq_n_f32(floats_per_short); - for (i=0; i < (nsamps & ~0x03); i+=2) { - int16x4_t D0 = vld1_s16(reinterpret_cast<const int16_t *>(&input[i])); - int16x4_t D1 = vrev32_s16(D0); - int32x4_t Q2 = vmovl_s16(D1); - float32x4_t Q3 = vcvtq_f32_s32(Q2); - float32x4_t Q4 = vmulq_f32(Q3, Q1); - vst1q_f32((reinterpret_cast<float *>(&output[i])), Q4); - } - - for (; i < nsamps; i++) - output[i] = item32_to_fc32(input[i]); -} - -#else -static UHD_INLINE void item32_to_fc32_nswap( - const item32_t *input, fc32_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = item32_to_fc32(input[i]); - } -} -#endif - -//////////////////////////////////// -// byte-swap -//////////////////////////////////// -#if defined(USE_EMMINTRIN_H) -static UHD_INLINE void item32_to_fc32_bswap( - const item32_t *input, fc32_t *output, size_t nsamps -){ - __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); - __m128i zeroi = _mm_setzero_si128(); - - //convert blocks of samples with intrinsics - size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ - //load from input - __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); - - //byteswap + unpack -> byteswap 16 bit words - tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); - __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits - __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); - - //convert and scale - __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); - __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); - - //store to output - _mm_storeu_ps(reinterpret_cast<float *>(output+i+0), tmplo); - _mm_storeu_ps(reinterpret_cast<float *>(output+i+2), tmphi); - } - - //convert remainder - for (; i < nsamps; i++){ - output[i] = item32_to_fc32(uhd::byteswap(input[i])); - } -} - -#else -static UHD_INLINE void item32_to_fc32_bswap( - const item32_t *input, fc32_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = item32_to_fc32(uhd::byteswap(input[i])); - } -} - -#endif - -#endif /* INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP */ diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py deleted file mode 100755 index f9509c81d..000000000 --- a/host/lib/transport/gen_convert_types.py +++ /dev/null @@ -1,211 +0,0 @@ -#!/usr/bin/env python -# -# 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/>. -# - -TMPL_TEXT = """ -#import time -/*********************************************************************** - * This file was generated by $file on $time.strftime("%c") - **********************************************************************/ - -\#include <uhd/config.hpp> -\#include <uhd/transport/convert_types.hpp> -\#include <boost/cstdint.hpp> -\#include <boost/detail/endian.hpp> -\#include <stdexcept> -\#include "convert_types_impl.hpp" - -using namespace uhd; - -/*********************************************************************** - * Generate predicate for jump table - **********************************************************************/ -UHD_INLINE boost::uint8_t get_pred( - const io_type_t &io_type, - const otw_type_t &otw_type, - size_t num_chans -){ - boost::uint8_t pred = 0; - - switch(otw_type.byteorder){ - \#ifdef BOOST_BIG_ENDIAN - case otw_type_t::BO_BIG_ENDIAN: pred |= $ph.nswap_p; break; - case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.bswap_p; break; - \#else - case otw_type_t::BO_BIG_ENDIAN: pred |= $ph.bswap_p; break; - case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.nswap_p; break; - \#endif - case otw_type_t::BO_NATIVE: pred |= $ph.nswap_p; break; - default: throw std::runtime_error("unhandled otw byteorder type"); - } - - switch(otw_type.get_sample_size()){ - case sizeof(boost::uint32_t): pred |= $ph.item32_p; break; - default: throw std::runtime_error("unhandled otw sample size"); - } - - switch(io_type.tid){ - case io_type_t::COMPLEX_FLOAT32: pred |= $ph.fc32_p; break; - case io_type_t::COMPLEX_INT16: pred |= $ph.sc16_p; break; - default: throw std::runtime_error("unhandled io type id"); - } - - switch(num_chans){ - case 1: pred |= $ph.chan1_p; break; - case 2: pred |= $ph.chan2_p; break; - case 3: pred |= $ph.chan3_p; break; - case 4: pred |= $ph.chan4_p; break; - default: throw std::runtime_error("unhandled number of channels"); - } - - return pred; -} - -/*********************************************************************** - * Convert host type to device type - **********************************************************************/ -void transport::convert_io_type_to_otw_type( - const std::vector<const void *> &io_buffs, - const io_type_t &io_type, - void *otw_buff, - const otw_type_t &otw_type, - size_t nsamps_per_io_buff -){ - switch(get_pred(io_type, otw_type, io_buffs.size())){ - #for $pred in range(2**$ph.nbits) - case $pred: - #set $out_type = $ph.get_dev_type($pred) - #set $in_type = $ph.get_host_type($pred) - #set $num_chans = $ph.get_num_chans($pred) - #set $converter = '_'.join([$in_type, 'to', $out_type]) - #if $num_chans == 1 - $(converter)_$ph.get_swap_type($pred)( - reinterpret_cast<const $(in_type)_t *>(io_buffs.front()), - reinterpret_cast<$(out_type)_t *>(otw_buff), - nsamps_per_io_buff - ); - #else - for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){ - #for $j in range($num_chans) - reinterpret_cast<$(out_type)_t *>(otw_buff)[j++] = - #if $ph.get_swap_type($pred) == 'bswap' - uhd::byteswap($(converter)(reinterpret_cast<const $(in_type)_t *>(io_buffs[$j])[i])); - #else - $(converter)(reinterpret_cast<const $(in_type)_t *>(io_buffs[$j])[i]); - #end if - #end for - } - #end if - break; - #end for - } -} - -/*********************************************************************** - * Convert device type to host type - **********************************************************************/ -void transport::convert_otw_type_to_io_type( - const void *otw_buff, - const otw_type_t &otw_type, - std::vector<void *> &io_buffs, - const io_type_t &io_type, - size_t nsamps_per_io_buff -){ - switch(get_pred(io_type, otw_type, io_buffs.size())){ - #for $pred in range(2**$ph.nbits) - case $pred: - #set $out_type = $ph.get_host_type($pred) - #set $in_type = $ph.get_dev_type($pred) - #set $num_chans = $ph.get_num_chans($pred) - #set $converter = '_'.join([$in_type, 'to', $out_type]) - #if $num_chans == 1 - $(converter)_$ph.get_swap_type($pred)( - reinterpret_cast<const $(in_type)_t *>(otw_buff), - reinterpret_cast<$(out_type)_t *>(io_buffs.front()), - nsamps_per_io_buff - ); - #else - for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){ - #for $j in range($num_chans) - reinterpret_cast<$(out_type)_t *>(io_buffs[$j])[i] = - #if $ph.get_swap_type($pred) == 'bswap' - $(converter)(uhd::byteswap(reinterpret_cast<const $(in_type)_t *>(otw_buff)[j++])); - #else - $(converter)(reinterpret_cast<const $(in_type)_t *>(otw_buff)[j++]); - #end if - #end for - } - #end if - break; - #end for - } -} - -""" - -def parse_tmpl(_tmpl_text, **kwargs): - from Cheetah.Template import Template - return str(Template(_tmpl_text, kwargs)) - -class ph: - bswap_p = 0b00001 - nswap_p = 0b00000 - item32_p = 0b00000 - sc16_p = 0b00010 - fc32_p = 0b00000 - chan1_p = 0b00000 - chan2_p = 0b00100 - chan3_p = 0b01000 - chan4_p = 0b01100 - - nbits = 4 #see above - - @staticmethod - def has(pred, mask, flag): return (pred & mask) == flag - - @staticmethod - def get_swap_type(pred): - mask = 0b1 - if ph.has(pred, mask, ph.bswap_p): return 'bswap' - if ph.has(pred, mask, ph.nswap_p): return 'nswap' - raise NotImplementedError - - @staticmethod - def get_dev_type(pred): - mask = 0b0 - if ph.has(pred, mask, ph.item32_p): return 'item32' - raise NotImplementedError - - @staticmethod - def get_host_type(pred): - mask = 0b10 - if ph.has(pred, mask, ph.sc16_p): return 'sc16' - if ph.has(pred, mask, ph.fc32_p): return 'fc32' - raise NotImplementedError - - @staticmethod - def get_num_chans(pred): - mask = 0b1100 - if ph.has(pred, mask, ph.chan1_p): return 1 - if ph.has(pred, mask, ph.chan2_p): return 2 - if ph.has(pred, mask, ph.chan3_p): return 3 - if ph.has(pred, mask, ph.chan4_p): return 4 - raise NotImplementedError - -if __name__ == '__main__': - import sys - open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=__file__, ph=ph)) diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index f589d7c77..adc590284 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// 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 @@ -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); @@ -134,7 +134,6 @@ static void callback(libusb_transfer *lut){ * \param pointer to libusb_transfer */ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut){ - boost::this_thread::disable_interruption di; //disable because the wait can throw _completed_list->push_with_wait(lut); } @@ -157,9 +156,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 @@ -272,7 +271,6 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut){ } libusb_transfer *usb_endpoint::get_lut_with_wait(double timeout){ - boost::this_thread::disable_interruption di; //disable because the wait can throw libusb_transfer *lut; if (_completed_list->pop_with_timed_wait(lut, timeout)) return lut; return NULL; @@ -293,6 +291,7 @@ public: ~libusb_zero_copy_impl(void){ _threads_running = false; + _thread_group.interrupt_all(); _thread_group.join_all(); } @@ -333,12 +332,14 @@ private: set_thread_priority_safe(); libusb::session::sptr session = libusb::session::get_global_session(); _threads_running = true; - while(_threads_running){ - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 100000; //100ms - libusb_handle_events_timeout(session->get_context(), &tv); - } + try{ + while(_threads_running){ + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100000; //100ms + libusb_handle_events_timeout(session->get_context(), &tv); + } + } catch(const boost::thread_interrupted &){} } }; diff --git a/host/lib/transport/msvc/stdint.h b/host/lib/transport/msvc/stdint.h deleted file mode 100644 index b3eb61aae..000000000 --- a/host/lib/transport/msvc/stdint.h +++ /dev/null @@ -1,35 +0,0 @@ -//
-// 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/>.
-//
-
-#ifndef INCLUDED_LIBUHD_TRANSPORT_STDINT_H
-#define INCLUDED_LIBUHD_TRANSPORT_STDINT_H
-
-#include <boost/cstdint.hpp>
-
-//provide a stdint implementation for libusb
-
-typedef boost::uint64_t uint64_t;
-typedef boost::uint32_t uint32_t;
-typedef boost::uint16_t uint16_t;
-typedef boost::uint8_t uint8_t;
-
-typedef boost::int64_t int64_t;
-typedef boost::int32_t int32_t;
-typedef boost::int16_t int16_t;
-typedef boost::int8_t int8_t;
-
-#endif /* INCLUDED_LIBUHD_TRANSPORT_STDINT_H */
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index c758fa894..5c049cfad 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// 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 @@ -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> @@ -37,14 +37,15 @@ namespace asio = boost::asio; **********************************************************************/ //Define this to the the boost async io calls to perform receive. //Otherwise, get_recv_buff uses a blocking receive with timeout. -//#define USE_ASIO_ASYNC_RECV +#define USE_ASIO_ASYNC_RECV //Define this to the the boost async io calls to perform send. //Otherwise, the commit callback uses a blocking send. //#define USE_ASIO_ASYNC_SEND -//enough buffering for half a second of samples at full rate on usrp2 -static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(4 * 25e6 * 0.5); +//By default, this buffer is sized insufficiently small. +//For peformance, this buffer should be 10s of megabytes. +static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(10e3); //Large buffers cause more underflow at high rates. //Perhaps this is due to the kernel scheduling, @@ -123,16 +124,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 +303,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; @@ -321,12 +322,13 @@ private: **********************************************************************/ template<typename Opt> static void resize_buff_helper( udp_zero_copy_asio_impl::sptr udp_trans, - size_t target_size, + const size_t target_size, const std::string &name ){ size_t min_sock_buff_size = 0; if (name == "recv") min_sock_buff_size = MIN_RECV_SOCK_BUFF_SIZE; if (name == "send") min_sock_buff_size = MIN_SEND_SOCK_BUFF_SIZE; + min_sock_buff_size = std::max(min_sock_buff_size, target_size); std::string help_message; #if defined(UHD_PLATFORM_LINUX) @@ -347,7 +349,7 @@ template<typename Opt> static void resize_buff_helper( ) % name % actual_size << std::endl; if (actual_size < target_size) uhd::warning::post(str(boost::format( "The %s buffer is smaller than the requested size.\n" - "The minimum recommended buffer size is %d bytes.\n" + "The minimum requested buffer size is %d bytes.\n" "See the transport application notes on buffer resizing.\n%s" ) % name % min_sock_buff_size % help_message)); } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 278bcfeaa..c535edd04 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// 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 @@ -26,7 +26,7 @@ #include <uhd/types/otw_type.hpp> #include <uhd/types/metadata.hpp> #include <uhd/transport/vrt_if_packet.hpp> -#include <uhd/transport/convert_types.hpp> +#include <uhd/convert.hpp> #include <uhd/transport/zero_copy.hpp> #include <boost/function.hpp> #include <stdexcept> @@ -35,6 +35,9 @@ namespace vrt_packet_handler{ +//this may change in the future but its a constant for now +static const size_t OTW_BYTES_PER_SAMP = sizeof(boost::uint32_t); + template <typename T> UHD_INLINE T get_context_code( const boost::uint32_t *vrt_hdr, const uhd::transport::vrt::if_packet_info_t &if_packet_info @@ -91,6 +94,7 @@ template <typename T> UHD_INLINE T get_context_code( //vrt unpack each managed buffer uhd::transport::vrt::if_packet_info_t if_packet_info; for (size_t i = 0; i < state.width; i++){ + if (state.managed_buffs[i].get() == NULL) continue; //better have a message packet coming up... //extract packet words and check thats its enough to move on size_t num_packet_words32 = state.managed_buffs[i]->size()/sizeof(boost::uint32_t); @@ -144,8 +148,7 @@ template <typename T> UHD_INLINE T get_context_code( size_t offset_bytes, size_t total_samps, uhd::rx_metadata_t &metadata, - const uhd::io_type_t &io_type, - const uhd::otw_type_t &otw_type, + uhd::convert::function_type &converter, double tick_rate, const vrt_unpacker_t &vrt_unpacker, const get_recv_buffs_t &get_recv_buffs, @@ -183,7 +186,7 @@ template <typename T> UHD_INLINE T get_context_code( } //extract the number of samples available to copy - size_t bytes_per_item = otw_type.get_sample_size(); + size_t bytes_per_item = OTW_BYTES_PER_SAMP; size_t nsamps_available = state.size_of_copy_buffs/bytes_per_item; size_t nsamps_to_copy = std::min(total_samps*chans_per_otw_buff, nsamps_available); size_t bytes_to_copy = nsamps_to_copy*bytes_per_item; @@ -198,9 +201,8 @@ template <typename T> UHD_INLINE T get_context_code( } //copy-convert the samples from the recv buffer - uhd::transport::convert_otw_type_to_io_type( - state.copy_buffs[i], otw_type, io_buffs, io_type, nsamps_to_copy_per_io_buff - ); + uhd::convert::input_type otw_buffs(1, state.copy_buffs[i]); + converter(otw_buffs, io_buffs, nsamps_to_copy_per_io_buff); //update the rx copy buffer to reflect the bytes copied state.copy_buffs[i] += bytes_to_copy; @@ -234,6 +236,11 @@ template <typename T> UHD_INLINE T get_context_code( size_t vrt_header_offset_words32 = 0, size_t chans_per_otw_buff = 1 ){ + uhd::convert::function_type converter( + uhd::convert::get_converter_otw_to_cpu( + io_type, otw_type, 1, chans_per_otw_buff + )); + switch(recv_mode){ //////////////////////////////////////////////////////////////// @@ -244,7 +251,7 @@ template <typename T> UHD_INLINE T get_context_code( buffs, 0, total_num_samps, metadata, - io_type, otw_type, + converter, tick_rate, vrt_unpacker, get_recv_buffs, @@ -265,7 +272,7 @@ template <typename T> UHD_INLINE T get_context_code( buffs, accum_num_samps*io_type.size, total_num_samps - accum_num_samps, (accum_num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept - io_type, otw_type, + converter, tick_rate, vrt_unpacker, get_recv_buffs, @@ -309,15 +316,14 @@ template <typename T> UHD_INLINE T get_context_code( const size_t offset_bytes, const size_t num_samps, uhd::transport::vrt::if_packet_info_t &if_packet_info, - const uhd::io_type_t &io_type, - const uhd::otw_type_t &otw_type, + uhd::convert::function_type &converter, const vrt_packer_t &vrt_packer, const get_send_buffs_t &get_send_buffs, const size_t vrt_header_offset_words32, const size_t chans_per_otw_buff ){ //load the rest of the if_packet_info in here - if_packet_info.num_payload_words32 = (num_samps*chans_per_otw_buff*otw_type.get_sample_size())/sizeof(boost::uint32_t); + if_packet_info.num_payload_words32 = (num_samps*chans_per_otw_buff*OTW_BYTES_PER_SAMP)/sizeof(boost::uint32_t); if_packet_info.packet_count = state.next_packet_seq; //get send buffers for each channel @@ -337,9 +343,8 @@ template <typename T> UHD_INLINE T get_context_code( otw_mem += if_packet_info.num_header_words32; //copy-convert the samples into the send buffer - uhd::transport::convert_io_type_to_otw_type( - io_buffs, io_type, otw_mem, otw_type, num_samps - ); + uhd::convert::output_type otw_buffs(1, otw_mem); + converter(io_buffs, otw_buffs, num_samps); //commit the samples to the zero-copy interface size_t num_bytes_total = (vrt_header_offset_words32+if_packet_info.num_packet_words32)*sizeof(boost::uint32_t); @@ -367,6 +372,11 @@ template <typename T> UHD_INLINE T get_context_code( size_t vrt_header_offset_words32 = 0, size_t chans_per_otw_buff = 1 ){ + uhd::convert::function_type converter( + uhd::convert::get_converter_cpu_to_otw( + io_type, otw_type, chans_per_otw_buff, 1 + )); + //translate the metadata to vrt if packet info uhd::transport::vrt::if_packet_info_t if_packet_info; if_packet_info.has_sid = false; @@ -402,7 +412,7 @@ template <typename T> UHD_INLINE T get_context_code( buffs_, 0, std::min(total_num_samps_, max_samples_per_packet), if_packet_info, - io_type, otw_type, + converter, vrt_packer, get_send_buffs, vrt_header_offset_words32, @@ -435,7 +445,7 @@ template <typename T> UHD_INLINE T get_context_code( buffs, total_num_samps_sent*io_type.size, std::min(total_num_samps_unsent, max_samples_per_packet), if_packet_info, - io_type, otw_type, + converter, vrt_packer, get_send_buffs, vrt_header_offset_words32, |