13
0

Put Windows timer functions into PBD namespace in preparation for moving them to libpbd

Add functions for get/set the Multimedia timer resolution, although we are
really only interested in the minimum, this will facilitate testing

Put timer utility functions inside nested namespaces as they are platform
specific
This commit is contained in:
Tim Mayberry 2015-09-12 14:58:35 +10:00
parent 4330db1aa7
commit 4ffe8ffc0f
6 changed files with 167 additions and 64 deletions

View File

@ -680,7 +680,7 @@ PortAudioBackend::samples_since_cycle_start ()
return 0;
}
return m_cycle_timer.samples_since_cycle_start (utils::get_microseconds());
return m_cycle_timer.samples_since_cycle_start (PBD::get_microseconds());
}
int
@ -1525,7 +1525,7 @@ PortAudioBackend::blocking_process_main(const float* interleaved_input_data,
int64_t min_elapsed_us = 1000000;
int64_t max_elapsed_us = 0;
m_dsp_calc.set_start_timestamp_us (utils::get_microseconds());
m_dsp_calc.set_start_timestamp_us (PBD::get_microseconds());
i = 0;
/* Copy input audio data into input port buffers */
@ -1551,7 +1551,7 @@ PortAudioBackend::blocking_process_main(const float* interleaved_input_data,
}
m_last_cycle_start = m_cycle_timer.get_start();
m_cycle_timer.reset_start(utils::get_microseconds());
m_cycle_timer.reset_start(PBD::get_microseconds());
m_cycle_count++;
uint64_t cycle_diff_us = (m_cycle_timer.get_start() - m_last_cycle_start);
@ -1599,7 +1599,7 @@ PortAudioBackend::blocking_process_main(const float* interleaved_input_data,
_processed_samples += _samples_per_period;
/* calculate DSP load */
m_dsp_calc.set_stop_timestamp_us (utils::get_microseconds());
m_dsp_calc.set_stop_timestamp_us (PBD::get_microseconds());
_dsp_load = m_dsp_calc.get_dsp_load();
DEBUG_TIMING(string_compose("DSP Load: %1\n", _dsp_load));

View File

@ -27,6 +27,90 @@
namespace {
UINT&
old_timer_resolution ()
{
static UINT timer_res_ms = 0;
return timer_res_ms;
}
} // anon namespace
namespace PBD {
namespace MMTIMERS {
bool
set_min_resolution ()
{
TIMECAPS caps;
if (timeGetDevCaps (&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
DEBUG_TIMING ("Could not get timer device capabilities.\n");
return false;
}
return set_resolution(caps.wPeriodMin);
}
bool
set_resolution (uint32_t timer_resolution_ms)
{
TIMECAPS caps;
if (timeGetDevCaps (&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
DEBUG_TIMING ("Could not get timer device capabilities.\n");
return false;
}
UINT old_timer_res = caps.wPeriodMin;
if (timeBeginPeriod(timer_resolution_ms) != TIMERR_NOERROR) {
DEBUG_TIMING(
string_compose("Could not set minimum timer resolution to %1(ms)\n",
timer_resolution_ms));
return false;
}
old_timer_resolution () = old_timer_res;
DEBUG_TIMING (string_compose ("Multimedia timer resolution set to %1(ms)\n",
caps.wPeriodMin));
return true;
}
bool
get_resolution (uint32_t& timer_resolution_ms)
{
TIMECAPS caps;
if (timeGetDevCaps(&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
DEBUG_TIMING ("Could not get timer device capabilities.\n");
return false;
}
timer_resolution_ms = caps.wPeriodMin;
return true;
}
bool
reset_resolution ()
{
if (old_timer_resolution ()) {
if (timeEndPeriod (old_timer_resolution ()) != TIMERR_NOERROR) {
DEBUG_TIMING ("Could not reset timer resolution.\n");
return false;
}
}
DEBUG_TIMING (string_compose ("Multimedia timer resolution set to %1(ms)\n",
old_timer_resolution ()));
return true;
}
} // namespace MMTIMERS
namespace {
bool&
qpc_frequency_success ()
{
@ -48,76 +132,52 @@ qpc_frequency ()
return freq;
}
UINT&
old_timer_resolution ()
LARGE_INTEGER
qpc_frequency_cached ()
{
static UINT timer_res_ms = 0;
return timer_res_ms;
static LARGE_INTEGER frequency = qpc_frequency ();
return frequency;
}
} // anon namespace
namespace utils {
namespace QPC {
bool
set_min_timer_resolution ()
get_timer_valid ()
{
TIMECAPS caps;
if (timeGetDevCaps (&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
DEBUG_TIMING ("Could not get timer device capabilities.\n");
return false;
} else {
old_timer_resolution () = caps.wPeriodMin;
if (timeBeginPeriod (caps.wPeriodMin) != TIMERR_NOERROR) {
DEBUG_TIMING (string_compose (
"Could not set minimum timer resolution to %1(ms)\n", caps.wPeriodMin));
return false;
}
}
DEBUG_TIMING (string_compose ("Multimedia timer resolution set to %1(ms)\n",
caps.wPeriodMin));
return true;
}
bool
reset_timer_resolution ()
{
if (old_timer_resolution ()) {
if (timeEndPeriod (old_timer_resolution ()) != TIMERR_NOERROR) {
DEBUG_TIMING ("Could not reset timer resolution.\n");
return false;
}
}
DEBUG_TIMING (string_compose ("Multimedia timer resolution set to %1(ms)\n",
old_timer_resolution ()));
return true;
// setup caching the timer frequency
qpc_frequency_cached ();
return qpc_frequency_success ();
}
int64_t
get_microseconds ()
{
static LARGE_INTEGER frequency = qpc_frequency ();
LARGE_INTEGER current_val;
if (qpc_frequency_success()) {
// MS docs say this will always succeed for systems >= XP but it may
// not return a monotonic value with non-invariant TSC's etc
if (QueryPerformanceCounter(&current_val) != 0) {
return (int64_t)(((double)current_val.QuadPart) /
((double)frequency.QuadPart) * 1000000.0);
} else {
DEBUG_TIMING ("Could not get QPC timer\n");
((double)qpc_frequency_cached().QuadPart) * 1000000.0);
}
return -1;
}
DEBUG_TIMING ("Could not get QPC timer\n");
return -1;
}
} // namespace QPC
int64_t
get_microseconds ()
{
if (qpc_frequency_success()) {
return QPC::get_microseconds ();
}
// For XP systems that don't support a high-res performance counter
return g_get_monotonic_time ();
}
} // namespace utils
} // namespace PBD

View File

@ -21,22 +21,66 @@
#include <stdint.h>
namespace utils {
namespace PBD {
bool set_min_timer_resolution ();
namespace MMTIMERS {
bool reset_timer_resolution ();
/**
* Set the minimum Multimedia Timer resolution as supported by the system
* @return true if min timer resolution was successfully set
*
* Call reset_resolution to restore old timer resolution
*/
bool set_min_resolution ();
/** The highest resolution timer source provided by the system. On Vista and
/**
* Get current Multimedia Timer resolution
* @return true if getting the timer value was successful
*/
bool get_resolution(uint32_t& timer_resolution_us);
/**
* Set current Multimedia Timer resolution
* @return true if setting the timer value was successful
*/
bool set_resolution(uint32_t timer_resolution_us);
/**
* Reset the Multimedia Timer back to what it was originally before
* setting the timer resolution.
*/
bool reset_resolution ();
} // namespace MMTIMERS
namespace QPC {
/**
* @return true if QueryPerformanceCounter is usable as a timer source
*/
bool get_timer_valid ();
/**
* @return the value of the performance counter converted to microseconds
*
* If get_counter_valid returns true then get_microseconds will always
* return a positive value. If QPC is not supported(OS < XP) then -1 is
* returned but the MS docs say that this won't occur for systems >= XP.
*/
int64_t get_microseconds ();
} // namespace QPC
/**
* The highest resolution timer source provided by the system. On Vista and
* above this is the value returned by QueryPerformanceCounter(QPC). On XP,
* this will QPC if supported or otherwise g_get_monotonic_time will be used.
*
* @return A timer value in microseconds or -1 in the event that the reading
* the timer source fails, but the MS docs say that this won't occur for
* systems >= XP
* the timer source fails.
*/
int64_t get_microseconds ();
}
} // namespace PBD
#endif // WIN_UTILS_H

View File

@ -346,7 +346,7 @@ WinMMEMidiInputDevice::enqueue_midi_msg (const uint8_t* midi_data,
}
// don't use winmme timestamps for now
uint64_t ts = utils::get_microseconds ();
uint64_t ts = PBD::get_microseconds ();
DEBUG_TIMING (string_compose (
"Enqueing MIDI data device: %1 with timestamp: %2 and size %3\n",

View File

@ -31,7 +31,6 @@
#include "i18n.h"
using namespace ARDOUR;
using namespace utils;
WinMMEMidiIO::WinMMEMidiIO()
: m_active (false)
@ -136,7 +135,7 @@ WinMMEMidiIO::start ()
m_run = true;
DEBUG_MIDI ("Starting MIDI driver\n");
set_min_timer_resolution();
PBD::MMTIMERS::set_min_resolution();
discover();
start_devices ();
}
@ -156,7 +155,7 @@ WinMMEMidiIO::stop ()
cleanup ();
pthread_mutex_unlock (&m_device_lock);
reset_timer_resolution();
PBD::MMTIMERS::reset_resolution();
}
void

View File

@ -390,7 +390,7 @@ WinMMEMidiOutputDevice::midi_output_thread ()
DEBUG_MIDI ("WinMMEMidiOut: MIDI buffer underrun, shouldn't occur\n");
continue;
}
uint64_t current_time = utils::get_microseconds ();
uint64_t current_time = PBD::get_microseconds ();
DEBUG_TIMING (string_compose (
"WinMMEMidiOut: h.time = %1, current_time = %2\n", h.time, current_time));
@ -408,7 +408,7 @@ WinMMEMidiOutputDevice::midi_output_thread ()
break;
}
uint64_t wakeup_time = utils::get_microseconds ();
uint64_t wakeup_time = PBD::get_microseconds ();
DEBUG_TIMING (string_compose ("WinMMEMidiOut: woke up at %1(ms)\n",
((double)wakeup_time) / 1000.0));
if (wakeup_time > h.time) {