Browse Source

Add JackGnuPlotMonitor to JackTools - improve time monitoring for netjack2

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2722 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.90
moret 17 years ago
parent
commit
e3ceba7078
7 changed files with 227 additions and 224 deletions
  1. +43
    -42
      common/JackNetDriver.cpp
  2. +7
    -7
      common/JackNetDriver.h
  3. +22
    -20
      common/JackNetManager.cpp
  4. +3
    -2
      common/JackNetManager.h
  5. +0
    -125
      common/JackNetTool.h
  6. +0
    -1
      common/JackTools.cpp
  7. +152
    -27
      common/JackTools.h

+ 43
- 42
common/JackNetDriver.cpp View File

@@ -30,24 +30,26 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#define DEFAULT_MULTICAST_IP "225.3.19.154"
#define DEFAULT_PORT 19000

using namespace std;

namespace Jack
{
#ifdef JACK_MONITOR
uint JackNetDriver::fMeasureCnt = 50;
uint JackNetDriver::fMeasureCnt = 64;
uint JackNetDriver::fMeasurePoints = 5;
uint JackNetDriver::fMonitorPlotOptionsCnt = 2;
std::string JackNetDriver::fMonitorPlotOptions[] =
string JackNetDriver::fMonitorPlotOptions[] =
{
std::string ( "set xlabel \"audio cycles\"" ),
std::string ( "set ylabel \"usecs\"" )
string ( "set xlabel \"audio cycles\"" ),
string ( "set ylabel \"% of audio cycle\"" )
};
std::string JackNetDriver::fMonitorFieldNames[] =
string JackNetDriver::fMonitorFieldNames[] =
{
std::string ( "cyclestart" ),
std::string ( "read end" ),
std::string ( "write start" ),
std::string ( "sync end" ),
std::string ( "send end" )
string ( "cyclestart" ),
string ( "read end" ),
string ( "write start" ),
string ( "sync send" ),
string ( "send end" )
};
#endif

@@ -55,6 +57,8 @@ namespace Jack
const char* ip, int port, int mtu, int midi_input_ports, int midi_output_ports, const char* net_name, uint transport_sync )
: JackAudioDriver ( name, alias, engine, table ), fSocket ( ip, port )
{
jack_log ( "JackNetDriver::JackNetDriver ip %s, port %d", ip, port );

fMulticastIP = new char[strlen ( ip ) + 1];
strcpy ( fMulticastIP, ip );
fParams.fMtu = mtu;
@@ -63,15 +67,6 @@ namespace Jack
strcpy ( fParams.fName, net_name );
fSocket.GetName ( fParams.fSlaveNetName );
fParams.fTransportSync = transport_sync;

//monitor
#ifdef JACK_MONITOR
fMonitor = new NetMonitor<jack_time_t> ( JackNetDriver::fMeasureCnt, JackNetDriver::fMeasurePoints );
fMeasure = new jack_time_t[JackNetDriver::fMeasurePoints];
std::string plot_file_name = std::string ( fParams.fName );
fMonitor->SetPlotFile ( plot_file_name, JackNetDriver::fMonitorPlotOptions, JackNetDriver::fMonitorPlotOptionsCnt,
JackNetDriver::fMonitorFieldNames, JackNetDriver::fMeasurePoints );
#endif
}

JackNetDriver::~JackNetDriver()
@@ -88,6 +83,7 @@ namespace Jack
delete[] fMidiCapturePortList;
delete[] fMidiPlaybackPortList;
#ifdef JACK_MONITOR
fMonitor->Save();
delete[] fMeasure;
delete fMonitor;
#endif
@@ -108,16 +104,6 @@ namespace Jack
return res;
}


#ifdef JACK_MONITOR
int JackNetDriver::Close()
{
std::string filename = string ( fParams.fName );
fMonitor->Save ( filename );
return JackDriver::Close();
}
#endif

