13
0

split apart read and write chunk size and offer platform-dependent sizes for reading. Write chunk size should remain unchanged from before.

This commit is contained in:
Paul Davis 2015-01-22 12:52:06 -05:00
parent 1473442204
commit 3b2c23be93
8 changed files with 66 additions and 47 deletions

View File

@ -138,8 +138,12 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream
ChanCount n_channels() { return _n_channels; } ChanCount n_channels() { return _n_channels; }
static framecnt_t disk_io_frames() { return disk_io_chunk_frames; } static framecnt_t disk_read_frames() { return disk_read_chunk_frames; }
static void set_disk_io_chunk_frames (framecnt_t n) { disk_io_chunk_frames = n; } static framecnt_t disk_write_frames() { return disk_write_chunk_frames; }
static void set_disk_read_chunk_frames (framecnt_t n) { disk_read_chunk_frames = n; }
static void set_disk_write_chunk_frames (framecnt_t n) { disk_write_chunk_frames = n; }
static framecnt_t default_disk_read_chunk_frames ();
static framecnt_t default_disk_write_chunk_frames ();
/* Stateful */ /* Stateful */
virtual XMLNode& get_state(void); virtual XMLNode& get_state(void);
@ -268,7 +272,9 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream
framecnt_t& rec_nframes, framecnt_t& rec_offset framecnt_t& rec_nframes, framecnt_t& rec_offset
); );
static framecnt_t disk_io_chunk_frames; static framecnt_t disk_read_chunk_frames;
static framecnt_t disk_write_chunk_frames;
std::vector<CaptureInfo*> capture_info; std::vector<CaptureInfo*> capture_info;
mutable Glib::Threads::Mutex capture_info_lock; mutable Glib::Threads::Mutex capture_info_lock;

View File

@ -67,7 +67,8 @@ CONFIG_VARIABLE (RemoteModel, remote_model, "remote-model", MixerOrdered)
/* disk operations */ /* disk operations */
CONFIG_VARIABLE (uint32_t, minimum_disk_io_bytes, "minimum-disk-io-bytes", 1024 * 256) CONFIG_VARIABLE (uint32_t, minimum_disk_read_bytes, "minimum-disk-read-bytes", ARDOUR::Diskstream::default_disk_read_chunk_frames() * sizeof (ARDOUR::Sample))
CONFIG_VARIABLE (uint32_t, minimum_disk_write_bytes, "minimum-disk-write-bytes", ARDOUR::Diskstream::default_disk_write_chunk_frames() * sizeof (ARDOUR::Sample))
CONFIG_VARIABLE (float, midi_readahead, "midi-readahead", 1.0) CONFIG_VARIABLE (float, midi_readahead, "midi-readahead", 1.0)
CONFIG_VARIABLE (float, audio_capture_buffer_seconds, "capture-buffer-seconds", 5.0) CONFIG_VARIABLE (float, audio_capture_buffer_seconds, "capture-buffer-seconds", 5.0)
CONFIG_VARIABLE (float, audio_playback_buffer_seconds, "playback-buffer-seconds", 5.0) CONFIG_VARIABLE (float, audio_playback_buffer_seconds, "playback-buffer-seconds", 5.0)

View File

