The code used to be in common/JackTools.h until it got moved to
JackTools.cpp in aabbb62282.
However, it is not possible to split a template implementation between
header and source file, so the code in JackTools.cpp was never compiled,
resulting in
Could not open component .so '/tmp/jacktest/lib/jack/jack_net.so':
/tmp/jacktest/lib/jack/jack_net.so: undefined symbol:
_ZN4Jack18JackGnuPlotMonitorIfED1E
See https://github.com/jackaudio/jack2/issues/4 for more.
Note that fill_n in JackTools.h needs additional modifications for
gcc-4.7.
fixes #4
tags/1.9.9.5
| @@ -291,123 +291,6 @@ void BuildClientPath(char* path_to_so, int path_len, const char* so_name) | |||||
| #endif | #endif | ||||
| template <class T> | |||||
| JackGnuPlotMonitor<T>::JackGnuPlotMonitor(uint32_t measure_cnt, uint32_t measure_points, std::string name) | |||||
| { | |||||
| jack_log ( "JackGnuPlotMonitor::JackGnuPlotMonitor %u measure points - %u measures", measure_points, measure_cnt ); | |||||
| fMeasureCnt = measure_cnt; | |||||
| fMeasurePoints = measure_points; | |||||
| fTablePos = 0; | |||||
| fName = name; | |||||
| fCurrentMeasure = new T[fMeasurePoints]; | |||||
| fMeasureTable = new T*[fMeasureCnt]; | |||||
| for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||||
| { | |||||
| fMeasureTable[cnt] = new T[fMeasurePoints]; | |||||
| fill_n ( fMeasureTable[cnt], fMeasurePoints, 0 ); | |||||
| } | |||||
| } | |||||
| template <class T> | |||||
| JackGnuPlotMonitor<T>::~JackGnuPlotMonitor() | |||||
| { | |||||
| jack_log ( "JackGnuPlotMonitor::~JackGnuPlotMonitor" ); | |||||
| for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||||
| delete[] fMeasureTable[cnt]; | |||||
| delete[] fMeasureTable; | |||||
| delete[] fCurrentMeasure; | |||||
| } | |||||
| template <class T> | |||||
| T JackGnuPlotMonitor<T>::AddNew(T measure_point) | |||||
| { | |||||
| fMeasureId = 0; | |||||
| return fCurrentMeasure[fMeasureId++] = measure_point; | |||||
| } | |||||
| template <class T> | |||||
| uint32_t JackGnuPlotMonitor<T>::New() | |||||
| { | |||||
| return fMeasureId = 0; | |||||
| } | |||||
| template <class T> | |||||
| T JackGnuPlotMonitor<T>::Add(T measure_point) | |||||
| { | |||||
| return fCurrentMeasure[fMeasureId++] = measure_point; | |||||
| } | |||||
| template <class T> | |||||
| uint32_t JackGnuPlotMonitor<T>::AddLast(T measure_point) | |||||
| { | |||||
| fCurrentMeasure[fMeasureId] = measure_point; | |||||
| fMeasureId = 0; | |||||
| return Write(); | |||||
| } | |||||
| template <class T> | |||||
| uint32_t JackGnuPlotMonitor<T>::Write() | |||||
| { | |||||
| for ( uint32_t point = 0; point < fMeasurePoints; point++ ) | |||||
| fMeasureTable[fTablePos][point] = fCurrentMeasure[point]; | |||||
| if ( ++fTablePos == fMeasureCnt ) | |||||
| fTablePos = 0; | |||||
| return fTablePos; | |||||
| } | |||||
| template <class T> | |||||
| int JackGnuPlotMonitor<T>::Save(std::string name) | |||||
| { | |||||
| std::string filename = ( name.empty() ) ? fName : name; | |||||
| filename += ".log"; | |||||
| jack_log ( "JackGnuPlotMonitor::Save filename %s", filename.c_str() ); | |||||
| std::ofstream file ( filename.c_str() ); | |||||
| for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||||
| { | |||||
| for ( uint32_t point = 0; point < fMeasurePoints; point++ ) | |||||
| file << fMeasureTable[cnt][point] << " \t"; | |||||
| file << std::endl; | |||||
| } | |||||
| file.close(); | |||||
| return 0; | |||||
| } | |||||
| template <class T> | |||||
| int JackGnuPlotMonitor<T>::SetPlotFile(std::string* options_list, uint32_t options_number, | |||||
| std::string* field_names, uint32_t field_number, | |||||
| std::string name) | |||||
| { | |||||
| std::string title = ( name.empty() ) ? fName : name; | |||||
| std::string plot_filename = title + ".plt"; | |||||
| std::string data_filename = title + ".log"; | |||||
| std::ofstream file ( plot_filename.c_str() ); | |||||
| file << "set multiplot" << std::endl; | |||||
| file << "set grid" << std::endl; | |||||
| file << "set title \"" << title << "\"" << std::endl; | |||||
| for ( uint32_t i = 0; i < options_number; i++ ) | |||||
| file << options_list[i] << std::endl; | |||||
| file << "plot "; | |||||
| for ( uint32_t row = 1; row <= field_number; row++ ) | |||||
| { | |||||
| file << "\"" << data_filename << "\" using " << row << " title \"" << field_names[row-1] << "\" with lines"; | |||||
| file << ( ( row < field_number ) ? ", " : "\n" ); | |||||
| } | |||||
| jack_log ( "JackGnuPlotMonitor::SetPlotFile - Save GnuPlot file to '%s'", plot_filename.c_str() ); | |||||
| file.close(); | |||||
| return 0; | |||||
| } | |||||
| } // end of namespace | } // end of namespace | ||||
| @@ -37,6 +37,7 @@ | |||||
| #include "jslist.h" | #include "jslist.h" | ||||
| #include "JackCompilerDeps.h" | #include "JackCompilerDeps.h" | ||||
| #include "JackError.h" | |||||
| #include <string> | #include <string> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| @@ -109,26 +110,115 @@ namespace Jack | |||||
| std::string fName; | std::string fName; | ||||
| public: | public: | ||||
| JackGnuPlotMonitor(uint32_t measure_cnt, uint32_t measure_points, std::string name) | |||||
| { | |||||
| jack_log ( "JackGnuPlotMonitor::JackGnuPlotMonitor %u measure points - %u measures", measure_points, measure_cnt ); | |||||
| fMeasureCnt = measure_cnt; | |||||
| fMeasurePoints = measure_points; | |||||
| fTablePos = 0; | |||||
| fName = name; | |||||
| fCurrentMeasure = new T[fMeasurePoints]; | |||||
| fMeasureTable = new T*[fMeasureCnt]; | |||||
| for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||||
| { | |||||
| fMeasureTable[cnt] = new T[fMeasurePoints]; | |||||
| fill_n ( fMeasureTable[cnt], fMeasurePoints, 0 ); | |||||
| } | |||||
| } | |||||
| ~JackGnuPlotMonitor() | |||||
| { | |||||
| jack_log ( "JackGnuPlotMonitor::~JackGnuPlotMonitor" ); | |||||
| for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||||
| delete[] fMeasureTable[cnt]; | |||||
| delete[] fMeasureTable; | |||||
| delete[] fCurrentMeasure; | |||||
| } | |||||
| T AddNew(T measure_point) | |||||
| { | |||||
| fMeasureId = 0; | |||||
| return fCurrentMeasure[fMeasureId++] = measure_point; | |||||
| } | |||||
| uint32_t New() | |||||
| { | |||||
| return fMeasureId = 0; | |||||
| } | |||||
| T Add(T measure_point) | |||||
| { | |||||
| return fCurrentMeasure[fMeasureId++] = measure_point; | |||||
| } | |||||
| uint32_t AddLast(T measure_point) | |||||
| { | |||||
| fCurrentMeasure[fMeasureId] = measure_point; | |||||
| fMeasureId = 0; | |||||
| return Write(); | |||||
| } | |||||
| uint32_t Write() | |||||
| { | |||||
| for ( uint32_t point = 0; point < fMeasurePoints; point++ ) | |||||
| fMeasureTable[fTablePos][point] = fCurrentMeasure[point]; | |||||
| if ( ++fTablePos == fMeasureCnt ) | |||||
| fTablePos = 0; | |||||
| return fTablePos; | |||||
| } | |||||
| int Save(std::string name = std::string ( "" )) | |||||
| { | |||||
| std::string filename = ( name.empty() ) ? fName : name; | |||||
| filename += ".log"; | |||||
| jack_log ( "JackGnuPlotMonitor::Save filename %s", filename.c_str() ); | |||||
| std::ofstream file ( filename.c_str() ); | |||||
| for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||||
| { | |||||
| for ( uint32_t point = 0; point < fMeasurePoints; point++ ) | |||||
| file << fMeasureTable[cnt][point] << " \t"; | |||||
| file << std::endl; | |||||
| } | |||||
| file.close(); | |||||
| return 0; | |||||
| } | |||||
| int SetPlotFile(std::string* options_list, uint32_t options_number, | |||||
| std::string* field_names, uint32_t field_number, | |||||
| std::string name = std::string ( "" )) | |||||
| { | |||||
| std::string title = ( name.empty() ) ? fName : name; | |||||
| std::string plot_filename = title + ".plt"; | |||||
| std::string data_filename = title + ".log"; | |||||
| std::ofstream file ( plot_filename.c_str() ); | |||||
| file << "set multiplot" << std::endl; | |||||
| file << "set grid" << std::endl; | |||||
| file << "set title \"" << title << "\"" << std::endl; | |||||
| for ( uint32_t i = 0; i < options_number; i++ ) | |||||
| file << options_list[i] << std::endl; | |||||
| file << "plot "; | |||||
| for ( uint32_t row = 1; row <= field_number; row++ ) | |||||
| { | |||||
| file << "\"" << data_filename << "\" using " << row << " title \"" << field_names[row-1] << "\" with lines"; | |||||
| file << ( ( row < field_number ) ? ", " : "\n" ); | |||||
| } | |||||
| jack_log ( "JackGnuPlotMonitor::SetPlotFile - Save GnuPlot file to '%s'", plot_filename.c_str() ); | |||||
| file.close(); | |||||
| return 0; | |||||
| } | |||||
| JackGnuPlotMonitor(uint32_t measure_cnt = 512, uint32_t measure_points = 5, std::string name = std::string("default")); | |||||
| ~JackGnuPlotMonitor(); | |||||
| T AddNew(T measure_point); | |||||
| uint32_t New(); | |||||
| T Add(T measure_point); | |||||
| uint32_t AddLast(T measure_point); | |||||
| uint32_t Write(); | |||||
| int Save(std::string name = std::string("")); | |||||
| int SetPlotFile(std::string* options_list = NULL, uint32_t options_number = 0, | |||||
| std::string* field_names = NULL, uint32_t field_number = 0, | |||||
| std::string name = std::string("")); | |||||
| }; | }; | ||||
| void BuildClientPath(char* path_to_so, int path_len, const char* so_name); | void BuildClientPath(char* path_to_so, int path_len, const char* so_name); | ||||