X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=tools%2Fsftest.cc;h=86e301889cea3f63626081de458078f38eabb5e4;hb=8488d8f6a53d3385893a435481cb60ed21c21ea0;hp=4424513077e340916a346bcfff71cff962304107;hpb=50b7ab651e4afbf298df051e87159668e15f158c;p=ardour.git diff --git a/tools/sftest.cc b/tools/sftest.cc index 4424513077..86e301889c 100644 --- a/tools/sftest.cc +++ b/tools/sftest.cc @@ -5,11 +5,16 @@ #include #include #include +#include + #include #include #include #include #include +#include +#include +#include #include @@ -18,6 +23,13 @@ using namespace std; SF_INFO format_info; float* data = 0; bool with_sync = false; +bool keep_writing = true; + +void +signal_handler (int) +{ + keep_writing = false; +} int write_one (SNDFILE* sf, uint32_t nframes) @@ -36,7 +48,13 @@ write_one (SNDFILE* sf, uint32_t nframes) void usage () { - cout << "sftest [ -f HEADER-FORMAT ] [ -F DATA-FORMAT ] [ -r SAMPLERATE ] [ -n NFILES ] [ -b BLOCKSIZE ] [ -s ]" << endl; + cout << "sftest [ -f HEADER-FORMAT ] [ -F DATA-FORMAT ] [ -r SAMPLERATE ] [ -n NFILES ] [ -b BLOCKSIZE ] [ -s ]"; + +#ifdef __APPLE__ + cout << " [ -D ]"; +#endif + cout << endl; + cout << "\tHEADER-FORMAT is one of:" << endl << "\t\tWAV" << endl << "\t\tCAF" << endl @@ -53,13 +71,24 @@ main (int argc, char* argv[]) { vector sndfiles; uint32_t sample_size; - char optstring[] = "f:r:F:n:c:b:s"; - int channels, samplerate; + char optstring[] = "f:r:F:n:c:b:sd:qS:" +#ifdef __APPLE__ + "D" +#endif + ; + int channels = 1; + int samplerate = 48000; char const *suffix = ".wav"; char const *header_format = "wav"; char const *data_format = "float"; + size_t filesize = 10 * 1048576; uint32_t block_size = 64 * 1024; uint32_t nfiles = 100; + string dirname = "/tmp"; + bool quiet = false; +#ifdef __APPLE__ + bool direct = false; +#endif const struct option longopts[] = { { "header-format", 1, 0, 'f' }, { "data-format", 1, 0, 'F' }, @@ -68,6 +97,12 @@ main (int argc, char* argv[]) { "blocksize", 1, 0, 'b' }, { "channels", 1, 0, 'c' }, { "sync", 0, 0, 's' }, + { "dirname", 1, 0, 'd' }, + { "quiet", 0, 0, 'q' }, + { "filesize", 1, 0, 'S' }, +#ifdef __APPLE__ + { "direct", 0, 0, 'D' }, +#endif { 0, 0, 0, 0 } }; @@ -105,7 +140,20 @@ main (int argc, char* argv[]) case 's': with_sync = true; break; - + case 'S': + filesize = atoi (optarg); + break; +#ifdef __APPLE__ + case 'D': + direct = true; + break; +#endif + case 'd': + dirname = optarg; + break; + case 'q': + quiet = true; + break; default: usage (); return 0; @@ -154,8 +202,11 @@ main (int argc, char* argv[]) return 0; } - char tmpdirname[] = "sftest-XXXXXX"; - g_mkdtemp (tmpdirname); + string tmpdirname = Glib::build_filename (dirname, "sftest"); + if (g_mkdir_with_parents (tmpdirname.c_str(), 0755)) { + cerr << "Cannot create output directory\n"; + return 1; + } for (uint32_t n = 0; n < nfiles; ++n) { SNDFILE* sf; @@ -167,22 +218,54 @@ main (int argc, char* argv[]) ss << suffix; path = Glib::build_filename (tmpdirname, ss.str()); - - if ((sf = sf_open (path.c_str(), SFM_RDWR, &format_info)) == 0) { - cerr << "Could not open file #" << n << " @ " << path << endl; + + int flags = O_RDWR|O_CREAT|O_TRUNC; + int fd = open (path.c_str(), 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_RDWR, &format_info, true)) == 0) { + cerr << "Could not open SNDFILE #" << n << " @ " << path << " (" << sf_strerror (0) << ")" << endl; return 1; } sndfiles.push_back (sf); } - cout << nfiles << " files are in " << tmpdirname << endl; - cout << "Format is " << suffix << ' ' << channels << " channel" << (channels > 1 ? "s" : "") << " written in chunks of " << block_size << " frames, synced ? " << (with_sync ? "yes" : "no") << endl; - + if (!quiet) { + cout << nfiles << " files are in " << tmpdirname; +#ifdef __APPLE__ + cout << " all used " << (direct ? "without" : "with") << " OS buffer cache"; +#endif + cout << endl; + cout << "Format is " << suffix << ' ' << channels << " channel" << (channels > 1 ? "s" : "") << " written in chunks of " << block_size << " frames, synced ? " << (with_sync ? "yes" : "no") << endl; + } + data = new float[block_size*channels]; uint64_t written = 0; - - while (true) { + + signal (SIGINT, signal_handler); + signal (SIGSTOP, signal_handler); + + + double max_bandwidth = 0; + double min_bandwidth = DBL_MAX; + + while (keep_writing && written < filesize) { gint64 before; before = g_get_monotonic_time(); for (vector::iterator s = sndfiles.begin(); s != sndfiles.end(); ++s) { @@ -198,10 +281,26 @@ main (int argc, char* argv[]) const double data_rate = sndfiles.size() * channels * sample_size * samplerate; stringstream ds; ds << setprecision (1) << data_minutes; + + max_bandwidth = max (max_bandwidth, bandwidth); + min_bandwidth = min (min_bandwidth, bandwidth); - cout << "BW @ " << written << " frames (" << ds.str() << " minutes) = " << (bandwidth/1048576.0) << " MB/sec " << bandwidth / data_rate << " x faster than necessary " << endl; + if (!quiet) { + cout << "BW @ " << written << " frames (" << ds.str() << " minutes) = " << (bandwidth/1048576.0) << " MB/sec " << bandwidth / data_rate << " x faster than necessary " << endl; + } } + cout << "Max bandwidth = " << max_bandwidth / 1048576.0 << " MB/sec" << endl; + cout << "Min bandwidth = " << min_bandwidth / 1048576.0 << " MB/sec" << endl; + + if (!quiet) { + cout << "Closing files ...\n"; + for (vector::iterator s = sndfiles.begin(); s != sndfiles.end(); ++s) { + sf_close (*s); + } + cout << "Done.\n"; + } + return 0; }