int JackNetDriver::Attach()
{
return 0;
@@ -256,22 +242,26 @@ namespace Jack
{
jack_info ( "Restarting driver..." );
delete[] fTxBuffer;
fTxBuffer = NULL;
delete[] fRxBuffer;
fRxBuffer = NULL;
delete fNetAudioCaptureBuffer;
fNetAudioCaptureBuffer = NULL;
delete fNetAudioPlaybackBuffer;
fNetAudioPlaybackBuffer = NULL;
delete fNetMidiCaptureBuffer;
fNetMidiCaptureBuffer = NULL;
delete fNetMidiPlaybackBuffer;
fNetMidiPlaybackBuffer = NULL;
FreePorts();
delete[] fMidiCapturePortList;
delete[] fMidiPlaybackPortList;
fTxBuffer = NULL;
fRxBuffer = NULL;
fNetAudioCaptureBuffer = NULL;
fNetAudioPlaybackBuffer = NULL;
fNetMidiCaptureBuffer = NULL;
fNetMidiPlaybackBuffer = NULL;
fMidiCapturePortList = NULL;
delete[] fMidiPlaybackPortList;
fMidiPlaybackPortList = NULL;
delete[] fMeasure;
fMeasure = NULL;
delete fMonitor;
fMonitor = NULL;
}

int JackNetDriver::SetParams()
@@ -335,6 +325,17 @@ namespace Jack
//payload size
fPayloadSize = fParams.fMtu - sizeof ( packet_header_t );

//monitor
#ifdef JACK_MONITOR
string plot_name = string ( fParams.fName );
plot_name += string ( "_slave_" );
plot_name += ( fEngineControl->fSyncMode ) ? string ( "sync" ) : string ( "async" );
fMonitor = new JackGnuPlotMonitor<float> ( JackNetDriver::fMeasureCnt, JackNetDriver::fMeasurePoints, plot_name );
fMeasure = new float[JackNetDriver::fMeasurePoints];
fMonitor->SetPlotFile ( JackNetDriver::fMonitorPlotOptions, JackNetDriver::fMonitorPlotOptionsCnt,
JackNetDriver::fMonitorFieldNames, JackNetDriver::fMeasurePoints );
#endif

return 0;
}

@@ -528,8 +529,8 @@ namespace Jack
JackDriver::CycleTakeBeginTime();

#ifdef JACK_MONITOR
fUsecCycleStart = GetMicroSeconds();
fMeasure[0] = GetMicroSeconds() - fUsecCycleStart;
fMeasureId = 0;
fMeasure[fMeasureId++] = ( ( (float)(GetMicroSeconds() - JackDriver::fBeginDateUst) ) / (float)fEngineControl->fPeriodUsecs ) * 100.f;
#endif

//audio, midi or sync if driver is late
@@ -572,7 +573,7 @@ namespace Jack


#ifdef JACK_MONITOR
fMeasure[1] = GetMicroSeconds() - fUsecCycleStart;
fMeasure[fMeasureId++] = ( ( (float)(GetMicroSeconds() - JackDriver::fBeginDateUst) ) / (float)fEngineControl->fPeriodUsecs ) * 100.f;
#endif

return 0;
@@ -594,7 +595,7 @@ namespace Jack
fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer ( audio_port_index ));

#ifdef JACK_MONITOR
fMeasure[2] = GetMicroSeconds() - fUsecCycleStart;
fMeasure[fMeasureId++] = ( ( (float)(GetMicroSeconds() - JackDriver::fBeginDateUst) ) / (float)fEngineControl->fPeriodUsecs ) * 100.f;
#endif

//sync
@@ -606,7 +607,7 @@ namespace Jack
tx_bytes = Send ( fParams.fMtu, 0 );

#ifdef JACK_MONITOR
fMeasure[3] = GetMicroSeconds() - fUsecCycleStart;
fMeasure[fMeasureId++] = ( ( (float)(GetMicroSeconds() - JackDriver::fBeginDateUst) ) / (float)fEngineControl->fPeriodUsecs ) * 100.f;
#endif

