From a3c8c5edf19fae7d2cb4db1d01a207e011affeea Mon Sep 17 00:00:00 2001 From: Jonathan Hanks <jonathan.hanks@ligo.org> Date: Fri, 11 Oct 2019 16:48:20 -0700 Subject: [PATCH] Tracking down an issue with 16bit code. Extending mbuf probe and tests. Added an 'analyze' mode to mbuf_probe to allow it to dump data in real time with some basic data extracted. Extended tests with new synthentic generators to help highlight issues. It appears that there is a byte swap issue with 16bit ints. Committing code before looking into the daqd code. --- src/drv/mbuf/mbuf_probe/CMakeLists.txt | 11 +- .../mbuf/mbuf_probe/analyze_daq_multi_dc.cc | 178 +++++++++++++ .../mbuf/mbuf_probe/analyze_daq_multi_dc.hh | 19 ++ src/drv/mbuf/mbuf_probe/analyze_rmipc.cc | 124 +++++++++ src/drv/mbuf/mbuf_probe/analyze_rmipc.hh | 19 ++ src/drv/mbuf/mbuf_probe/mbuf_decoders.cc | 247 ++++++++++++++++++ src/drv/mbuf/mbuf_probe/mbuf_decoders.hh | 54 ++++ src/drv/mbuf/mbuf_probe/mbuf_probe.cc | 196 +++++++------- src/drv/mbuf/mbuf_probe/mbuf_probe.hh | 141 ++++++++++ src/fe_stream_test/fe_multi_stream_test.cc | 12 +- src/fe_stream_test/fe_stream_generator.cc | 151 ++++++----- src/fe_stream_test/fe_stream_generator.hh | 85 ++++++ src/fe_stream_test/lookup_chan_from_ini.py | 113 ++++++++ 13 files changed, 1187 insertions(+), 163 deletions(-) create mode 100644 src/drv/mbuf/mbuf_probe/analyze_daq_multi_dc.cc create mode 100644 src/drv/mbuf/mbuf_probe/analyze_daq_multi_dc.hh create mode 100644 src/drv/mbuf/mbuf_probe/analyze_rmipc.cc create mode 100644 src/drv/mbuf/mbuf_probe/analyze_rmipc.hh create mode 100644 src/drv/mbuf/mbuf_probe/mbuf_decoders.cc create mode 100644 src/drv/mbuf/mbuf_probe/mbuf_decoders.hh create mode 100644 src/drv/mbuf/mbuf_probe/mbuf_probe.hh create mode 100644 src/fe_stream_test/lookup_chan_from_ini.py diff --git a/src/drv/mbuf/mbuf_probe/CMakeLists.txt b/src/drv/mbuf/mbuf_probe/CMakeLists.txt index 660e95c85..41da74017 100644 --- a/src/drv/mbuf/mbuf_probe/CMakeLists.txt +++ b/src/drv/mbuf/mbuf_probe/CMakeLists.txt @@ -1,4 +1,11 @@ -add_executable(mbuf_probe mbuf_probe.cc) -target_include_directories(mbuf_probe PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) +add_executable(mbuf_probe + mbuf_probe.cc + mbuf_decoders.cc + analyze_daq_multi_dc.cc + analyze_rmipc.cc) +target_include_directories(mbuf_probe PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/../../include + ) target_link_libraries(mbuf_probe PUBLIC driver::shmem) \ No newline at end of file diff --git a/src/drv/mbuf/mbuf_probe/analyze_daq_multi_dc.cc b/src/drv/mbuf/mbuf_probe/analyze_daq_multi_dc.cc new file mode 100644 index 000000000..52fb85f21 --- /dev/null +++ b/src/drv/mbuf/mbuf_probe/analyze_daq_multi_dc.cc @@ -0,0 +1,178 @@ +// +// Created by jonathan.hanks on 10/11/19. +// + +#include "analyze_daq_multi_dc.hh" + +#include "mbuf.h" +#include "daq_core.h" + +#include <algorithm> +#include <iterator> +#include <iomanip> +#include <iostream> +#include <sstream> + +namespace analyze +{ + namespace multi_dc + { + void + simple_running_dump_single_dcu( + volatile daq_multi_cycle_data_t* multi_data, + int dcu_id, + const DataDecoder& decoder ) + { + + unsigned int last_cycle = multi_data->header.curCycle; + + bool use_decoder = ( decoder.required_size( ) > 0 ); + + while ( true ) + { + unsigned int cur_cycle = wait_until_changed( + &( multi_data->header.curCycle ), last_cycle ); + if ( cur_cycle > 1024 ) + { + break; + } + + last_cycle = cur_cycle; + + unsigned int data_size = multi_data->header.cycleDataSize; + std::size_t cycle_offset = data_size * cur_cycle; + + volatile daq_dc_data_t* dc_data = + reinterpret_cast< volatile daq_dc_data_t* >( + &( multi_data->dataBlock[ 0 ] ) + cycle_offset ); + unsigned int dcu_count = dc_data->header.dcuTotalModels; + volatile daq_msg_header_t* header = + (volatile daq_msg_header_t*)0; + volatile char* data = &( dc_data->dataBlock[ 0 ] ); + for ( int i = 0; i < dcu_count; ++i ) + { + if ( dc_data->header.dcuheader[ i ].dcuId == dcu_id ) + { + header = &( dc_data->header.dcuheader[ i ] ); + break; + } + data += dc_data->header.dcuheader[ i ].dataBlockSize + + dc_data->header.dcuheader[ i ].tpBlockSize; + } + + std::ostringstream os; + os << "Cycle: " << std::setw( 2 ) << cur_cycle; + if ( header ) + { + os << " dcu: " << std::setw( 3 ) << header->dcuId; + os << " gps: " << std::setw( 10 ) << header->timeSec << ":" + << std::setw( 2 ) << header->timeNSec; + os << " data: " << header->dataBlockSize; + os << " tp: " << header->tpBlockSize; + if ( header->tpCount > 0 ) + { + os << "("; + std::copy( + const_cast< unsigned int* >( + &( header->tpNum[ 0 ] ) ), + const_cast< unsigned int* >( + &( header->tpNum[ header->tpCount ] ) ), + std::ostream_iterator< unsigned int >( os, "," ) ); + os << ") "; + } + if ( use_decoder ) + { + os << " - "; + decoder.decode( + reinterpret_cast< volatile void* >( data ), os ); + } + } + else + { + os << " not found in this cycle\n"; + } + + std::cout << os.str( ) << std::endl; + } + } + + void + simple_running_dump( volatile daq_multi_cycle_data_t* multi_data ) + { + + unsigned int last_cycle = multi_data->header.curCycle; + + while ( true ) + { + unsigned int cur_cycle = wait_until_changed( + &( multi_data->header.curCycle ), last_cycle ); + if ( cur_cycle > 1024 ) + { + break; + } + + unsigned int data_size = multi_data->header.cycleDataSize; + unsigned int max_cycle = multi_data->header.maxCycle; + + std::size_t cycle_offset = data_size * cur_cycle; + + volatile daq_dc_data_t* dc_data = + reinterpret_cast< volatile daq_dc_data_t* >( + &( multi_data->dataBlock[ 0 ] ) + cycle_offset ); + unsigned int dcu_count = dc_data->header.dcuTotalModels; + + last_cycle = cur_cycle; + + std::ostringstream os; + + os << "Cycle: " << std::setw( 2 ) << cur_cycle << "/" + << std::setw( 2 ) << max_cycle; + os << " DataSize: " << data_size; + os << " DcuCount: " << dcu_count; + + for ( unsigned int i = 0; i < dcu_count; ++i ) + { + volatile daq_msg_header_t& header = + dc_data->header.dcuheader[ i ]; + os << "\n\tdcu: " << std::setw( 3 ) << header.dcuId; + os << " gps: " << std::setw( 10 ) << header.timeSec << ":" + << std::setw( 2 ) << header.timeNSec; + os << " data: " << header.dataBlockSize; + os << " tp: " << header.tpBlockSize; + if ( header.tpCount > 0 ) + { + os << "("; + std::copy( + const_cast< unsigned int* >( + &( header.tpNum[ 0 ] ) ), + const_cast< unsigned int* >( + &( header.tpNum[ header.tpCount ] ) ), + std::ostream_iterator< unsigned int >( os, "," ) ); + os << ")"; + } + } + + std::cout << os.str( ) << std::endl; + } + } + } // namespace multi_dc + + void + analyze_multi_dc( volatile void* buffer, + std::size_t size, + const ConfigOpts& options ) + { + volatile daq_multi_cycle_data_t* multi_data = + reinterpret_cast< volatile daq_multi_cycle_data_t* >( buffer ); + + if ( options.dcu_id > 0 ) + { + multi_dc::simple_running_dump_single_dcu( + multi_data, options.dcu_id, options.decoder ); + } + else + { + multi_dc::simple_running_dump( multi_data ); + } + } +} // namespace analyze diff --git a/src/drv/mbuf/mbuf_probe/analyze_daq_multi_dc.hh b/src/drv/mbuf/mbuf_probe/analyze_daq_multi_dc.hh new file mode 100644 index 000000000..b5f8799ce --- /dev/null +++ b/src/drv/mbuf/mbuf_probe/analyze_daq_multi_dc.hh @@ -0,0 +1,19 @@ +// +// Created by jonathan.hanks on 10/11/19. +// + +#ifndef DAQD_MBUF_ANALYZE_DAQ_MULTI_DC_HH +#define DAQD_MBUF_ANALYZE_DAQ_MULTI_DC_HH + +#include <cstddef> + +#include "mbuf_probe.hh" + +namespace analyze +{ + void analyze_multi_dc( volatile void* buffer, + std::size_t size, + const ConfigOpts& options ); +} + +#endif // DAQD_MBUF_ANALYZE_DAQ_MULTI_DC_HH diff --git a/src/drv/mbuf/mbuf_probe/analyze_rmipc.cc b/src/drv/mbuf/mbuf_probe/analyze_rmipc.cc new file mode 100644 index 000000000..393ac58dc --- /dev/null +++ b/src/drv/mbuf/mbuf_probe/analyze_rmipc.cc @@ -0,0 +1,124 @@ +// +// Created by jonathan.hanks on 10/10/19. +// + +#include "analyze_rmipc.hh" + +#include <time.h> +#include <unistd.h> +#include <daqmap.h> +#include <daq_core_defs.h> +#include <drv/fb.h> + +#include <iomanip> +#include <iostream> +#include <sstream> + +namespace analyze +{ + + namespace rmipc + { + /*! + * @brief a grouping of commonly needed offsets and structures in a + * rmIpcStr style buffer + */ + struct memory_layout + { + explicit memory_layout( volatile char* buf ) + : ipc( reinterpret_cast< volatile rmIpcStr* >( + buf + CDS_DAQ_NET_IPC_OFFSET ) ), + data( buf + CDS_DAQ_NET_DATA_OFFSET ), + tp_num( reinterpret_cast< volatile cdsDaqNetGdsTpNum* >( + buf + CDS_DAQ_NET_GDS_TP_TABLE_OFFSET ) ) + { + } + + volatile rmIpcStr* ipc; + volatile char* data; + volatile cdsDaqNetGdsTpNum* tp_num; + }; + + static const std::size_t buf_size = + DAQ_DCU_BLOCK_SIZE * DAQ_NUM_SWING_BUFFERS; + + double + time_diff( const struct timespec& t0, const struct timespec& t1 ) + { + double t0d = static_cast< double >( t0.tv_sec ) + + static_cast< double >( t0.tv_nsec ) / 1000000000.0; + double t1d = static_cast< double >( t1.tv_sec ) + + static_cast< double >( t1.tv_nsec ) / 1000000000.0; + return t1d - t0d; + } + + void + simple_running_dump( memory_layout layout, const DataDecoder& decoder ) + { + unsigned int last_cycle = layout.ipc->cycle; + + bool use_decoder = decoder.required_size( ) > 0; + + struct timespec last_time; + clock_gettime( CLOCK_MONOTONIC, &last_time ); + while ( true ) + { + unsigned int cur_cycle = + wait_until_changed( &( layout.ipc->cycle ), last_cycle ); + struct timespec cur_time; + clock_gettime( CLOCK_MONOTONIC, &cur_time ); + + if ( cur_cycle > 1024 ) + { + break; + } + + unsigned int dcu_id = layout.ipc->dcuId; + unsigned int status = layout.ipc->status; + unsigned int channel_count = layout.ipc->channelCount; + unsigned int data_size = layout.ipc->dataBlockSize; + unsigned int blk_sec = layout.ipc->bp[ cur_cycle ].timeSec; + unsigned int blk_nsec = layout.ipc->bp[ cur_cycle ].timeNSec; + unsigned int blk_crc = layout.ipc->bp[ cur_cycle ].crc; + + last_cycle = cur_cycle; + std::ostringstream os; + os << "Cycle: " << std::setw( 2 ) << cur_cycle + << std::setw( 0 ); + os << " DCU: " << dcu_id; + os << " Chan#: " << channel_count; + os << " DataSize: " << data_size; + os << " Status: " << status; + os << " BlkCrc: " << blk_crc; + os << " BlkSec: " << std::setw( 10 ) << blk_sec; + os << ":" << std::setw( 2 ) << blk_nsec; + + if ( use_decoder ) + { + os << " - "; + decoder.decode( reinterpret_cast< volatile void* >( + layout.data + cur_cycle * buf_size ), + os ); + } + + double time_delta = time_diff( last_time, cur_time ); + last_time = cur_time; + + os << " delta(ms): " << time_delta * 1000; + + std::cout << os.str( ) << std::endl; + } + } + } // namespace rmipc + + void + analyze_rmipc( volatile void* buffer, + std::size_t size, + const ConfigOpts& options ) + { + rmipc::memory_layout layout( + reinterpret_cast< volatile char* >( buffer ) ); + + rmipc::simple_running_dump( layout, options.decoder ); + } +} // namespace analyze diff --git a/src/drv/mbuf/mbuf_probe/analyze_rmipc.hh b/src/drv/mbuf/mbuf_probe/analyze_rmipc.hh new file mode 100644 index 000000000..306e62684 --- /dev/null +++ b/src/drv/mbuf/mbuf_probe/analyze_rmipc.hh @@ -0,0 +1,19 @@ +// +// Created by jonathan.hanks on 10/10/19. +// + +#ifndef DAQD_MBUF_ANALYSE_RMIPC_HH +#define DAQD_MBUF_ANALYSE_RMIPC_HH + +#include <cstddef> + +#include "mbuf_probe.hh" + +namespace analyze +{ + void analyze_rmipc( volatile void* buffer, + std::size_t size, + const ConfigOpts& options ); +} + +#endif // DAQD_MBUF_ANALYSE_RMIPC_HH diff --git a/src/drv/mbuf/mbuf_probe/mbuf_decoders.cc b/src/drv/mbuf/mbuf_probe/mbuf_decoders.cc new file mode 100644 index 000000000..4bc982fc3 --- /dev/null +++ b/src/drv/mbuf/mbuf_probe/mbuf_decoders.cc @@ -0,0 +1,247 @@ +// +// Created by jonathan.hanks on 10/10/19. +// + +#include "mbuf_decoders.hh" + +#include <algorithm> +#include <numeric> +#include <iostream> +#include <sstream> + +namespace mbuf_decoders +{ + template < typename T > + class BasicDecoder : public Decoder + { + public: + explicit BasicDecoder( std::size_t count ) : count_( count ) + { + } + + virtual ~BasicDecoder( ) + { + } + + virtual volatile void* + decode( volatile void* data, std::ostream& os ) const + { + volatile T* cur = reinterpret_cast< volatile T* >( data ); + for ( std::size_t i = 0; i < count_; ++i ) + { + os << " " << *cur; + ++cur; + } + return reinterpret_cast< volatile void* >( cur ); + } + + virtual std::size_t + required_size( ) const + { + return sizeof( T ) * count_; + } + + virtual std::string + describe( ) const + { + std::ostringstream os; + os << "BasicDecoder data_size = " << sizeof( T ) + << " count = " << count_ << " req_size = " << required_size( ); + return os.str( ); + } + + private: + std::size_t count_; + }; + + class PadDecoder : public Decoder + { + public: + explicit PadDecoder( std::size_t count ) : count_( count ) + { + } + + virtual ~PadDecoder( ) + { + } + + virtual volatile void* + decode( volatile void* data, std::ostream& os ) const + { + volatile char* cur = reinterpret_cast< volatile char* >( data ); + cur += count_; + return reinterpret_cast< volatile void* >( cur ); + } + + virtual std::size_t + required_size( ) const + { + return count_; + } + + virtual std::string + describe( ) const + { + return "pad"; + } + + private: + std::size_t count_; + }; + + std::tr1::shared_ptr< Decoder > + create_decoder( char format, std::size_t count = 1 ) + { + std::tr1::shared_ptr< Decoder > ptr; + + switch ( format ) + { + case 'x': + ptr = std::tr1::shared_ptr< Decoder >( new PadDecoder( count ) ); + break; + case 'c': + ptr = std::tr1::shared_ptr< Decoder >( + new BasicDecoder< char >( count ) ); + break; + case 'b': + ptr = std::tr1::shared_ptr< Decoder >( + new BasicDecoder< signed char >( count ) ); + break; + case 'B': + ptr = std::tr1::shared_ptr< Decoder >( + new BasicDecoder< unsigned char >( count ) ); + break; + case 'h': + ptr = std::tr1::shared_ptr< Decoder >( + new BasicDecoder< short >( count ) ); + break; + case 'H': + ptr = std::tr1::shared_ptr< Decoder >( + new BasicDecoder< unsigned short >( count ) ); + break; + case 'i': + ptr = std::tr1::shared_ptr< Decoder >( + new BasicDecoder< int >( count ) ); + break; + case 'I': + ptr = std::tr1::shared_ptr< Decoder >( + new BasicDecoder< unsigned int >( count ) ); + break; + case 'f': + ptr = std::tr1::shared_ptr< Decoder >( + new BasicDecoder< float >( count ) ); + break; + case 'd': + ptr = std::tr1::shared_ptr< Decoder >( + new BasicDecoder< double >( count ) ); + break; + default: + throw std::runtime_error( + "Unknown format specifier for a decoder" ); + } + return ptr; + } +} // namespace mbuf_decoders + +class not_equal +{ +public: + not_equal( char c ) : val( c ) + { + } + not_equal( const not_equal& other ) : val( other.val ) + { + } + not_equal& + operator=( const not_equal& other ) + { + val = other.val; + return *this; + } + + bool + operator( )( char cur ) const + { + return cur != val; + } + +private: + char val; +}; + +DataDecoder::DataDecoder( std::size_t offset, const std::string& format ) + : offset_( offset ), decoders_( ) +{ + decoders_.reserve( format.size( ) ); + + std::string::const_iterator cur = format.begin( ); + std::string::const_iterator end = format.end( ); + + while ( cur != end ) + { + std::string::const_iterator next = + find_if( cur, end, not_equal( *cur ) ); + decoders_.push_back( + mbuf_decoders::create_decoder( *cur, next - cur ) ); + cur = next; + } + + std::cout << "Decoder:\n"; + for ( int i = 0; i < decoders_.size( ); ++i ) + { + std::cout << "\t" << decoders_[ i ]->describe( ) << "\n"; + } +} + +DataDecoder::DataDecoder( const DataDecoder& other ) + : offset_( other.offset_ ), decoders_( other.decoders_ ) +{ +} + +DataDecoder& +DataDecoder::operator=( const DataDecoder& other ) +{ + if ( &other != this ) + { + decoders_ = other.decoders_; + offset_ = other.offset_; + } + return *this; +} + +static std::size_t +required_size_accumulator( std::size_t cur, + std::tr1::shared_ptr< Decoder > decoder ) +{ + return cur + decoder->required_size( ); +} + +std::size_t +DataDecoder::required_size( ) const +{ + return std::accumulate( decoders_.begin( ), + decoders_.end( ), + std::size_t( 0 ), + required_size_accumulator ); +} + +void +DataDecoder::decode( volatile void* data, std::ostream& os ) const +{ + std::vector< std::size_t > steps( decoders_.size( ), 0 ); + os << "offset: " << offset_; + volatile void* cur = reinterpret_cast< volatile void* >( + reinterpret_cast< volatile char* >( data ) + offset_ ); + for ( std::size_t i = 0; i < decoders_.size( ); ++i ) + { + volatile void* tmp = decoders_[ i ]->decode( cur, os ); + steps[ i ] = ( (char*)tmp ) - ( (char*)cur ); + cur = tmp; + } + + os << " steps -"; + for ( std::size_t i = 0; i < steps.size( ); ++i ) + { + os << " " << steps[ i ]; + } +} \ No newline at end of file diff --git a/src/drv/mbuf/mbuf_probe/mbuf_decoders.hh b/src/drv/mbuf/mbuf_probe/mbuf_decoders.hh new file mode 100644 index 000000000..ddbffdfd4 --- /dev/null +++ b/src/drv/mbuf/mbuf_probe/mbuf_decoders.hh @@ -0,0 +1,54 @@ +// +// Created by jonathan.hanks on 10/10/19. +// + +#ifndef DAQD_MBUF_DECODERS_HH +#define DAQD_MBUF_DECODERS_HH + +#include <cstddef> +#include <ostream> +#include <string> +#include <vector> + +#include <tr1/memory> + +class Decoder +{ +public: + Decoder( ) + { + } + virtual ~Decoder( ){}; + + virtual volatile void* decode( volatile void* data, + std::ostream& os ) const = 0; + virtual std::size_t required_size( ) const = 0; + + virtual std::string describe( ) const = 0; +}; + +class DataDecoder +{ +public: + DataDecoder( ) : offset_( 0 ), decoders_( ) + { + } + DataDecoder( std::size_t offset, const std::string& format ); + DataDecoder( const DataDecoder& other ); + DataDecoder& operator=( const DataDecoder& other ); + + std::size_t + offset( ) const + { + return offset_; + } + std::size_t required_size( ) const; + + void decode( volatile void* data, std::ostream& os ) const; + +private: + std::size_t offset_; + std::vector< std::tr1::shared_ptr< Decoder > > decoders_; +}; + +#endif // DAQD_TRUNK_MBUF_DECODERS_HH diff --git a/src/drv/mbuf/mbuf_probe/mbuf_probe.cc b/src/drv/mbuf/mbuf_probe/mbuf_probe.cc index d3d5080e8..5fb26e3a7 100644 --- a/src/drv/mbuf/mbuf_probe/mbuf_probe.cc +++ b/src/drv/mbuf/mbuf_probe/mbuf_probe.cc @@ -24,97 +24,9 @@ #include "drv/shmem.h" #include "mbuf.h" -enum MBufCommands -{ - INVALID, - CREATE, - LIST, - COPY, - DELETE, -}; - -struct ConfigOpts -{ - ConfigOpts( ) - : action( INVALID ), buffer_size( 0 ), buffer_name( "" ), - output_fname( "probe_out.bin" ), error_msg( "" ) - { - } - MBufCommands action; - std::size_t buffer_size; - std::string buffer_name; - std::string output_fname; - std::string error_msg; - - bool - select_action( MBufCommands selected_action ) - { - if ( action != INVALID ) - { - set_error( "Please only select one action" ); - return false; - } - action = selected_action; - return true; - } - - void - set_error( const std::string& msg ) - { - action = INVALID; - error_msg = msg; - } - - void - validate_options( ) - { - if ( !error_msg.empty( ) ) - { - return; - } - switch ( action ) - { - case CREATE: - if ( buffer_name.empty( ) || buffer_size == 0 ) - { - set_error( "Both a buffer name and buffer size are required to " - "create a buffer" ); - } - break; - case LIST: - break; - case COPY: - if ( buffer_name.empty( ) || buffer_size == 0 || - output_fname.empty( ) ) - { - set_error( "To copy a buffer a buffer name, size, and output " - "filename must be provided" ); - } - break; - case DELETE: - if ( buffer_name.empty( ) ) - { - set_error( "To delete a buffer you must specify its name" ); - } - break; - case INVALID: - default: - set_error( "Please select a valid action" ); - } - } - - bool - should_show_help( ) - { - return action == INVALID; - } - - bool - is_in_error( ) - { - return ( should_show_help( ) ? !error_msg.empty( ) : false ); - } -}; +#include "mbuf_probe.hh" +#include "analyze_daq_multi_dc.hh" +#include "analyze_rmipc.hh" void usage( const char* progname ) @@ -126,6 +38,7 @@ usage( const char* progname ) std::cout << "\tcreate - create a mbuf\n"; std::cout << "\tcopy - copy a mbuf to a file\n"; std::cout << "\tdelete - decrement the usage count of an mbuf\n"; + std::cout << "\tanalyze - continually read the mbuf and do some analysis\n"; std::cout << "\t-b <buffer name> - The name of the buffer to act on\n"; std::cout << "\t-m <buffer size in MB> - The size of the buffer in megabytes\n"; @@ -133,8 +46,22 @@ usage( const char* progname ) "multiple of 4k)\n"; std::cout << "\t-o <filename> - Output file for the copy operation " "(defaults to probe_out.bin)\n"; + std::cout + << "\t--struct <type> - Type of structure to analyze [rmIpcStr]\n"; + std::cout << "\t--dcu <dcuid> - Optional DCU id used to select a dcu for " + "analysis\n"; + std::cout << "\t\twhen analyzing daq_multi_cycle buffers.\n"; + std::cout << "\t-d <offset:format> - Decode the data section, optional\n"; + std::cout + << "\t\tPart of the analyze command. Decode a specified stretch\n"; + std::cout << "\t\tof data, with a given format specifier (same as python " + "struct)\n"; std::cout << "\t-h|--help - This help\n"; std::cout << "\n"; + std::cout << "Analysis modes:\n"; + std::cout << "\trmIpcStr (or rmipcstr) Analyze a models output buffer\n"; + std::cout + << "\tdaq_multi_cycle Analyze the output of a streamer/local_dc\n"; } ConfigOpts @@ -147,6 +74,14 @@ parse_options( int argc, char* argv[] ) command_lookup.insert( std::make_pair( "create", CREATE ) ); command_lookup.insert( std::make_pair( "copy", COPY ) ); command_lookup.insert( std::make_pair( "delete", DELETE ) ); + command_lookup.insert( std::make_pair( "analyze", ANALYZE ) ); + + std::map< std::string, MBufStructures > struct_lookup; + struct_lookup.insert( std::make_pair( "rmIpcStr", MBUF_RMIPC ) ); + struct_lookup.insert( std::make_pair( "rmipcstr", MBUF_RMIPC ) ); + struct_lookup.insert( + std::make_pair( "daq_multi_cycle", MBUF_DAQ_MULTI_DC ) ); + std::deque< std::string > args; for ( int i = 1; i < argc; ++i ) { @@ -176,7 +111,7 @@ parse_options( int argc, char* argv[] ) { if ( args.empty( ) ) { - opts.set_error( "You must specify a size when using -m or -S"); + opts.set_error( "You must specify a size when using -m or -S" ); return opts; } std::size_t multiplier = ( arg == "-m" ? 1024 * 1024 : 1 ); @@ -195,6 +130,58 @@ parse_options( int argc, char* argv[] ) opts.output_fname = args.front( ); args.pop_front( ); } + else if ( arg == "-d" ) + { + if ( args.empty( ) ) + { + opts.set_error( + "You must specify a format string when using -d" ); + return opts; + } + std::string format = args.front( ); + args.pop_front( ); + std::string::size_type split = format.find( ':' ); + if ( split == std::string::npos ) + { + opts.set_error( "You must have a format strip when using -d" ); + return opts; + } + std::string offset_str = format.substr( 0, split ); + std::string format_spec = format.substr( split + 1 ); + std::istringstream is( offset_str ); + std::size_t offset = 0; + is >> offset; + opts.decoder = DataDecoder( offset, format_spec ); + } + else if ( arg == "--struct" ) + { + if ( args.empty( ) ) + { + opts.set_error( + "You must specify a structure type when using --struct" ); + return opts; + } + std::map< std::string, MBufStructures >::iterator it; + it = struct_lookup.find( args.front( ) ); + if ( it == struct_lookup.end( ) ) + { + opts.set_error( "Invalid structure type passed to --struct" ); + return opts; + } + opts.analysis_type = it->second; + args.pop_front( ); + } + else if ( arg == "--dcu" ) + { + if ( args.empty( ) ) + { + opts.set_error( "You must specify a dcu id when using --dcu" ); + return opts; + } + std::istringstream is( args.front( ) ); + is >> opts.dcu_id; + args.pop_front( ); + } else { std::map< std::string, MBufCommands >::iterator it; @@ -331,6 +318,29 @@ list_shmem_segments( ) } } +int +handle_analyze( const ConfigOpts& opts ) +{ + const int OK = 0; + const int ERROR = 1; + + volatile void* buffer = + shmem_open_segment( opts.buffer_name.c_str( ), opts.buffer_size ); + switch ( opts.analysis_type ) + { + case MBUF_RMIPC: + analyze::analyze_rmipc( buffer, opts.buffer_size, opts ); + break; + case MBUF_DAQ_MULTI_DC: + analyze::analyze_multi_dc( buffer, opts.buffer_size, opts ); + break; + default: + std::cout << "Unknown analysis type\n"; + return ERROR; + } + return OK; +} + int main( int argc, char* argv[] ) { @@ -372,6 +382,8 @@ main( int argc, char* argv[] ) case DELETE: shmem_dec_segment_count( opts.buffer_name.c_str( ) ); break; + case ANALYZE: + return handle_analyze( opts ); } return 0; } diff --git a/src/drv/mbuf/mbuf_probe/mbuf_probe.hh b/src/drv/mbuf/mbuf_probe/mbuf_probe.hh new file mode 100644 index 000000000..1c3f8c3d3 --- /dev/null +++ b/src/drv/mbuf/mbuf_probe/mbuf_probe.hh @@ -0,0 +1,141 @@ +// +// Created by jonathan.hanks on 10/10/19. +// + +#ifndef DAQD_MBUF_PROBE_HH +#define DAQD_MBUF_PROBE_HH + +#include <cstddef> +#include <string> +#include <vector> + +#include <unistd.h> + +#include "mbuf_decoders.hh" + +enum MBufCommands +{ + INVALID, + CREATE, + LIST, + COPY, + DELETE, + ANALYZE, +}; + +enum MBufStructures +{ + MBUF_INVALID, + MBUF_RMIPC, + MBUF_DAQ_MULTI_DC, +}; + +struct ConfigOpts +{ + ConfigOpts( ) + : action( INVALID ), buffer_size( 0 ), buffer_name( "" ), + output_fname( "probe_out.bin" ), error_msg( "" ), dcu_id( -1 ), + decoder( ), analysis_type( MBUF_INVALID ) + { + } + MBufCommands action; + std::size_t buffer_size; + std::string buffer_name; + std::string output_fname; + std::string error_msg; + int dcu_id; + DataDecoder decoder; + MBufStructures analysis_type; + + bool + select_action( MBufCommands selected_action ) + { + if ( action != INVALID ) + { + set_error( "Please only select one action" ); + return false; + } + action = selected_action; + return true; + } + + void + set_error( const std::string& msg ) + { + action = INVALID; + error_msg = msg; + } + + void + validate_options( ) + { + if ( !error_msg.empty( ) ) + { + return; + } + switch ( action ) + { + case CREATE: + if ( buffer_name.empty( ) || buffer_size == 0 ) + { + set_error( "Both a buffer name and buffer size are required to " + "create a buffer" ); + } + break; + case LIST: + break; + case COPY: + if ( buffer_name.empty( ) || buffer_size == 0 || + output_fname.empty( ) ) + { + set_error( "To copy a buffer a buffer name, size, and output " + "filename must be provided" ); + } + break; + case DELETE: + if ( buffer_name.empty( ) ) + { + set_error( "To delete a buffer you must specify its name" ); + } + break; + case ANALYZE: + if ( buffer_name.empty( ) || buffer_size == 0 || + analysis_type == MBUF_INVALID ) + { + set_error( "To analyze a buffer a buffer, size, and structure " + "type must be provided" ); + } + break; + case INVALID: + default: + set_error( "Please select a valid action" ); + } + } + + bool + should_show_help( ) + { + return action == INVALID; + } + + bool + is_in_error( ) + { + return ( should_show_help( ) ? !error_msg.empty( ) : false ); + } +}; + +template < typename T > +unsigned int +wait_until_changed( volatile T* counter, T old_counter ) +{ + T cur_cycle = *counter; + do + { + usleep( 250 ); + cur_cycle = *counter; + } while ( cur_cycle == old_counter ); + return cur_cycle; +} + +#endif // DAQD_MBUF_PROBE_HH diff --git a/src/fe_stream_test/fe_multi_stream_test.cc b/src/fe_stream_test/fe_multi_stream_test.cc index b08056a64..c5d8aaa6d 100644 --- a/src/fe_stream_test/fe_multi_stream_test.cc +++ b/src/fe_stream_test/fe_multi_stream_test.cc @@ -286,8 +286,8 @@ public: std::ostringstream ss; ss << name_ << "-" << i; - generators_.push_back( - GeneratorPtr( new Generators::GPSSecondWithOffset< int >( + generators_.push_back( GeneratorPtr( + new Generators::GPSMod100kSecWithOffsetAndCycle< int >( SimChannel( ss.str( ), 2, 16, chnum ), ( i + dcu_id_ ) % 21 ) ) ); } @@ -297,8 +297,8 @@ public: std::ostringstream ss; ss << name_ << "-" << i; - generators_.push_back( - GeneratorPtr( new Generators::GPSMod30kSecWithOffset< short >( + generators_.push_back( GeneratorPtr( + new Generators::GPSMod100SecWithOffsetAndCycle< short >( SimChannel( ss.str( ), 1, 16, chnum ), ( i + dcu_id_ ) % 21 ) ) ); } @@ -310,8 +310,8 @@ public: std::ostringstream ss; ss << name_ << "-TP" << i; // TP need truncated - tp_generators_.push_back( - GeneratorPtr( new Generators::GPSMod100kSecWithOffset< float >( + tp_generators_.push_back( GeneratorPtr( + new Generators::GPSMod100kSecWithOffsetAndCycle< float >( SimChannel( ss.str( ), 4, model_rate_, chnum, dcu_id_ ), ( i + dcu_id_ ) % 21 ) ) ); } diff --git a/src/fe_stream_test/fe_stream_generator.cc b/src/fe_stream_test/fe_stream_generator.cc index 6f47eb06b..700dce01a 100644 --- a/src/fe_stream_test/fe_stream_generator.cc +++ b/src/fe_stream_test/fe_stream_generator.cc @@ -4,79 +4,104 @@ #include "fe_stream_generator.hh" bool -is_data_type_valid(int data_type) +is_data_type_valid( int data_type ) { - switch (static_cast<daq_data_t>(data_type)) + switch ( static_cast< daq_data_t >( data_type ) ) { - case _16bit_integer: - case _32bit_integer: - case _64bit_integer: - case _32bit_float: - case _64bit_double: - case _32bit_uint: - return true; - case _32bit_complex: - default: - break; + case _16bit_integer: + case _32bit_integer: + case _64bit_integer: + case _32bit_float: + case _64bit_double: + case _32bit_uint: + return true; + case _32bit_complex: + default: + break; } return false; } GeneratorPtr -create_generator(const std::string& generator, const SimChannel& ch) +create_generator( const std::string& generator, const SimChannel& ch ) { - if (ch.data_type() != 2) - throw std::runtime_error("Invalid/unsupported data type for a generator"); - if (generator == "gps_sec") { - return GeneratorPtr(new Generators::GPSSecondGenerator(ch)); - } - throw std::runtime_error("Unknown generator type"); + if ( ch.data_type( ) != 2 ) + throw std::runtime_error( + "Invalid/unsupported data type for a generator" ); + if ( generator == "gps_sec" ) + { + return GeneratorPtr( new Generators::GPSSecondGenerator( ch ) ); + } + throw std::runtime_error( "Unknown generator type" ); } GeneratorPtr -create_generator(const std::string& channel_name) +create_generator( const std::string& channel_name ) { - std::vector<std::string> parts = split(channel_name, "--"); - if (parts.size() < 4) - throw std::runtime_error("Generator name has too few parts, invalid input"); - int data_type = 0; - { - std::istringstream is (parts[parts.size()-2]); - is >> data_type; - } - int rate = 0; - { - std::istringstream is (parts[parts.size()-1]); - is >> rate; - } - if (!is_data_type_valid(data_type) || rate < 16) - throw std::runtime_error("Invalid data type or rate found"); - std::string& base = parts[0]; - std::string& name = parts[1]; - int arg_count = parts.size()-4; // ignore base channel name, data type, rate - if (name == "gpssoff1p" && arg_count == 1) - { - std::istringstream is(parts[2]); - int offset = 0; - is >> offset; - return create_generic_generator<Generators::GPSSecondWithOffset>(data_type, SimChannel(base, data_type, rate, 0), offset); - } - else if (name == "gpssmd100koff1p" && arg_count == 1) - { - std::istringstream is(parts[2]); - int offset = 0; - is >> offset; - return create_generic_generator<Generators::GPSMod100kSecWithOffset>(data_type, SimChannel(base, data_type, rate, 0), offset); - } - else if (name == "gpssmd30koff1p" && arg_count == 1) - { - std::istringstream is(parts[2]); - int offset = 0; - is >> offset; - return create_generic_generator<Generators::GPSMod30kSecWithOffset>(data_type, SimChannel(base, data_type, rate, 0), offset); - } - else - { - throw std::runtime_error("Unknown generator type"); - } + std::vector< std::string > parts = split( channel_name, "--" ); + if ( parts.size( ) < 4 ) + throw std::runtime_error( + "Generator name has too few parts, invalid input" ); + int data_type = 0; + { + std::istringstream is( parts[ parts.size( ) - 2 ] ); + is >> data_type; + } + int rate = 0; + { + std::istringstream is( parts[ parts.size( ) - 1 ] ); + is >> rate; + } + if ( !is_data_type_valid( data_type ) || rate < 16 ) + throw std::runtime_error( "Invalid data type or rate found" ); + std::string& base = parts[ 0 ]; + std::string& name = parts[ 1 ]; + int arg_count = + parts.size( ) - 4; // ignore base channel name, data type, rate + if ( name == "gpssoff1p" && arg_count == 1 ) + { + std::istringstream is( parts[ 2 ] ); + int offset = 0; + is >> offset; + return create_generic_generator< Generators::GPSSecondWithOffset >( + data_type, SimChannel( base, data_type, rate, 0 ), offset ); + } + else if ( name == "gpssmd100koff1p" && arg_count == 1 ) + { + std::istringstream is( parts[ 2 ] ); + int offset = 0; + is >> offset; + return create_generic_generator< Generators::GPSMod100kSecWithOffset >( + data_type, SimChannel( base, data_type, rate, 0 ), offset ); + } + else if ( name == "gpssmd100koffc1p" && arg_count == 1 ) + { + std::istringstream is( parts[ 2 ] ); + int offset = 0; + is >> offset; + return create_generic_generator< + Generators::GPSMod100kSecWithOffsetAndCycle >( + data_type, SimChannel( base, data_type, rate, 0 ), offset ); + } + else if ( name == "gpssmd30koff1p" && arg_count == 1 ) + { + std::istringstream is( parts[ 2 ] ); + int offset = 0; + is >> offset; + return create_generic_generator< Generators::GPSMod30kSecWithOffset >( + data_type, SimChannel( base, data_type, rate, 0 ), offset ); + } + else if ( name == "gpssmd100offc1p" && arg_count == 1 ) + { + std::istringstream is( parts[ 2 ] ); + int offset = 0; + is >> offset; + return create_generic_generator< + Generators::GPSMod100SecWithOffsetAndCycle >( + data_type, SimChannel( base, data_type, rate, 0 ), offset ); + } + else + { + throw std::runtime_error( "Unknown generator type" ); + } } diff --git a/src/fe_stream_test/fe_stream_generator.hh b/src/fe_stream_test/fe_stream_generator.hh index d08b81fa3..955a67897 100644 --- a/src/fe_stream_test/fe_stream_generator.hh +++ b/src/fe_stream_test/fe_stream_generator.hh @@ -289,6 +289,47 @@ namespace Generators } }; + template < typename T > + class GPSMod100kSecWithOffsetAndCycle : public SimChannelGenerator + { + int offset_; + + public: + GPSMod100kSecWithOffsetAndCycle( const SimChannel& ch, int offset ) + : SimChannelGenerator( ch ), offset_( offset ) + { + } + + std::string + generator_name( ) const + { + return "gpssmd100koffc1p"; + } + + std::string + other_params( ) const + { + std::ostringstream os; + os << "--" << offset_; + return os.str( ); + } + + char* + generate( int gps_sec, int gps_nano, char* out ) + { + int rate = data_rate( ) / 16; + T* out_ = reinterpret_cast< T* >( out ); + for ( int i = 0; i < rate; ++i ) + { + *out_ = + static_cast< T >( ( gps_sec % 100000 ) + offset_ ) * 100 + + gps_nano; + ++out_; + } + return reinterpret_cast< char* >( out_ ); + } + }; + template < typename T > class GPSMod30kSecWithOffset : public SimChannelGenerator { @@ -328,6 +369,50 @@ namespace Generators } }; + template < typename T > + class GPSMod100SecWithOffsetAndCycle : public SimChannelGenerator + { + int offset_; + + public: + GPSMod100SecWithOffsetAndCycle( const SimChannel& ch, int offset ) + : SimChannelGenerator( ch ), offset_( offset ) + { + } + + std::string + generator_name( ) const + { + return "gpssmd100offc1p"; + } + + std::string + other_params( ) const + { + std::ostringstream os; + os << "--" << offset_; + return os.str( ); + } + + char* + generate( int gps_sec, int gps_nano, char* out ) + { + int rate = data_rate( ) / 16; + T* out_ = reinterpret_cast< T* >( out ); + if ( gps_nano > 15 ) + { + gps_nano /= 62500000; + } + for ( int i = 0; i < rate; ++i ) + { + *out_ = static_cast< T >( ( gps_sec % 100 ) + offset_ ) * 100 + + gps_nano; + ++out_; + } + return reinterpret_cast< char* >( out_ ); + } + }; + template < typename T > class StaticValue : public SimChannelGenerator { diff --git a/src/fe_stream_test/lookup_chan_from_ini.py b/src/fe_stream_test/lookup_chan_from_ini.py new file mode 100644 index 000000000..b32764055 --- /dev/null +++ b/src/fe_stream_test/lookup_chan_from_ini.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 + +import argparse +import json +import sys + + +class channel_info(object): + def __init__(self, name=None, dcu=-1, datarate=0, datatype=0, offset=0): + self.name = name + self.dcu = dcu + self.datarate = datarate + self.datatype = datatype + self.offset = offset + + def copy(self): + return channel_info(name=self.name, dcu=self.dcu, datarate=self.datarate, datatype=self.datatype, offset=self.offset) + + def size(self): + return datatype_size(self.datatype) * (self.datarate // 16) + + def __unicode__(self): + data = { + 'name': self.name, + 'dcu': self.dcu, + 'datarate': self.datarate, + 'datatype': self.datatype, + 'datatypename': datatypename(self.datatype), + 'datatypesize': datatype_size(self.datatype), + 'size': self.size(), + 'offset': self.offset, + } + return json.dumps(data) + + def __str__(self): + return self.__unicode__() + + +def datatypename(data_type): + mapping = { + 1: 'int16', + 2: 'int32', + 3: 'int64', + 4: 'float32', + 5: 'float64', + 6: 'complex', + 7: 'uint32', + } + return mapping[data_type] + + +def datatype_size(data_type): + if data_type == 1: + return 2 + elif data_type in (2,4,7): + return 4 + elif data_type in (3, 5, 6): + return 8 + raise RuntimeError("Invalid datatype {0}".format(data_type)) + + +print(sys.argv) + + +parser = argparse.ArgumentParser(description="Lookup channel information from an ini file") +parser.add_argument("-i", "--ini", help="Specify the ini file") +parser.add_argument("-c", "--channel", help="Specify the channel") + +args = parser.parse_args() + +channels = [] + +default_settings = channel_info() + +with open(args.ini, "rt") as f: + cur_info = default_settings.copy() + cur_offset = 0 + + for line in f: + line = line.strip() + if line == "": + continue + if line.startswith("["): + if not line.endswith("]"): + raise RuntimeError("Unparsable line {0}".format(line)) + + # first store the old entry + if cur_info.name == 'default': + default_settings = cur_info + default_settings.offset = 0 + elif cur_info.name is not None: + channels.append(cur_info) + cur_offset += cur_info.size() + + cur_info = default_settings.copy() + cur_info.name = line[1:-1] + cur_info.offset = cur_offset + else: + parts = line.split("=") + if len(parts) != 2: + continue + if parts[0] == "dcuid": + cur_info.dcu = int(parts[1]) + elif parts[0] == "datatype": + cur_info.datatype = int(parts[1]) + elif parts[0] == "datarate": + cur_info.datarate = int(parts[1]) + + if cur_info.name is not None: + channels.append("{0}".format(cur_info)) + +for entry in channels: + print(entry) -- GitLab