From f1a59e5373c844d34acbc1c7eabbc75b23a77e54 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 19 Jan 2015 14:57:24 -0500 Subject: [PATCH] new read tester for investigating read bandwidth issues --- tools/sfrtest.cc | 167 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 tools/sfrtest.cc diff --git a/tools/sfrtest.cc b/tools/sfrtest.cc new file mode 100644 index 0000000000..8a1d715007 --- /dev/null +++ b/tools/sfrtest.cc @@ -0,0 +1,167 @@ +/* g++ -o sfrtest sfrtest.cc `pkg-config --cflags --libs sndfile` `pkg-config --cflags --libs glibmm-2.4` */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; + +SF_INFO format_info; +float* data = 0; +bool with_sync = false; + +int +read_one (SNDFILE* sf, uint32_t nframes) +{ + if (sf_read_float (sf, (float*) data, nframes) != nframes) { + return -1; + } + + if (with_sync) { + sf_write_sync (sf); + } + + return 0; +} + +void +usage () +{ + cout << "sfrtest [ -n NFILES ] [ -b BLOCKSIZE ] [ -s ] [ -D ] filename-template" << endl; +} + +int +main (int argc, char* argv[]) +{ + vector sndfiles; + uint32_t sample_size; + char optstring[] = "n:b:s"; + uint32_t block_size = 64 * 1024; + uint32_t nfiles = 100; + bool direct = false; + const struct option longopts[] = { + { "nfiles", 1, 0, 'n' }, + { "blocksize", 1, 0, 'b' }, + { "sync", 0, 0, 's' }, + { "direct", 0, 0, 'D' }, + { 0, 0, 0, 0 } + }; + + int option_index = 0; + int c = 0; + char const * name_template = 0; + int samplerate; + + while (1) { + if ((c = getopt_long (argc, argv, optstring, longopts, &option_index)) == -1) { + break; + } + + switch (c) { + case 'n': + nfiles = atoi (optarg); + break; + case 'b': + block_size = atoi (optarg); + break; + case 's': + with_sync = true; + break; + case 'D': + direct = true; + break; + default: + usage (); + return 0; + } + } + + if (optind < argc) { + name_template = argv[optind]; + } else { + usage (); + return 1; + } + + for (uint32_t n = 1; n <= nfiles; ++n) { + SNDFILE* sf; + char path[PATH_MAX+1]; + + snprintf (path, sizeof (path), name_template, n); + + if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + break; + } + + int flags = O_RDONLY; + int fd = open (path, flags, 0644); + + if (fd < 0) { + cerr << "Could not open file #" << n << " @ " << path << " (" << strerror (errno) << ")" << endl; + return 1; + } + +#ifdef __APPLE__ + if (direct) { + /* Apple man pages say only that it returns "a value other than -1 on success", + which probably means zero, but you just can't be too careful with + those guys. + */ + if (fcntl (fd, F_NOCACHE, 1) == -1) { + cerr << "Cannot set F_NOCACHE on file # " << n << endl; + } + } +#endif + + if ((sf = sf_open_fd (fd, SFM_READ, &format_info, true)) == 0) { + cerr << "Could not open SNDFILE #" << n << " @ " << path << " (" << sf_strerror (0) << ")" << endl; + return 1; + } + + samplerate = format_info.samplerate; + + sndfiles.push_back (sf); + } + + cout << "Discovered " << nfiles+1 << " files using " << name_template << endl; + + data = new float[block_size]; + uint64_t read = 0; + + while (true) { + gint64 before; + before = g_get_monotonic_time(); + for (vector::iterator s = sndfiles.begin(); s != sndfiles.end(); ++s) { + if (read_one (*s, block_size)) { + cerr << "Read failed for file #" << distance (sndfiles.begin(), s) << endl; + return 1; + } + } + read += block_size; + gint64 elapsed = g_get_monotonic_time() - before; + double bandwidth = (sndfiles.size() * block_size * sample_size) / (elapsed/1000000.0); + double data_minutes = read / (double) (60.0 * 48000.0); + const double data_rate = sndfiles.size() * sample_size * samplerate; + stringstream ds; + ds << setprecision (1) << data_minutes; + + cout << "BW @ " << read << " frames (" << ds.str() << " minutes) = " << (bandwidth/1048576.0) << " MB/sec " << bandwidth / data_rate << " x faster than necessary " << endl; + } + + return 0; +} + +