//midi
@@ -642,7 +643,7 @@ namespace Jack
}

#ifdef JACK_MONITOR
fMeasure[4] = GetMicroSeconds() - fUsecCycleStart;
fMeasure[fMeasureId++] = ( ( (float)(GetMicroSeconds() - JackDriver::fBeginDateUst) ) / (float)fEngineControl->fPeriodUsecs ) * 100.f;
fMonitor->Write ( fMeasure );
#endif



+ 7
- 7
common/JackNetDriver.h View File

@@ -24,6 +24,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "JackAudioDriver.h"
#include "JackNetTool.h"

#ifdef JACK_MONITOR
#include "JackFrameTimer.h"
#endif

namespace Jack
{
class JackNetDriver : public JackAudioDriver
@@ -67,9 +71,9 @@ namespace Jack
static uint fMonitorPlotOptionsCnt;
static std::string fMonitorPlotOptions[];
static std::string fMonitorFieldNames[];
jack_time_t* fMeasure;
NetMonitor<jack_time_t>* fMonitor;
jack_time_t fUsecCycleStart;
float* fMeasure;
int fMeasureId;
JackGnuPlotMonitor<float>* fMonitor;
#endif

bool Init();
@@ -98,10 +102,6 @@ namespace Jack
int inchannels, int outchannels, bool monitor, const char* capture_driver_name,
const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency );

#ifdef JACK_MONITOR
int Close();
#endif

int Attach();
int Detach();



+ 22
- 20
common/JackNetManager.cpp View File

@@ -31,18 +31,18 @@ namespace Jack
uint JackNetMaster::fMeasureCnt = 50;
uint JackNetMaster::fMeasurePoints = 5;
uint JackNetMaster::fMonitorPlotOptionsCnt = 2;
std::string JackNetMaster::fMonitorPlotOptions[] =
string JackNetMaster::fMonitorPlotOptions[] =
{
std::string ( "set xlabel \"audio cycles\"" ),
std::string ( "set ylabel \"audio frames\"" )
string ( "set xlabel \"audio cycles\"" ),
string ( "set ylabel \"% of audio cycle\"" )
};
std::string JackNetMaster::fMonitorFieldNames[] =
string JackNetMaster::fMonitorFieldNames[] =
{
std::string ( "cycle start" ),
std::string ( "sync send" ),
std::string ( "send end" ),
std::string ( "sync recv" ),
std::string ( "end of cycle" )
string ( "cycle start" ),
string ( "sync send" ),
string ( "send end" ),
string ( "sync recv" ),
string ( "end of cycle" )
};
#endif

@@ -119,10 +119,12 @@ namespace Jack

//monitor
#ifdef JACK_MONITOR
fMonitor = new NetMonitor<jack_nframes_t> ( JackNetMaster::fMeasureCnt, JackNetMaster::fMeasurePoints );
fMeasure = new jack_nframes_t[JackNetMaster::fMeasurePoints];
std::string plot_file_name = std::string ( fParams.fName );
fMonitor->SetPlotFile ( plot_file_name, JackNetMaster::fMonitorPlotOptions, JackNetMaster::fMonitorPlotOptionsCnt,
string plot_name = string ( fParams.fName );
plot_name += string ( "_master" );
//plot_name += ( fEngineControl->fSyncMode ) ? string ( "sync" ) : string ( "async" );
fMonitor = new JackGnuPlotMonitor<float> ( JackNetMaster::fMeasureCnt, JackNetMaster::fMeasurePoints, plot_name );
fMeasure = new float[JackNetMaster::fMeasurePoints];
fMonitor->SetPlotFile ( JackNetMaster::fMonitorPlotOptions, JackNetMaster::fMonitorPlotOptionsCnt,
JackNetMaster::fMonitorFieldNames, JackNetMaster::fMeasurePoints );
#endif
}
@@ -148,8 +150,7 @@ namespace Jack
delete[] fTxBuffer;
delete[] fRxBuffer;
#ifdef JACK_MONITOR
std::string filename = string ( fParams.fName );
fMonitor->Save ( filename );
fMonitor->Save();
delete[] fMeasure;
delete fMonitor;
#endif
@@ -394,7 +395,8 @@ fail:
packet_header_t* rx_head = reinterpret_cast<packet_header_t*> ( fRxBuffer );

