diff options
Diffstat (limited to 'gnuradio-core/src')
25 files changed, 832 insertions, 27 deletions
diff --git a/gnuradio-core/src/examples/mp-sched/CMakeLists.txt b/gnuradio-core/src/examples/mp-sched/CMakeLists.txt index dc47d17f9..d2d910ecf 100644 --- a/gnuradio-core/src/examples/mp-sched/CMakeLists.txt +++ b/gnuradio-core/src/examples/mp-sched/CMakeLists.txt @@ -20,6 +20,7 @@ include(GrPython) GR_PYTHON_INSTALL(PROGRAMS + affinity_set.py plot_flops.py run_synthetic.py synthetic.py diff --git a/gnuradio-core/src/examples/mp-sched/affinity_set.py b/gnuradio-core/src/examples/mp-sched/affinity_set.py new file mode 100755 index 000000000..6db632e0f --- /dev/null +++ b/gnuradio-core/src/examples/mp-sched/affinity_set.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +################################################## +# Gnuradio Python Flow Graph +# Title: Affinity Set Test +################################################## + +from gnuradio import eng_notation +from gnuradio import gr +from gnuradio.eng_option import eng_option +from gnuradio.gr import firdes +from optparse import OptionParser +import sys + +class affinity_set(gr.top_block): + + def __init__(self): + gr.top_block.__init__(self, "Affinity Set Test") + + ################################################## + # Variables + ################################################## + self.samp_rate = samp_rate = 32000 + + ################################################## + # Blocks + ################################################## + vec_len = 1 + self.gr_throttle_0 = gr.throttle(gr.sizeof_gr_complex*vec_len, samp_rate) + self.gr_null_source_0 = gr.null_source(gr.sizeof_gr_complex*vec_len) + self.gr_null_sink_0 = gr.null_sink(gr.sizeof_gr_complex*vec_len) + self.gr_filt_0 = gr.fir_filter_ccc(1, 40000*[0.2+0.3j,]) + self.gr_filt_1 = gr.fir_filter_ccc(1, 40000*[0.2+0.3j,]) + + self.gr_filt_0.set_processor_affinity([0,]) + self.gr_filt_1.set_processor_affinity([0,1]) + + ################################################## + # Connections + ################################################## + self.connect((self.gr_null_source_0, 0), (self.gr_throttle_0, 0)) + self.connect((self.gr_throttle_0, 0), (self.gr_filt_0, 0)) + self.connect((self.gr_filt_0, 0), (self.gr_filt_1, 0)) + self.connect((self.gr_filt_1, 0), (self.gr_null_sink_0, 0)) + + + # QT sink close method reimplementation + + def get_samp_rate(self): + return self.samp_rate + + def set_samp_rate(self, samp_rate): + self.samp_rate = samp_rate + +if __name__ == '__main__': + parser = OptionParser(option_class=eng_option, usage="%prog: [options]") + (options, args) = parser.parse_args() + tb = affinity_set() + tb.start() + + while(1): + ret = raw_input('Press Enter to quit: ') + if(len(ret) == 0): + tb.stop() + sys.exit(0) + elif(ret.lower() == "none"): + tb.gr_filt_0.unset_processor_affinity() + else: + try: + n = int(ret) + except ValueError: + print "Invalid number" + else: + tb.gr_filt_0.set_processor_affinity([n,]) diff --git a/gnuradio-core/src/lib/general/CMakeLists.txt b/gnuradio-core/src/lib/general/CMakeLists.txt index 4c99acfc3..ce9a80f37 100644 --- a/gnuradio-core/src/lib/general/CMakeLists.txt +++ b/gnuradio-core/src/lib/general/CMakeLists.txt @@ -259,6 +259,7 @@ set(gr_core_general_triple_threats gr_pwr_squelch_cc gr_pwr_squelch_ff gr_quadrature_demod_cf + gr_random_pdu gr_rail_ff gr_regenerate_bb gr_remez diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i index 1446088a2..b727bc8a6 100644 --- a/gnuradio-core/src/lib/general/general.i +++ b/gnuradio-core/src/lib/general/general.i @@ -70,6 +70,7 @@ #include <gr_agc_cc.h> #include <gr_agc2_ff.h> #include <gr_agc2_cc.h> +#include <gr_random_pdu.h> #include <gr_rms_cf.h> #include <gr_rms_ff.h> #include <gr_nlog10_ff.h> @@ -194,6 +195,7 @@ %include "gr_agc_cc.i" %include "gr_agc2_ff.i" %include "gr_agc2_cc.i" +%include "gr_random_pdu.i" %include "gr_rms_cf.i" %include "gr_rms_ff.i" %include "gr_nlog10_ff.i" diff --git a/gnuradio-core/src/lib/gengen/CMakeLists.txt b/gnuradio-core/src/lib/gengen/CMakeLists.txt index b44a47075..db3103a26 100644 --- a/gnuradio-core/src/lib/gengen/CMakeLists.txt +++ b/gnuradio-core/src/lib/gengen/CMakeLists.txt @@ -85,6 +85,7 @@ expand_h_cc_i(gr_vector_source_X b s i f c) expand_h_cc_i(gr_vector_insert_X b) expand_h_cc_i(gr_vector_sink_X b s i f c) expand_h_cc_i(gr_noise_source_X s i f c) +expand_h_cc_i(gr_fastnoise_source_X s i f c) expand_h_cc_i(gr_sig_source_X s i f c) expand_h_cc_i(gr_probe_signal_X b s i f c) expand_h_cc_i(gr_probe_signal_vX b s i f c) diff --git a/gnuradio-core/src/lib/gengen/gr_fastnoise_source_X.cc.t b/gnuradio-core/src/lib/gengen/gr_fastnoise_source_X.cc.t new file mode 100644 index 000000000..7be7bdde8 --- /dev/null +++ b/gnuradio-core/src/lib/gengen/gr_fastnoise_source_X.cc.t @@ -0,0 +1,116 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +// @WARNING@ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <@NAME@.h> +#include <gr_io_signature.h> +#include <stdexcept> + + +@NAME@_sptr +gr_make_@BASE_NAME@ (gr_noise_type_t type, float ampl, long seed, long samples) +{ + return gnuradio::get_initial_sptr(new @NAME@ (type, ampl, seed, samples)); +} + + +@NAME@::@NAME@ (gr_noise_type_t type, float ampl, long seed, long samples) + : gr_sync_block ("@BASE_NAME@", + gr_make_io_signature (0, 0, 0), + gr_make_io_signature (1, 1, sizeof (@TYPE@))), + d_type (type), + d_ampl (ampl), + d_rng (seed) +{ + d_samples.resize(samples); + generate(); +} + +void +@NAME@::generate() +{ + int noutput_items = d_samples.size(); + switch (d_type){ +#if @IS_COMPLEX@ // complex? + + case GR_UNIFORM: + for (int i = 0; i < noutput_items; i++) + d_samples[i] = gr_complex (d_ampl * ((d_rng.ran1 () * 2.0) - 1.0), + d_ampl * ((d_rng.ran1 () * 2.0) - 1.0)); + break; + + case GR_GAUSSIAN: + for (int i = 0; i < noutput_items; i++) + d_samples[i] = d_ampl * d_rng.rayleigh_complex (); + break; + +#else // nope... + + case GR_UNIFORM: + for (int i = 0; i < noutput_items; i++) + d_samples[i] = (@TYPE@)(d_ampl * ((d_rng.ran1 () * 2.0) - 1.0)); + break; + + case GR_GAUSSIAN: + for (int i = 0; i < noutput_items; i++) + d_samples[i] = (@TYPE@)(d_ampl * d_rng.gasdev ()); + break; + + case GR_LAPLACIAN: + for (int i = 0; i < noutput_items; i++) + d_samples[i] = (@TYPE@)(d_ampl * d_rng.laplacian ()); + break; + + case GR_IMPULSE: // FIXME changeable impulse settings + for (int i = 0; i < noutput_items; i++) + d_samples[i] = (@TYPE@)(d_ampl * d_rng.impulse (9)); + break; +#endif + + default: + throw std::runtime_error ("invalid type"); + } + +} + +int +@NAME@::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + @TYPE@ *out = (@TYPE@ *) output_items[0]; + + for(int i=0; i<noutput_items; i++){ +#ifdef __USE_GNU + size_t idx = lrand48() % d_samples.size(); +#else + size_t idx = rand() % d_samples.size(); +#endif + out[i] = d_samples[idx]; + } + + return noutput_items; +} diff --git a/gnuradio-core/src/lib/gengen/gr_fastnoise_source_X.h.t b/gnuradio-core/src/lib/gengen/gr_fastnoise_source_X.h.t new file mode 100644 index 000000000..007e44975 --- /dev/null +++ b/gnuradio-core/src/lib/gengen/gr_fastnoise_source_X.h.t @@ -0,0 +1,87 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +// @WARNING@ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include <gr_core_api.h> +#include <gr_sync_block.h> +#include <gr_noise_type.h> +#include <gr_random.h> + + +class @NAME@; +typedef boost::shared_ptr<@NAME@> @NAME@_sptr; + +/*! \brief Make a noise source + * \param type the random distribution to use (see gr_noise_type.h) + * \param ampl a scaling factor for the output + * \param seed seed for random generators. Note that for uniform and + * Gaussian distributions, this should be a negative number. + * \param samples number of samples to pre-generate. + */ +GR_CORE_API @NAME@_sptr +gr_make_@BASE_NAME@ (gr_noise_type_t type, float ampl, long seed = 0, long samples=1024*16); + +/*! + * \brief Random number source + * \ingroup source_blk + * + * \details + * Generate random values from different distributions. + * Currently, only Gaussian and uniform are enabled. + * + * \param type the random distribution to use (see gr_noise_type.h) + * \param ampl a scaling factor for the output + * \param seed seed for random generators. Note that for uniform and + * Gaussian distributions, this should be a negative number. + * \param samples number of samples to pre-generate. + */ +class GR_CORE_API @NAME@ : public gr_sync_block { + friend GR_CORE_API @NAME@_sptr + + gr_make_@BASE_NAME@ (gr_noise_type_t type, float ampl, long seed, long samples); + + gr_noise_type_t d_type; + float d_ampl; + gr_random d_rng; + std::vector<@TYPE@> d_samples; + + @NAME@ (gr_noise_type_t type, float ampl, long seed = 0, long samples=1024*16); + + public: + void set_type (gr_noise_type_t type) { d_type = type; generate(); } + void set_amplitude (float ampl) { d_ampl = ampl; generate(); } + void generate(); + + gr_noise_type_t type () const { return d_type; } + float amplitude () const { return d_ampl; } + + virtual int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + + +#endif diff --git a/gnuradio-core/src/lib/gengen/gr_fastnoise_source_X.i.t b/gnuradio-core/src/lib/gengen/gr_fastnoise_source_X.i.t new file mode 100644 index 000000000..e1f7c775b --- /dev/null +++ b/gnuradio-core/src/lib/gengen/gr_fastnoise_source_X.i.t @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +// @WARNING@ + +GR_SWIG_BLOCK_MAGIC(gr,@BASE_NAME@); + +@NAME@_sptr +gr_make_@BASE_NAME@ (gr_noise_type_t type, float ampl, long seed = 0, long samples = 1024*16); + +class @NAME@ : public gr_block { + private: + @NAME@ (gr_noise_type_t type, float ampl, long seed = 0, long samples = 1024*16); + + public: + void set_type (gr_noise_type_t type) { d_type = type; } + void set_amplitude (float ampl) { d_ampl = ampl; } + + gr_noise_type_t type () const { return d_type; } + float amplitude () const { return d_ampl; } +}; diff --git a/gnuradio-core/src/lib/hier/gr_channel_model.cc b/gnuradio-core/src/lib/hier/gr_channel_model.cc index bb01972d2..7da357809 100644 --- a/gnuradio-core/src/lib/hier/gr_channel_model.cc +++ b/gnuradio-core/src/lib/hier/gr_channel_model.cc @@ -59,7 +59,7 @@ gr_channel_model::gr_channel_model(double noise_voltage, d_multipath = gr_make_fir_filter_ccc(1, d_taps); d_noise_adder = gr_make_add_cc(); - d_noise = gr_make_noise_source_c(GR_GAUSSIAN, noise_voltage, noise_seed); + d_noise = gr_make_fastnoise_source_c(GR_GAUSSIAN, noise_voltage, noise_seed, 1024*8); d_freq_offset = gr_make_sig_source_c(1, GR_SIN_WAVE, frequency_offset, 1.0, 0.0); d_mixer_offset = gr_make_multiply_cc(); diff --git a/gnuradio-core/src/lib/hier/gr_channel_model.h b/gnuradio-core/src/lib/hier/gr_channel_model.h index f0b31b1a6..5796a6db2 100644 --- a/gnuradio-core/src/lib/hier/gr_channel_model.h +++ b/gnuradio-core/src/lib/hier/gr_channel_model.h @@ -25,7 +25,7 @@ #include <gr_sig_source_c.h> #include <gr_fir_filter_ccc.h> #include <gr_add_cc.h> -#include <gr_noise_source_c.h> +#include <gr_fastnoise_source_c.h> #include <gr_multiply_cc.h> class gr_channel_model; @@ -61,7 +61,7 @@ class GR_CORE_API gr_channel_model : public gr_hier_block2 gr_sig_source_c_sptr d_freq_offset; gr_fir_filter_ccc_sptr d_multipath; gr_add_cc_sptr d_noise_adder; - gr_noise_source_c_sptr d_noise; + gr_fastnoise_source_c_sptr d_noise; gr_multiply_cc_sptr d_mixer_offset; std::vector<gr_complex> d_taps; diff --git a/gnuradio-core/src/lib/io/gr_file_source.cc b/gnuradio-core/src/lib/io/gr_file_source.cc index 09f3986cd..f3def0721 100644 --- a/gnuradio-core/src/lib/io/gr_file_source.cc +++ b/gnuradio-core/src/lib/io/gr_file_source.cc @@ -89,7 +89,7 @@ gr_file_source::work (int noutput_items, if(d_fp == NULL) throw std::runtime_error("work with file not open"); - boost::mutex::scoped_lock lock(fp_mutex); // hold for the rest of this function + gruel::scoped_lock lock(fp_mutex); // hold for the rest of this function while (size) { i = fread(o, d_itemsize, size, (FILE *) d_fp); @@ -129,7 +129,7 @@ bool gr_file_source::seek (long seek_point, int whence) { // obtain exclusive access for duration of this function - boost::mutex::scoped_lock lock(fp_mutex); + gruel::scoped_lock lock(fp_mutex); return fseek((FILE *) d_fp, seek_point * d_itemsize, whence) == 0; } @@ -137,7 +137,7 @@ void gr_file_source::open(const char *filename, bool repeat) { // obtain exclusive access for duration of this function - boost::mutex::scoped_lock lock(fp_mutex); + gruel::scoped_lock lock(fp_mutex); int fd; @@ -166,7 +166,7 @@ void gr_file_source::close() { // obtain exclusive access for duration of this function - boost::mutex::scoped_lock lock(fp_mutex); + gruel::scoped_lock lock(fp_mutex); if(d_new_fp != NULL) { fclose(d_new_fp); @@ -179,7 +179,7 @@ void gr_file_source::do_update() { if(d_updated) { - boost::mutex::scoped_lock lock(fp_mutex); // hold while in scope + gruel::scoped_lock lock(fp_mutex); // hold while in scope if(d_fp) fclose(d_fp); diff --git a/gnuradio-core/src/lib/runtime/gr_block.cc b/gnuradio-core/src/lib/runtime/gr_block.cc index 5ba30955f..f52f7a6ba 100644 --- a/gnuradio-core/src/lib/runtime/gr_block.cc +++ b/gnuradio-core/src/lib/runtime/gr_block.cc @@ -31,8 +31,8 @@ #include <gr_block_registry.h> gr_block::gr_block (const std::string &name, - gr_io_signature_sptr input_signature, - gr_io_signature_sptr output_signature) + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature) : gr_basic_block(name, input_signature, output_signature), d_output_multiple (1), d_output_multiple_set(false), @@ -43,6 +43,7 @@ gr_block::gr_block (const std::string &name, d_fixed_rate(false), d_max_noutput_items_set(false), d_max_noutput_items(0), + d_min_noutput_items(0), d_tag_propagation_policy(TPP_ALL_TO_ALL), d_max_output_buffer(std::max(output_signature->max_streams(),1), -1), d_min_output_buffer(std::max(output_signature->max_streams(),1), -1) @@ -251,6 +252,101 @@ gr_block::is_set_max_noutput_items() return d_max_noutput_items_set; } +void +gr_block::set_processor_affinity(const std::vector<unsigned int> &mask) +{ + d_affinity = mask; + if(d_detail) { + d_detail->set_processor_affinity(d_affinity); + } +} + +void +gr_block::unset_processor_affinity() +{ + d_affinity.clear(); + if(d_detail) { + d_detail->unset_processor_affinity(); + } +} + +float +gr_block::pc_noutput_items() +{ + if(d_detail) { + return d_detail->pc_noutput_items(); + } + else { + return 0; + } +} + +float +gr_block::pc_nproduced() +{ + if(d_detail) { + return d_detail->pc_nproduced(); + } + else { + return 0; + } +} + +float +gr_block::pc_input_buffers_full(int which) +{ + if(d_detail) { + return d_detail->pc_input_buffers_full(static_cast<size_t>(which)); + } + else { + return 0; + } +} + +std::vector<float> +gr_block::pc_input_buffers_full() +{ + if(d_detail) { + return d_detail->pc_input_buffers_full(); + } + else { + return std::vector<float>(1,0); + } +} + +float +gr_block::pc_output_buffers_full(int which) +{ + if(d_detail) { + return d_detail->pc_output_buffers_full(static_cast<size_t>(which)); + } + else { + return 0; + } +} + +std::vector<float> +gr_block::pc_output_buffers_full() +{ + if(d_detail) { + return d_detail->pc_output_buffers_full(); + } + else { + return std::vector<float>(1,0); + } +} + +float +gr_block::pc_work_time() +{ + if(d_detail) { + return d_detail->pc_work_time(); + } + else { + return 0; + } +} + std::ostream& operator << (std::ostream& os, const gr_block *m) { diff --git a/gnuradio-core/src/lib/runtime/gr_block.h b/gnuradio-core/src/lib/runtime/gr_block.h index 7a70bdaf0..bd9ff42df 100644 --- a/gnuradio-core/src/lib/runtime/gr_block.h +++ b/gnuradio-core/src/lib/runtime/gr_block.h @@ -252,13 +252,30 @@ class GR_CORE_API gr_block : public gr_basic_block { void set_tag_propagation_policy(tag_propagation_policy_t p); /*! + * \brief Return the minimum number of output items this block can + * produce during a call to work. + * + * Should be 0 for most blocks. Useful if we're dealing with packets and + * the block produces one packet per call to work. + */ + int min_noutput_items() const { return d_min_noutput_items; } + + /*! + * \brief Set the minimum number of output items this block can + * produce during a call to work. + * + * \param m the minimum noutput_items this block can produce. + */ + void set_min_noutput_items(int m) { d_min_noutput_items = m; } + + /*! * \brief Return the maximum number of output items this block will * handle during a call to work. */ int max_noutput_items(); /*! - * \brief Set the maximum number of ouput items htis block will + * \brief Set the maximum number of output items this block will * handle during a call to work. * * \param m the maximum noutput_items this block will handle. @@ -358,6 +375,64 @@ class GR_CORE_API gr_block : public gr_basic_block { d_min_output_buffer[port] = min_output_buffer; } + // --------------- Performance counter functions ------------- + + /*! + * \brief Gets average noutput_items performance counter. + */ + float pc_noutput_items(); + + /*! + * \brief Gets average num items produced performance counter. + */ + float pc_nproduced(); + + /*! + * \brief Gets average average fullness of \p which input buffer. + */ + float pc_input_buffers_full(int which); + + /*! + * \brief Gets average fullness of all input buffers. + */ + std::vector<float> pc_input_buffers_full(); + + /*! + * \brief Gets average fullness of \p which input buffer. + */ + float pc_output_buffers_full(int which); + + /*! + * \brief Gets average fullness of all output buffers. + */ + std::vector<float> pc_output_buffers_full(); + + /*! + * \brief Gets average clock cycles spent in work. + */ + float pc_work_time(); + + + // ---------------------------------------------------------------------------- + // Functions to handle thread affinity + + /*! + * \brief Set the thread's affinity to processor core \p n. + * + * \param mask a vector of unsigned ints of the core numbers available to this block. + */ + void set_processor_affinity(const std::vector<unsigned int> &mask); + + /*! + * \brief Remove processor affinity to a specific core. + */ + void unset_processor_affinity(); + + /*! + * \brief Get the current processor affinity. + */ + std::vector<unsigned int> processor_affinity() { return d_affinity; } + // ---------------------------------------------------------------------------- private: @@ -370,9 +445,11 @@ class GR_CORE_API gr_block : public gr_basic_block { gr_block_detail_sptr d_detail; // implementation details unsigned d_history; bool d_fixed_rate; + int d_min_noutput_items; bool d_max_noutput_items_set; // if d_max_noutput_items is valid int d_max_noutput_items; // value of max_noutput_items for this block tag_propagation_policy_t d_tag_propagation_policy; // policy for moving tags downstream + std::vector<unsigned int> d_affinity; // thread affinity proc. mask protected: gr_block (void){} //allows pure virtual interface sub-classes diff --git a/gnuradio-core/src/lib/runtime/gr_block.i b/gnuradio-core/src/lib/runtime/gr_block.i index db6c1d04a..c016f2c28 100644 --- a/gnuradio-core/src/lib/runtime/gr_block.i +++ b/gnuradio-core/src/lib/runtime/gr_block.i @@ -66,6 +66,20 @@ class gr_block : public gr_basic_block { void set_min_output_buffer(long min_output_buffer); void set_min_output_buffer(int port, long min_output_buffer); + // Methods to access performance counters + float pc_noutput_items(); + float pc_nproduced(); + float pc_input_buffers_full(int which); + std::vector<float> pc_input_buffers_full(); + float pc_output_buffers_full(int which); + std::vector<float> pc_output_buffers_full(); + float pc_work_time(); + + // Methods to manage processor affinity. + void set_processor_affinity(const gr_vector_uint &mask); + void unset_processor_affinity(); + gr_vector_uint processor_affinity(); + // internal use gr_block_detail_sptr detail () const { return d_detail; } void set_detail (gr_block_detail_sptr detail) { d_detail = detail; } diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.cc b/gnuradio-core/src/lib/runtime/gr_block_detail.cc index c65493473..ff20e0e85 100644 --- a/gnuradio-core/src/lib/runtime/gr_block_detail.cc +++ b/gnuradio-core/src/lib/runtime/gr_block_detail.cc @@ -26,6 +26,7 @@ #include <gr_block_detail.h> #include <gr_buffer.h> +#include <iostream> using namespace pmt; @@ -41,7 +42,11 @@ gr_block_detail::gr_block_detail (unsigned int ninputs, unsigned int noutputs) : d_produce_or(0), d_ninputs (ninputs), d_noutputs (noutputs), d_input (ninputs), d_output (noutputs), - d_done (false) + d_done (false), + d_avg_noutput_items(0), d_avg_nproduced(0), + d_avg_input_buffers_full(ninputs, 0), + d_avg_output_buffers_full(noutputs, 0), + d_avg_work_time(0) { s_ncurrently_allocated++; } @@ -201,3 +206,104 @@ gr_block_detail::get_tags_in_range(std::vector<gr_tag_t> &v, } } } + +void +gr_block_detail::set_processor_affinity(const std::vector<unsigned int> &mask) +{ + if(threaded) { + try { + gruel::thread_bind_to_processor(thread, mask); + } + catch (std::runtime_error e) { + std::cerr << "set_processor_affinity: invalid mask." << std::endl;; + } + } +} + +void +gr_block_detail::unset_processor_affinity() +{ + if(threaded) { + gruel::thread_unbind(thread); + } +} + +void +gr_block_detail::start_perf_counters() +{ + d_start_of_work = gruel::high_res_timer_now(); +} + +void +gr_block_detail::stop_perf_counters(int noutput_items, int nproduced) +{ + float alpha = 0.05; + float beta = 1.0-alpha; + + d_end_of_work = gruel::high_res_timer_now(); + gruel::high_res_timer_type diff = d_end_of_work - d_start_of_work; + d_avg_work_time = beta*d_avg_work_time + alpha*diff; + + d_avg_nproduced = beta*d_avg_nproduced + alpha*nproduced; + d_avg_noutput_items = beta*d_avg_noutput_items + alpha*noutput_items; + + for(size_t i=0; i < d_input.size(); i++) { + float pfull = static_cast<float>(d_input[i]->items_available()) / + static_cast<float>(d_input[i]->max_possible_items_available()); + d_avg_input_buffers_full[i] = beta*d_avg_input_buffers_full[i] + alpha*pfull; + } + + for(size_t i=0; i < d_output.size(); i++) { + float pfull = 1.0f - static_cast<float>(d_output[i]->space_available()) / + static_cast<float>(d_output[i]->bufsize()); + d_avg_output_buffers_full[i] = beta*d_avg_output_buffers_full[i] + alpha*pfull; + } +} + +float +gr_block_detail::pc_noutput_items() +{ + return d_avg_noutput_items; +} + +float +gr_block_detail::pc_nproduced() +{ + return d_avg_nproduced; +} + +float +gr_block_detail::pc_input_buffers_full(size_t which) +{ + if(which < d_avg_input_buffers_full.size()) + return d_avg_input_buffers_full[which]; + else + return 0; +} + +std::vector<float> +gr_block_detail::pc_input_buffers_full() +{ + return d_avg_input_buffers_full; +} + +float +gr_block_detail::pc_output_buffers_full(size_t which) +{ + if(which < d_avg_output_buffers_full.size()) + return d_avg_output_buffers_full[which]; + else + return 0; +} + +std::vector<float> +gr_block_detail::pc_output_buffers_full() +{ + return d_avg_output_buffers_full; +} + +float +gr_block_detail::pc_work_time() +{ + return d_avg_work_time; +} diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.h b/gnuradio-core/src/lib/runtime/gr_block_detail.h index af00ea7c7..a8ed8da90 100644 --- a/gnuradio-core/src/lib/runtime/gr_block_detail.h +++ b/gnuradio-core/src/lib/runtime/gr_block_detail.h @@ -27,6 +27,7 @@ #include <gr_runtime_types.h> #include <gr_tpb_detail.h> #include <gr_tags.h> +#include <gruel/high_res_timer.h> #include <stdexcept> /*! @@ -155,6 +156,33 @@ class GR_CORE_API gr_block_detail { uint64_t abs_end, const pmt::pmt_t &key); + /*! + * \brief Set core affinity of block to the cores in the vector mask. + * + * \param mask a vector of unsigned ints of the core numbers available to this block. + */ + void set_processor_affinity(const std::vector<unsigned int> &mask); + + /*! + * \brief Unset core affinity. + */ + void unset_processor_affinity(); + + bool threaded; // set if thread is currently running. + gruel::gr_thread_t thread; // portable thread handle + + void start_perf_counters(); + void stop_perf_counters(int noutput_items, int nproduced); + + // Calls to get performance counter items + float pc_noutput_items(); + float pc_nproduced(); + float pc_input_buffers_full(size_t which); + std::vector<float> pc_input_buffers_full(); + float pc_output_buffers_full(size_t which); + std::vector<float> pc_output_buffers_full(); + float pc_work_time(); + gr_tpb_detail d_tpb; // used by thread-per-block scheduler int d_produce_or; @@ -167,6 +195,14 @@ class GR_CORE_API gr_block_detail { std::vector<gr_buffer_sptr> d_output; bool d_done; + // Performance counters + float d_avg_noutput_items; + float d_avg_nproduced; + std::vector<float> d_avg_input_buffers_full; + std::vector<float> d_avg_output_buffers_full; + gruel::high_res_timer_type d_start_of_work, d_end_of_work; + float d_avg_work_time; + gr_block_detail (unsigned int ninputs, unsigned int noutputs); friend struct gr_tpb_detail; diff --git a/gnuradio-core/src/lib/runtime/gr_block_executor.cc b/gnuradio-core/src/lib/runtime/gr_block_executor.cc index 375b58f56..27f591452 100644 --- a/gnuradio-core/src/lib/runtime/gr_block_executor.cc +++ b/gnuradio-core/src/lib/runtime/gr_block_executor.cc @@ -64,22 +64,21 @@ round_down (unsigned int n, unsigned int multiple) // on is done. // static int -min_available_space (gr_block_detail *d, int output_multiple) +min_available_space (gr_block_detail *d, int output_multiple, int min_noutput_items) { - int min_space = std::numeric_limits<int>::max(); - + int min_space = std::numeric_limits<int>::max(); + if (min_noutput_items == 0) + min_noutput_items = 1; for (int i = 0; i < d->noutputs (); i++){ gruel::scoped_lock guard(*d->output(i)->mutex()); -#if 0 - int n = round_down(d->output(i)->space_available(), output_multiple); -#else - int n = round_down(std::min(d->output(i)->space_available(), - d->output(i)->bufsize()/2), - output_multiple); -#endif - if (n == 0){ // We're blocked on output. - if (d->output(i)->done()){ // Downstream is done, therefore we're done. - return -1; + int avail_n = round_down(d->output(i)->space_available(), output_multiple); + int best_n = round_down(d->output(i)->bufsize()/2, output_multiple); + if (best_n < min_noutput_items) + throw std::runtime_error("Buffer too small for min_noutput_items"); + int n = std::min(avail_n, best_n); + if (n < min_noutput_items){ // We're blocked on output. + if (d->output(i)->done()){ // Downstream is done, therefore we're done. + return -1; } return 0; } @@ -205,7 +204,7 @@ gr_block_executor::run_one_iteration() d_start_nitems_read.resize(0); // determine the minimum available output space - noutput_items = min_available_space (d, m->output_multiple ()); + noutput_items = min_available_space (d, m->output_multiple (), m->min_noutput_items ()); noutput_items = std::min(noutput_items, max_noutput_items); LOG(*d_log << " source\n noutput_items = " << noutput_items << std::endl); if (noutput_items == -1) // we're done @@ -286,7 +285,7 @@ gr_block_executor::run_one_iteration() } // determine the minimum available output space - noutput_items = min_available_space (d, m->output_multiple ()); + noutput_items = min_available_space (d, m->output_multiple (), m->min_noutput_items ()); if (ENABLE_LOGGING){ *d_log << " regular "; if (m->relative_rate() >= 1.0) @@ -420,9 +419,18 @@ gr_block_executor::run_one_iteration() for (int i = 0; i < d->ninputs(); i++) d_start_nitems_read[i] = d->nitems_read(i); +#ifdef GR_PERFORMANCE_COUNTERS + d->start_perf_counters(); +#endif /* GR_PERFORMANCE_COUNTERS */ + // Do the actual work of the block int n = m->general_work (noutput_items, d_ninput_items, d_input_items, d_output_items); + +#ifdef GR_PERFORMANCE_COUNTERS + d->stop_perf_counters(noutput_items, n); +#endif /* GR_PERFORMANCE_COUNTERS */ + LOG(*d_log << " general_work: noutput_items = " << noutput_items << " result = " << n << std::endl); diff --git a/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc b/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc index 9f17a48a8..cea374fac 100644 --- a/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc +++ b/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc @@ -38,6 +38,13 @@ gr_tpb_thread_body::gr_tpb_thread_body(gr_block_sptr block, int max_noutput_item gr_block_executor::state s; pmt_t msg; + d->threaded = true; + d->thread = gruel::get_current_thread_id(); + + // Set thread affinity if it was set before fg was started. + if(block->processor_affinity().size() > 0) { + gruel::thread_bind_to_processor(d->thread, block->processor_affinity()); + } while (1){ boost::this_thread::interruption_point(); diff --git a/gnuradio-core/src/lib/runtime/gr_types.h b/gnuradio-core/src/lib/runtime/gr_types.h index ad6cee768..db13e456a 100644 --- a/gnuradio-core/src/lib/runtime/gr_types.h +++ b/gnuradio-core/src/lib/runtime/gr_types.h @@ -31,6 +31,7 @@ #include <gr_complex.h> typedef std::vector<int> gr_vector_int; +typedef std::vector<unsigned int> gr_vector_uint; typedef std::vector<float> gr_vector_float; typedef std::vector<double> gr_vector_double; typedef std::vector<void *> gr_vector_void_star; diff --git a/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc b/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc index a0b4755a8..1d3dafadf 100644 --- a/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc +++ b/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc @@ -262,3 +262,24 @@ void qa_gr_top_block::t10_reconfig_max_output_buffer() // Wait for flowgraph to end on its own tb->wait(); } + +void qa_gr_top_block::t11_set_block_affinity() +{ + gr_top_block_sptr tb = gr_make_top_block("top"); + gr_block_sptr src (gr_make_null_source(sizeof(float))); + gr_block_sptr snk (gr_make_null_sink(sizeof(float))); + + std::vector<unsigned int> set(1, 0), ret; + src->set_processor_affinity(set); + + tb->connect(src, 0, snk, 0); + tb->start(); + tb->stop(); + tb->wait(); + + ret = src->processor_affinity(); + + // We only set the core affinity to 0 because we always know at + // least one thread core exists to use. + CPPUNIT_ASSERT_EQUAL(set[0], ret[0]); +} diff --git a/gnuradio-core/src/lib/runtime/qa_gr_top_block.h b/gnuradio-core/src/lib/runtime/qa_gr_top_block.h index bb891abca..634eeab1f 100644 --- a/gnuradio-core/src/lib/runtime/qa_gr_top_block.h +++ b/gnuradio-core/src/lib/runtime/qa_gr_top_block.h @@ -38,6 +38,11 @@ class qa_gr_top_block : public CppUnit::TestCase CPPUNIT_TEST(t4_reconfigure); // triggers 'join never returns' bug CPPUNIT_TEST(t5_max_noutputs); CPPUNIT_TEST(t6_reconfig_max_noutputs); + CPPUNIT_TEST(t7_max_noutputs_per_block); + CPPUNIT_TEST(t8_reconfig_max_noutputs_per_block); + CPPUNIT_TEST(t9_max_output_buffer); + CPPUNIT_TEST(t10_reconfig_max_output_buffer); + CPPUNIT_TEST(t11_set_block_affinity); CPPUNIT_TEST_SUITE_END(); @@ -54,6 +59,8 @@ private: void t8_reconfig_max_noutputs_per_block(); void t9_max_output_buffer(); void t10_reconfig_max_output_buffer(); + void t11_set_block_affinity(); + }; #endif /* INCLUDED_QA_GR_TOP_BLOCK_H */ diff --git a/gnuradio-core/src/python/gnuradio/gr/CMakeLists.txt b/gnuradio-core/src/python/gnuradio/gr/CMakeLists.txt index bd78c8fb4..da22a5f98 100644 --- a/gnuradio-core/src/python/gnuradio/gr/CMakeLists.txt +++ b/gnuradio-core/src/python/gnuradio/gr/CMakeLists.txt @@ -29,6 +29,7 @@ GR_PYTHON_INSTALL(FILES gr_threading_24.py hier_block2.py prefs.py + tag_utils.py top_block.py pubsub.py DESTINATION ${GR_PYTHON_DIR}/gnuradio/gr diff --git a/gnuradio-core/src/python/gnuradio/gr/__init__.py b/gnuradio-core/src/python/gnuradio/gr/__init__.py index 5d01ea11b..f1b971e62 100644 --- a/gnuradio-core/src/python/gnuradio/gr/__init__.py +++ b/gnuradio-core/src/python/gnuradio/gr/__init__.py @@ -29,6 +29,7 @@ from exceptions import * from hier_block2 import * from top_block import * from gateway import basic_block, sync_block, decim_block, interp_block +from tag_utils import tag_to_python, tag_to_pmt # create a couple of aliases serial_to_parallel = stream_to_vector diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_tag_utils.py b/gnuradio-core/src/python/gnuradio/gr/qa_tag_utils.py new file mode 100755 index 000000000..ca1184979 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/gr/qa_tag_utils.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# Copyright 2007,2010 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, gr_unittest +import tag_utils + +try: + import pmt_swig as pmt +except ImportError: + import pmt + +class test_tag_utils (gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + + def tearDown (self): + self.tb = None + + def test_001(self): + t = gr.gr_tag_t() + t.offset = 10 + t.key = pmt.pmt_string_to_symbol('key') + t.value = pmt.pmt_from_long(23) + t.srcid = pmt.pmt_from_bool(False) + pt = tag_utils.tag_to_python(t) + self.assertEqual(pt.key, 'key') + self.assertEqual(pt.value, 23) + self.assertEqual(pt.offset, 10) + + +if __name__ == '__main__': + print 'hi' + gr_unittest.run(test_tag_utils, "test_tag_utils.xml") + diff --git a/gnuradio-core/src/python/gnuradio/gr/tag_utils.py b/gnuradio-core/src/python/gnuradio/gr/tag_utils.py new file mode 100644 index 000000000..923718fc9 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/gr/tag_utils.py @@ -0,0 +1,54 @@ +# +# Copyright 2003-2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# +""" Conversion tools between stream tags and Python objects """ + +try: import pmt +except: from gruel import pmt + +from gnuradio_core import gr_tag_t + +class PythonTag(object): + " Python container for tags " + def __init__(self): + self.offset = None + self.key = None + self.value = None + self.srcid = None + +def tag_to_python(tag): + """ Convert a stream tag to a Python-readable object """ + newtag = PythonTag() + newtag.offset = tag.offset + newtag.key = pmt.to_python(tag.key) + newtag.value = pmt.to_python(tag.value) + newtag.srcid = pmt.to_python(tag.srcid) + return newtag + +def tag_to_pmt(tag): + """ Convert a Python-readable object to a stream tag """ + newtag = gr_tag_t() + newtag.offset = tag.offset + newtag.key = pmt.to_python(tag.key) + newtag.value = pmt.from_python(tag.value) + newtag.srcid = pmt.from_python(tag.srcid) + return newtag + + |