@ -128,9 +128,7 @@ AudioDiskstream::~AudioDiskstream ()
void void
AudioDiskstream::allocate_working_buffers() AudioDiskstream::allocate_working_buffers()
{ {
assert(disk_io_frames() > 0); _working_buffers_size = max (disk_write_chunk_frames, disk_read_chunk_frames);
_working_buffers_size = disk_io_frames();
_mixdown_buffer = new Sample[_working_buffers_size]; _mixdown_buffer = new Sample[_working_buffers_size];
_gain_buffer = new gain_t[_working_buffers_size]; _gain_buffer = new gain_t[_working_buffers_size];
} }
@ -786,10 +784,10 @@ AudioDiskstream::commit (framecnt_t playback_distance)
} }
} else { } else {
if (_io && _io->active()) { if (_io && _io->active()) {
need_butler = ((framecnt_t) c->front()->playback_buf->write_space() >= disk_io_chunk_frames) need_butler = ((framecnt_t) c->front()->playback_buf->write_space() >= disk_read_chunk_frames)
|| ((framecnt_t) c->front()->capture_buf->read_space() >= disk_io_chunk_frames); || ((framecnt_t) c->front()->capture_buf->read_space() >= disk_write_chunk_frames);
} else { } else {
need_butler = ((framecnt_t) c->front()->capture_buf->read_space() >= disk_io_chunk_frames); need_butler = ((framecnt_t) c->front()->capture_buf->read_space() >= disk_write_chunk_frames);
} }
} }
@ -1056,8 +1054,8 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
int int
AudioDiskstream::do_refill_with_alloc () AudioDiskstream::do_refill_with_alloc ()
{ {
Sample* mix_buf = new Sample[disk_io_chunk_frames]; Sample* mix_buf = new Sample[disk_read_chunk_frames];
float* gain_buf = new float[disk_io_chunk_frames]; float* gain_buf = new float[disk_read_chunk_frames];
int ret = _do_refill(mix_buf, gain_buf); int ret = _do_refill(mix_buf, gain_buf);
@ -1108,22 +1106,22 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
for us to be called again, ASAP. for us to be called again, ASAP.
*/ */
if (total_space >= (_slaved ? 3 : 2) * disk_io_chunk_frames) { if (total_space >= (_slaved ? 3 : 2) * disk_read_chunk_frames) {
ret = 1; ret = 1;
} }
/* if we're running close to normal speed and there isn't enough /* if we're running close to normal speed and there isn't enough
space to do disk_io_chunk_frames of I/O, then don't bother. space to do disk_read_chunk_frames of I/O, then don't bother.
at higher speeds, just do it because the sync between butler at higher speeds, just do it because the sync between butler
and audio thread may not be good enough. and audio thread may not be good enough.
Note: it is a design assumption that disk_io_chunk_frames is smaller Note: it is a design assumption that disk_read_chunk_frames is smaller
than the playback buffer size, so this check should never trip when than the playback buffer size, so this check should never trip when
the playback buffer is empty. the playback buffer is empty.
*/ */
if ((total_space < disk_io_chunk_frames) && fabs (_actual_speed) < 2.0f) { if ((total_space < disk_read_chunk_frames) && fabs (_actual_speed) < 2.0f) {
return 0; return 0;
} }
@ -1136,9 +1134,9 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
return 0; return 0;
} }
/* never do more than disk_io_chunk_frames worth of disk input per call (limit doesn't apply for memset) */ /* never do more than disk_read_chunk_frames worth of disk input per call (limit doesn't apply for memset) */
total_space = min (disk_io_chunk_frames, total_space); total_space = min (disk_read_chunk_frames, total_space);
if (reversed) { if (reversed) {
@ -1215,14 +1213,14 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
chan->playback_buf->get_write_vector (&vector); chan->playback_buf->get_write_vector (&vector);
if ((framecnt_t) vector.len[0] > disk_io_chunk_frames) { if ((framecnt_t) vector.len[0] > disk_read_chunk_frames) {
/* we're not going to fill the first chunk, so certainly do not bother with the /* we're not going to fill the first chunk, so certainly do not bother with the
other part. it won't be connected with the part we do fill, as in: other part. it won't be connected with the part we do fill, as in:
.... => writable space .... => writable space
++++ => readable space ++++ => readable space
^^^^ => 1 x disk_io_chunk_frames that would be filled ^^^^ => 1 x disk_read_chunk_frames that would be filled
|......|+++++++++++++|...............................| |......|+++++++++++++|...............................|
buf1 buf0 buf1 buf0
@ -1247,7 +1245,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
len2 = vector.len[1]; len2 = vector.len[1];
to_read = min (ts, len1); to_read = min (ts, len1);
to_read = min (to_read, disk_io_chunk_frames); to_read = min (to_read, disk_read_chunk_frames);
assert (to_read >= 0); assert (to_read >= 0);
@ -1266,7 +1264,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
if (to_read) { if (to_read) {
/* we read all of vector.len[0], but it wasn't an entire disk_io_chunk_frames of data, /* we read all of vector.len[0], but it wasn't an entire disk_read_chunk_frames of data,
so read some or all of vector.len[1] as well. so read some or all of vector.len[1] as well.
*/ */
@ -1294,12 +1292,12 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
/** Flush pending data to disk. /** Flush pending data to disk.
* *
* Important note: this function will write *AT MOST* disk_io_chunk_frames * Important note: this function will write *AT MOST* disk_write_chunk_frames
* of data to disk. it will never write more than that. If it writes that * of data to disk. it will never write more than that. If it writes that
* much and there is more than that waiting to be written, it will return 1, * much and there is more than that waiting to be written, it will return 1,
* otherwise 0 on success or -1 on failure. * otherwise 0 on success or -1 on failure.
* *
* If there is less than disk_io_chunk_frames to be written, no data will be * If there is less than disk_write_chunk_frames to be written, no data will be
* written at all unless @a force_flush is true. * written at all unless @a force_flush is true.
*/ */
int int
@ -1323,7 +1321,7 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
total = vector.len[0] + vector.len[1]; total = vector.len[0] + vector.len[1];
if (total == 0 || (total < disk_io_chunk_frames && !force_flush && was_recording)) { if (total == 0 || (total < disk_write_chunk_frames && !force_flush && was_recording)) {
goto out; goto out;
} }
@ -1338,11 +1336,11 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
let the caller know too. let the caller know too.
*/ */
if (total >= 2 * disk_io_chunk_frames || ((force_flush || !was_recording) && total > disk_io_chunk_frames)) { if (total >= 2 * disk_write_chunk_frames || ((force_flush || !was_recording) && total > disk_write_chunk_frames)) {
ret = 1; ret = 1;
} }
to_write = min (disk_io_chunk_frames, (framecnt_t) vector.len[0]); to_write = min (disk_write_chunk_frames, (framecnt_t) vector.len[0]);
// check the transition buffer when recording destructive // check the transition buffer when recording destructive
// important that we get this after the capture buf // important that we get this after the capture buf
@ -1402,14 +1400,14 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
(*chan)->capture_buf->increment_read_ptr (to_write); (*chan)->capture_buf->increment_read_ptr (to_write);
(*chan)->curr_capture_cnt += to_write; (*chan)->curr_capture_cnt += to_write;
if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_io_chunk_frames) && !destructive()) { if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_write_chunk_frames) && !destructive()) {
/* we wrote all of vector.len[0] but it wasn't an entire /* we wrote all of vector.len[0] but it wasn't an entire
disk_io_chunk_frames of data, so arrange for some part disk_write_chunk_frames of data, so arrange for some part
of vector.len[1] to be flushed to disk as well. of vector.len[1] to be flushed to disk as well.
*/ */
to_write = min ((framecnt_t)(disk_io_chunk_frames - to_write), (framecnt_t) vector.len[1]); to_write = min ((framecnt_t)(disk_write_chunk_frames - to_write), (framecnt_t) vector.len[1]);
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 additional write of %2\n", name(), to_write)); DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 additional write of %2\n", name(), to_write));