#ifdef JACK_MONITOR
fMeasure[0] = jack_frames_since_cycle_start( fJackClient );
fMeasureId = 0;
fMeasure[fMeasureId++] = ( (float)jack_frames_since_cycle_start( fJackClient ) /(float)fParams.fPeriodSize ) * 100.f;
#endif

//buffers
@@ -428,7 +430,7 @@ fail:
return tx_bytes;

#ifdef JACK_MONITOR
fMeasure[1] = jack_frames_since_cycle_start( fJackClient );
fMeasure[fMeasureId++] = ( (float)jack_frames_since_cycle_start( fJackClient ) /(float)fParams.fPeriodSize ) * 100.f;
#endif

//midi
@@ -468,7 +470,7 @@ fail:
}

#ifdef JACK_MONITOR
fMeasure[2] = jack_frames_since_cycle_start( fJackClient );
fMeasure[fMeasureId++] = ( (float)jack_frames_since_cycle_start( fJackClient ) /(float)fParams.fPeriodSize ) * 100.f;
#endif

//receive --------------------------------------------------------------------------------------------------------------------
@@ -482,7 +484,7 @@ fail:
while ( !rx_bytes && ( rx_head->fDataType != 's' ) );

#ifdef JACK_MONITOR
fMeasure[3] = jack_frames_since_cycle_start( fJackClient );
fMeasure[fMeasureId++] = ( (float)jack_frames_since_cycle_start( fJackClient ) /(float)fParams.fPeriodSize ) * 100.f;
#endif

if ( fParams.fReturnMidiChannels || fParams.fReturnAudioChannels )
@@ -524,7 +526,7 @@ fail:
}

#ifdef JACK_MONITOR
fMeasure[4] = jack_frames_since_cycle_start( fJackClient );
fMeasure[fMeasureId++] = ( (float)jack_frames_since_cycle_start( fJackClient ) /(float)fParams.fPeriodSize ) * 100.f;
fMonitor->Write ( fMeasure );
#endif
return 0;


+ 3
- 2
common/JackNetManager.h View File

@@ -85,8 +85,9 @@ namespace Jack
static uint fMonitorPlotOptionsCnt;
static std::string fMonitorPlotOptions[];
static std::string fMonitorFieldNames[];
jack_nframes_t* fMeasure;
NetMonitor<jack_nframes_t>* fMonitor;
float* fMeasure;
int fMeasureId;
JackGnuPlotMonitor<float>* fMonitor;
#endif

bool Init();


+ 0
- 125
common/JackNetTool.h View File

@@ -24,9 +24,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "JackTools.h"
#include "JackPlatformNetSocket.h"
#include "types.h"

#include <string>
#include <algorithm>
#include <cmath>

using namespace std;
@@ -172,128 +169,6 @@ namespace Jack
void SetBuffer(int index, sample_t* buffer);
};

// net monitor ********************************************************************************