View File

@ -53,12 +53,8 @@ using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
/* XXX This goes uninitialized when there is no ~/.config/ardour3 directory. ARDOUR::framecnt_t Diskstream::disk_read_chunk_frames = default_disk_read_chunk_frames ();
* I can't figure out why, so this will do for now (just stole the ARDOUR::framecnt_t Diskstream::disk_write_chunk_frames = default_disk_write_chunk_frames ();
* default from configuration_vars.h). 0 is not a good value for
* allocating buffer sizes..
*/
ARDOUR::framecnt_t Diskstream::disk_io_chunk_frames = 1024 * 256 / sizeof (Sample);
PBD::Signal0<void> Diskstream::DiskOverrun; PBD::Signal0<void> Diskstream::DiskOverrun;
PBD::Signal0<void> Diskstream::DiskUnderrun; PBD::Signal0<void> Diskstream::DiskUnderrun;
@ -772,3 +768,21 @@ Diskstream::disengage_record_enable ()
{ {
g_atomic_int_set (&_record_enabled, 0); g_atomic_int_set (&_record_enabled, 0);
} }
framecnt_t
Diskstream::default_disk_read_chunk_frames()
{
#ifdef PLATFORM_WINDOWS
return (2 * 1048576) / sizeof (Sample);
#elif defined __APPLE__
return (4 * 1048576) / sizeof (Sample);
#else
return 65536;
#endif
}
framecnt_t
Diskstream::default_disk_write_chunk_frames ()
{
return 65536;
}

View File

@ -620,7 +620,7 @@ MidiDiskstream::overwrite_existing_buffers ()
having the old data or knowing what change caused the overwrite. */ having the old data or knowing what change caused the overwrite. */
midi_playlist()->resolve_note_trackers (*_playback_buf, overwrite_frame); midi_playlist()->resolve_note_trackers (*_playback_buf, overwrite_frame);
read (overwrite_frame, disk_io_chunk_frames, false); read (overwrite_frame, disk_read_chunk_frames, false);
file_frame = overwrite_frame; // it was adjusted by ::read() file_frame = overwrite_frame; // it was adjusted by ::read()
overwrite_queued = false; overwrite_queued = false;
_pending_overwrite = false; _pending_overwrite = false;
@ -810,12 +810,12 @@ MidiDiskstream::do_refill ()
/** Flush pending data to disk. /** Flush pending data to disk.
* *
* Important note: this function will write *AT MOST* disk_io_chunk_frames * Important note: this function will write *AT MOST* disk_write_chunk_frames
* of data to disk. it will never write more than that. If it writes that * of data to disk. it will never write more than that. If it writes that
* much and there is more than that waiting to be written, it will return 1, * much and there is more than that waiting to be written, it will return 1,
* otherwise 0 on success or -1 on failure. * otherwise 0 on success or -1 on failure.
* *
* If there is less than disk_io_chunk_frames to be written, no data will be * If there is less than disk_write_chunk_frames to be written, no data will be
* written at all unless @a force_flush is true. * written at all unless @a force_flush is true.
*/ */
int int
@ -832,7 +832,7 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
if (total == 0 || if (total == 0 ||
_capture_buf->read_space() == 0 || _capture_buf->read_space() == 0 ||
(!force_flush && (total < disk_io_chunk_frames) && was_recording)) { (!force_flush && (total < disk_write_chunk_frames) && was_recording)) {
goto out; goto out;
} }
@ -847,7 +847,7 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
let the caller know too. let the caller know too.
*/ */
if (total >= 2 * disk_io_chunk_frames || ((force_flush || !was_recording) && total > disk_io_chunk_frames)) { if (total >= 2 * disk_write_chunk_frames || ((force_flush || !was_recording) && total > disk_write_chunk_frames)) {
ret = 1; ret = 1;
} }
@ -855,10 +855,10 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
/* push out everything we have, right now */ /* push out everything we have, right now */
to_write = max_framecnt; to_write = max_framecnt;
} else { } else {
to_write = disk_io_chunk_frames; to_write = disk_write_chunk_frames;
} }
if (record_enabled() && ((total > disk_io_chunk_frames) || force_flush)) { if (record_enabled() && ((total > disk_write_chunk_frames) || force_flush)) {
Source::Lock lm(_write_source->mutex()); Source::Lock lm(_write_source->mutex());
if (_write_source->midi_write (lm, *_capture_buf, get_capture_start_frame (0), to_write) != to_write) { if (_write_source->midi_write (lm, *_capture_buf, get_capture_start_frame (0), to_write) != to_write) {
error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg; error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg;

View File

@ -235,7 +235,8 @@ RCConfiguration::set_state (const XMLNode& root, int version)
} }
} }
Diskstream::set_disk_io_chunk_frames (minimum_disk_io_bytes.get() / sizeof (Sample)); Diskstream::set_disk_read_chunk_frames (minimum_disk_read_bytes.get() / sizeof (Sample));
Diskstream::set_disk_write_chunk_frames (minimum_disk_write_bytes.get() / sizeof (Sample));
return 0; return 0;
} }
@ -270,3 +271,4 @@ RCConfiguration::map_parameters (boost::function<void (std::string)>& functor)
#undef CONFIG_VARIABLE #undef CONFIG_VARIABLE
#undef CONFIG_VARIABLE_SPECIAL #undef CONFIG_VARIABLE_SPECIAL
} }

View File

@ -30,8 +30,7 @@
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
/* see disk_io_chunk_frames */ const uint32_t SrcFileSource::blocksize = 65536U; /* somewhat arbitrary */
const uint32_t SrcFileSource::blocksize = 65536U;
SrcFileSource::SrcFileSource (Session& s, boost::shared_ptr<AudioFileSource> src, SrcQuality srcq) SrcFileSource::SrcFileSource (Session& s, boost::shared_ptr<AudioFileSource> src, SrcQuality srcq)
: Source(s, DataType::AUDIO, src->name(), Flag (src->flags() & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy))) : Source(s, DataType::AUDIO, src->name(), Flag (src->flags() & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))

View File

@ -2,7 +2,6 @@
<Ardour> <Ardour>
<MIDI-port tag="@MIDITAG@" device="ardour" type="@MIDITYPE@" mode="duplex"/> <MIDI-port tag="@MIDITAG@" device="ardour" type="@MIDITYPE@" mode="duplex"/>
<Config> <Config>
<Option name="minimum-disk-io-bytes" value="262144"/>
<Option name="track-buffer-seconds" value="5.000000"/> <Option name="track-buffer-seconds" value="5.000000"/>
<Option name="mute-affects-pre-fader" value="1"/> <Option name="mute-affects-pre-fader" value="1"/>
<Option name="mute-affects-post-fader" value="1"/> <Option name="mute-affects-post-fader" value="1"/>