template <class T> class NetMonitor
{
private:
uint fMeasureCnt;
uint fMeasurePoints;
T** fMeasureTable;
uint fTablePos;

void DisplayMeasure ( T* measure )
{
string display;
for ( uint m_id = 0; m_id < fMeasurePoints; m_id++ )
{
char* value;
sprintf ( value, "%llu ", measure[m_id] );
display += string ( value );
}
cout << "NetMonitor:: '" << display << "'" << endl;
}


public:
NetMonitor ( uint measure_cnt = 512, uint measure_points = 5 )
{
jack_log ( "JackNetMonitor::JackNetMonitor measure_cnt %u measure_points %u", measure_cnt, measure_points );

fMeasureCnt = measure_cnt;
fMeasurePoints = measure_points;
fTablePos = 0;
//allocate measure table
fMeasureTable = new T*[fMeasureCnt];
for ( uint i = 0; i < fMeasureCnt; i++ )
fMeasureTable[i] = new T[fMeasurePoints];
//init measure table
for ( uint cnt = 0; cnt < fMeasureCnt; cnt++ )
for ( uint point = 0; point < fMeasurePoints; point++ )
fMeasureTable[cnt][point] = 0;
}

~NetMonitor()
{
jack_log ( "NetMonitor::~NetMonitor" );
for ( uint cnt = 0; cnt < fMeasureCnt; cnt++ )
delete[] fMeasureTable[cnt];
delete[] fMeasureTable;
}

void InitTable()
{
for ( uint cnt = 0; cnt < fMeasureCnt; cnt++ )
for ( uint point = 0; point < fMeasurePoints; point++ )
fMeasureTable[cnt][point] = 0;
}

uint Write ( T* measure )
{
for ( uint point = 0; point < fMeasurePoints; point++ )
fMeasureTable[fTablePos][point] = measure[point];
if ( ++fTablePos == fMeasureCnt )
fTablePos = 0;
return fTablePos;
}

int Save ( string& filename )
{
filename += "_netmonitor.log";

jack_log ( "JackNetMonitor::Save filename %s", filename.c_str() );

FILE* file = fopen ( filename.c_str(), "w" );

//print each measure with tab separated values
for ( uint cnt = 0; cnt < fMeasureCnt; cnt++ )
{
for ( uint pt = 0; pt < fMeasurePoints; pt++ )
fprintf ( file, "%llu \t ", fMeasureTable[cnt][pt] );
fprintf ( file, "\n" );
}

fclose(file);
return 0;
}

int SetPlotFile ( string& name, string* options_list = NULL, uint options_number = 0, string* field_names = NULL, uint field_number = 0 )
{
//names and file
string title = name + "_netmonitor";
string plot_filename = title + ".plt";
string data_filename = title + ".log";
FILE* file = fopen ( plot_filename.c_str(), "w" );

//base options
fprintf ( file, "set multiplot\n" );
fprintf ( file, "set grid\n" );
fprintf ( file, "set title \"%s\"\n", title.c_str() );

//additional options
for ( uint i = 0; i < options_number; i++ )
{
jack_log ( "JackNetMonitor::SetPlotFile - Add plot option : '%s'", options_list[i].c_str() );
fprintf ( file, "%s\n", options_list[i].c_str() );
}

//plot
fprintf ( file, "plot " );
for ( uint row = 1; row <= field_number; row++ )
{
jack_log ( "JackNetMonitor::SetPlotFile - Add plot : file '%s' row '%d' title '%s' field '%s'",
data_filename.c_str(), row, name.c_str(), field_names[row-1].c_str() );
fprintf ( file, "\"%s\" using %u title \"%s : %s\" with lines", data_filename.c_str(), row, name.c_str(), field_names[row-1].c_str() );
fprintf ( file, ( row < field_number ) ? "," : "\n" );
}

jack_log ( "JackNetMonitor::SetPlotFile - Saving GnuPlot '.plt' file to '%s'", plot_filename.c_str() );

fclose ( file );
return 0;
}
};

//utility *************************************************************************************

//socket API management


+ 0
- 1
common/JackTools.cpp View File

@@ -23,7 +23,6 @@

#include "JackConstants.h"
#include "JackTools.h"
#include "JackError.h"
#include <stdlib.h>
#include <stdio.h>



+ 152
- 27
common/JackTools.h View File

@@ -35,56 +35,181 @@
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
#include <fstream>
#include <strstream>
#include "jslist.h"
#include "driver_interface.h"

#include "JackExports.h"
#include "JackError.h"

namespace Jack
{

/*!
\brief Utility functions.
*/
struct EXPORT JackTools
{
static int GetPID();
static int GetUID();
static char* UserDir();
static char* ServerDir(const char* server_name, char* server_dir);
static const char* DefaultServerName();
static void CleanupFiles(const char* server_name);
static int GetTmpdir();
static void RewriteName(const char* name, char* new_name);
};
/*!
\brief Internal cient command line parser.
*/
class EXPORT JackArgParser
{
/*!
\brief Utility functions.
*/
struct EXPORT JackTools
{
static int GetPID();
static int GetUID();
static char* UserDir();
static char* ServerDir(const char* server_name, char* server_dir);
static const char* DefaultServerName();
static void CleanupFiles(const char* server_name);
static int GetTmpdir();
static void RewriteName(const char* name, char* new_name);
};
/*!
\brief Internal cient command line parser.
*/
class EXPORT JackArgParser
{
private:
std::string fArgString;
int fArgc;
std::vector<std::string> fArgv;

public:
JackArgParser(const char* arg);
~JackArgParser();
std::string GetArgString();
std::string GetArgString();
int GetNumArgv();
int GetArgc();
int GetArgv(std::vector<std::string>& argv);
int GetArgv(char** argv);
void DeleteArgv(const char** argv);
int ParseParams(jack_driver_desc_t* desc, JSList** param_list);
};
};

/*!
\brief Generic monitoring class. Saves data to GnuPlot files ('.plt' and '.log' datafile)
*/

template <class T> class JackGnuPlotMonitor
{
private:
uint32_t fMeasureCnt;
uint32_t fMeasurePoints;
T** fMeasureTable;
uint32_t fTablePos;
std::string fName;

void DisplayMeasure ( T* measure )
{
std::string display;
for ( uint32_t m_id = 0; m_id < fMeasurePoints; m_id++ )
{
std::ostrstream value ( display, measure[m_id] );
display += std::string ( " " );
}
std::cout << "JackGnuPlotMonitor::Display '" << display << "'" << std::endl;
}


public:
JackGnuPlotMonitor ( uint32_t measure_cnt = 512, uint32_t measure_points = 5, std::string name = std::string ( "default" ) )
{
jack_log ( "JackGnuPlotMonitor::JackGnuPlotMonitor measure_cnt %u measure_points %u", measure_cnt, measure_points );

fMeasureCnt = measure_cnt;
fMeasurePoints = measure_points;
fTablePos = 0;
fName = name;
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;
}

void InitTable()
{
for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ )
for ( uint32_t point = 0; point < fMeasurePoints; point++ )
fMeasureTable[cnt][point] = 0;
}

uint32_t Write ( T* measure )
{
for ( uint32_t point = 0; point < fMeasurePoints; point++ )
fMeasureTable[fTablePos][point] = measure[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 = NULL, uint32_t options_number = 0,
std::string* field_names = NULL, uint32_t field_number = 0,
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++ )
{
jack_log ( "JackGnuPlotMonitor::SetPlotFile - Add plot option : '%s'", options_list[i].c_str() );
file << options_list[i] << std::endl;
}

file << "plot ";
for ( uint32_t row = 1; row <= field_number; row++ )
{
jack_log ( "JackGnuPlotMonitor::SetPlotFile - Add plot : file '%s' row '%d' title '%s' field '%s'",
data_filename.c_str(), row, name.c_str(), field_names[row-1].c_str() );
file << "\"" << data_filename << "\" using " << row << " title \"" << title << " : " << field_names[row-1] << "\" with lines";
file << ( ( row < field_number ) ? ", " : "\n" );
}

jack_log ( "JackGnuPlotMonitor::SetPlotFile - Saving GnuPlot '.plt' file to '%s'", plot_filename.c_str() );

file.close();
return 0;
}
};
}

#endif

Loading…
Cancel
Save