Commit 542ac90d authored by sletz's avatar sletz
Browse files

Cleanup timing + cpuload code


git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2526 0c269be4-1314-0410-8aa9-9f06e86f4224
parent 275dbc30
......@@ -185,12 +185,12 @@ int JackAudioDriver::Process()
int JackAudioDriver::ProcessNull()
{
JackDriver::CycleTakeTime();
JackDriver::CycleTakeBeginTime();
int wait_time_usec = (int((float(fEngineControl->fBufferSize) / (float(fEngineControl->fSampleRate))) * 1000000.0f));
JackSleep(wait_time_usec);
if (!fEngine->Process(fLastWaitUst)) // fLastWaitUst is set in the "low level" layer
if (!fEngine->Process(fBeginDateUst, fEndDateUst)) // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle
jack_error("JackAudioDriver::ProcessNull Process error");
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable);
if (ProcessSlaves() < 0)
......@@ -219,7 +219,8 @@ int JackAudioDriver::ProcessAsync()
}
if (fIsMaster) {
if (!fEngine->Process(fLastWaitUst)) // fLastWaitUst is set in the "low level" layer
// fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle
if (!fEngine->Process(fBeginDateUst, fEndDateUst))
jack_error("JackAudioDriver::ProcessAsync Process error");
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable);
if (ProcessSlaves() < 0)
......@@ -227,6 +228,9 @@ int JackAudioDriver::ProcessAsync()
} else {
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable);
}
// Keep end cycle time
CycleTakeEndTime();
return 0;
}
......@@ -245,7 +249,8 @@ int JackAudioDriver::ProcessSync()
if (fIsMaster) {
if (fEngine->Process(fLastWaitUst)) { // fLastWaitUst is set in the "low level" layer
// fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle
if (fEngine->Process(fBeginDateUst, fEndDateUst)) {
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable);
if (ProcessSlaves() < 0)
jack_error("JackAudioDriver::ProcessSync ProcessSlaves error, engine may now behave abnormally!!");
......@@ -264,6 +269,9 @@ int JackAudioDriver::ProcessSync()
} else {
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable);
}
// Keep end cycle time
CycleTakeEndTime();
return 0;
}
......
......@@ -51,7 +51,7 @@ JackDriver::JackDriver(const char* name, const char* alias, JackLockedEngine* en
strcpy(fAliasName, alias);
fEngine = engine;
fGraphManager = NULL;
fLastWaitUst = 0;
fBeginDateUst = 0;
fDelayedUsecs = 0.f;
fIsMaster = true;
}
......@@ -62,7 +62,7 @@ JackDriver::JackDriver()
fClientControl = NULL;
fEngine = NULL;
fGraphManager = NULL;
fLastWaitUst = 0;
fBeginDateUst = 0;
fIsMaster = true;
}
......@@ -181,12 +181,18 @@ bool JackDriver::IsRealTime() const
void JackDriver::CycleIncTime()
{
fEngineControl->CycleIncTime(fLastWaitUst);
fEngineControl->CycleIncTime(fBeginDateUst);
}
void JackDriver::CycleTakeTime()
void JackDriver::CycleTakeBeginTime()
{
fBeginDateUst = GetMicroSeconds(); // Take callback date here
fEngineControl->CycleIncTime(fBeginDateUst);
}
void JackDriver::CycleTakeEndTime()
{
fLastWaitUst = GetMicroSeconds(); // Take callback date here
fEngineControl->CycleIncTime(fLastWaitUst);
fEndDateUst = GetMicroSeconds(); // Take end date here
}
JackClientControl* JackDriver::GetClientControl() const
......@@ -194,9 +200,9 @@ JackClientControl* JackDriver::GetClientControl() const
return fClientControl;
}
void JackDriver::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs)
void JackDriver::NotifyXRun(jack_time_t cur_cycle_begin, float delayed_usecs)
{
fEngine->NotifyXRun(callback_usecs, delayed_usecs);
fEngine->NotifyXRun(cur_cycle_begin, delayed_usecs);
}
void JackDriverClient::SetMaster(bool onoff)
......
......@@ -130,7 +130,8 @@ class EXPORT JackDriver : public JackDriverClient
char fAliasName[JACK_CLIENT_NAME_SIZE + 1];
jack_nframes_t fCaptureLatency;
jack_nframes_t fPlaybackLatency;
jack_time_t fLastWaitUst;
jack_time_t fBeginDateUst;
jack_time_t fEndDateUst;
float fDelayedUsecs;
JackLockedEngine* fEngine;
JackGraphManager* fGraphManager;
......@@ -141,7 +142,8 @@ class EXPORT JackDriver : public JackDriverClient
JackClientControl* GetClientControl() const;
void CycleIncTime();
void CycleTakeTime();
void CycleTakeBeginTime();
void CycleTakeEndTime();
public:
......
......@@ -65,9 +65,9 @@ int JackDummyDriver::Open(jack_nframes_t nframes,
int JackDummyDriver::Process()
{
JackDriver::CycleTakeTime();
JackDriver::CycleTakeBeginTime();
JackAudioDriver::Process();
JackSleep(std::max(0L, long(fWaitTime - (GetMicroSeconds() - fLastWaitUst))));
JackSleep(std::max(0L, long(fWaitTime - (GetMicroSeconds() - fBeginDateUst))));
return 0;
}
......
......@@ -133,41 +133,41 @@ void JackEngine::ReleaseRefnum(int ref)
// Graph management
//------------------
void JackEngine::ProcessNext(jack_time_t callback_usecs)
void JackEngine::ProcessNext(jack_time_t cur_cycle_begin)
{
fLastSwitchUsecs = callback_usecs;
fLastSwitchUsecs = cur_cycle_begin;
if (fGraphManager->RunNextGraph()) // True if the graph actually switched to a new state
fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0);
fSignal.SignalAll(); // Signal for threads waiting for next cycle
fSignal.SignalAll(); // Signal for threads waiting for next cycle
}
void JackEngine::ProcessCurrent(jack_time_t callback_usecs)
void JackEngine::ProcessCurrent(jack_time_t cur_cycle_begin)
{
if (callback_usecs < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failing cycle
CheckXRun(callback_usecs);
if (cur_cycle_begin < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failing cycle
CheckXRun(cur_cycle_begin);
fGraphManager->RunCurrentGraph();
}
bool JackEngine::Process(jack_time_t callback_usecs)
bool JackEngine::Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end)
{
bool res = true;
// Cycle begin
fEngineControl->CycleBegin(fClientTable, fGraphManager, callback_usecs);
fEngineControl->CycleBegin(fClientTable, fGraphManager, cur_cycle_begin, prev_cycle_end);
// Graph
if (fGraphManager->IsFinishedGraph()) {
ProcessNext(callback_usecs);
ProcessNext(cur_cycle_begin);
res = true;
} else {
jack_log("Process: graph not finished!");
if (callback_usecs > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
jack_log("Process: switch to next state delta = %ld", long(callback_usecs - fLastSwitchUsecs));
ProcessNext(callback_usecs);
if (cur_cycle_begin > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
jack_log("Process: switch to next state delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs));
ProcessNext(cur_cycle_begin);
res = true;
} else {
jack_log("Process: waiting to switch delta = %ld", long(callback_usecs - fLastSwitchUsecs));
ProcessCurrent(callback_usecs);
jack_log("Process: waiting to switch delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs));
ProcessCurrent(cur_cycle_begin);
res = false;
}
}
......
......@@ -108,7 +108,7 @@ class EXPORT JackEngine
int PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst);
// Graph
bool Process(jack_time_t callback_usecs);
bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end);
// Notifications
void NotifyXRun(jack_time_t callback_usecs, float delayed_usecs);
......
......@@ -37,14 +37,17 @@ void JackEngineControl::CycleIncTime(jack_time_t callback_usecs)
fFrameTimer.IncFrameTime(fBufferSize, callback_usecs, fPeriodUsecs);
}
void JackEngineControl::CycleBegin(JackClientInterface** table, JackGraphManager* manager, jack_time_t callback_usecs)
void JackEngineControl::CycleBegin(JackClientInterface** table,
JackGraphManager* manager,
jack_time_t cur_cycle_begin,
jack_time_t prev_cycle_end)
{
// Transport
fTransport.CycleBegin(fSampleRate, callback_usecs);
fTransport.CycleBegin(fSampleRate, cur_cycle_begin);
// Timing
GetTimeMeasure(table, manager, callback_usecs);
CalcCPULoad(table, manager);
//GetTimeMeasure(table, manager, callback_usecs);
CalcCPULoad(table, manager, cur_cycle_begin, prev_cycle_end);
}
void JackEngineControl::CycleEnd(JackClientInterface** table)
......@@ -57,9 +60,9 @@ void JackEngineControl::InitFrameTime()
fFrameTimer.InitFrameTime();
}
void JackEngineControl::ResetFrameTime(jack_time_t callback_usecs)
void JackEngineControl::ResetFrameTime(jack_time_t cur_cycle_begin)
{
fFrameTimer.ResetFrameTime(fSampleRate, callback_usecs, fPeriodUsecs);
fFrameTimer.ResetFrameTime(fSampleRate, cur_cycle_begin, fPeriodUsecs);
}
void JackEngineControl::ReadFrameTime(JackTimer* timer)
......@@ -77,38 +80,41 @@ inline jack_time_t MAX(jack_time_t a, jack_time_t b)
#define MAX(a,b) std::max((a),(b))
#endif
void JackEngineControl::CalcCPULoad(JackClientInterface** table, JackGraphManager* manager)
void JackEngineControl::CalcCPULoad(JackClientInterface** table,
JackGraphManager* manager,
jack_time_t cur_cycle_begin,
jack_time_t prev_cycle_end)
{
jack_time_t lastCycleEnd = fLastProcessTime;
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
JackClientInterface* client = table[i];
JackClientTiming* timing = manager->GetClientTiming(i);
if (client && client->GetClientControl()->fActive && timing->fStatus == Finished) {
lastCycleEnd = MAX(lastCycleEnd, timing->fFinishedAt);
fPrevCycleTime = fCurCycleTime;
fCurCycleTime = cur_cycle_begin;
jack_time_t last_cycle_end = prev_cycle_end;
// In Asynchronous mode, last cycle end is the max of client end dates
if (!fSyncMode) {
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
JackClientInterface* client = table[i];
JackClientTiming* timing = manager->GetClientTiming(i);
if (client && client->GetClientControl()->fActive && timing->fStatus == Finished)
last_cycle_end = MAX(last_cycle_end, timing->fFinishedAt);
}
}
/* store the execution time for later averaging */
fRollingClientUsecs[fRollingClientUsecsIndex++] = lastCycleEnd - fLastTime;
if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT) {
// Store the execution time for later averaging
fRollingClientUsecs[fRollingClientUsecsIndex++] = last_cycle_end - fPrevCycleTime;
if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT)
fRollingClientUsecsIndex = 0;
}
/* every so often, recompute the current maximum use over the
last JACK_ENGINE_ROLLING_COUNT client iterations.
*/
// Every so often, recompute the current maximum use over the
// last JACK_ENGINE_ROLLING_COUNT client iterations.
if (++fRollingClientUsecsCnt % fRollingInterval == 0) {
jack_time_t maxUsecs = 0;
for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++) {
maxUsecs = MAX(fRollingClientUsecs[i], maxUsecs);
}
fMaxUsecs = MAX(fMaxUsecs, maxUsecs);
fSpareUsecs = jack_time_t((maxUsecs < fPeriodUsecs) ? fPeriodUsecs - maxUsecs : 0);
jack_time_t max_usecs = 0;
for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++)
max_usecs = MAX(fRollingClientUsecs[i], max_usecs);
fMaxUsecs = MAX(fMaxUsecs, max_usecs);
fSpareUsecs = jack_time_t((max_usecs < fPeriodUsecs) ? fPeriodUsecs - max_usecs : 0);
fCPULoad = ((1.f - (float(fSpareUsecs) / float(fPeriodUsecs))) * 50.f + (fCPULoad * 0.5f));
}
}
......@@ -119,48 +125,7 @@ void JackEngineControl::ResetRollingUsecs()
fRollingClientUsecsIndex = 0;
fRollingClientUsecsCnt = 0;
fSpareUsecs = 0;
fRollingInterval = (int)floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.f) / fPeriodUsecs);
}
void JackEngineControl::GetTimeMeasure(JackClientInterface** table, JackGraphManager* manager, jack_time_t callback_usecs)
{
int pos = (++fAudioCycle) % TIME_POINTS;
fLastTime = fCurTime;
fCurTime = callback_usecs;
fLastProcessTime = fProcessTime;
fProcessTime = GetMicroSeconds();
if (fLastTime > 0) {
fMeasure[pos].fEngineTime = fLastTime;
fMeasure[pos].fAudioCycle = fAudioCycle;
for (int i = 0; i < CLIENT_NUM; i++) {
JackClientInterface* client = table[i];
JackClientTiming* timing = manager->GetClientTiming(i);
if (client && client->GetClientControl()->fActive) {
fMeasure[pos].fClientTable[i].fRefNum = i;
fMeasure[pos].fClientTable[i].fSignaledAt = timing->fSignaledAt;
fMeasure[pos].fClientTable[i].fAwakeAt = timing->fAwakeAt;
fMeasure[pos].fClientTable[i].fFinishedAt = timing->fFinishedAt;
fMeasure[pos].fClientTable[i].fStatus = timing->fStatus;
}
}
}
}
void JackEngineControl::ClearTimeMeasures()
{
for (int i = 0; i < TIME_POINTS; i++) {
for (int j = 0; j < CLIENT_NUM; j++) {
fMeasure[i].fClientTable[j].fRefNum = 0;
fMeasure[i].fClientTable[j].fSignaledAt = 0;
fMeasure[i].fClientTable[j].fAwakeAt = 0;
fMeasure[i].fClientTable[j].fFinishedAt = 0;
}
}
fLastTime = fCurTime = 0;
fRollingInterval = int(floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.f) / fPeriodUsecs));
}
void JackEngineControl::NotifyXRun(float delayed_usecs)
......
......@@ -33,34 +33,9 @@ namespace Jack
class JackClientInterface;
class JackGraphManager;
#define TIME_POINTS 1000
#define JACK_ENGINE_ROLLING_COUNT 32
#define JACK_ENGINE_ROLLING_INTERVAL 1024
/*!
\brief Timing stucture for a client.
*/
struct JackTimingMeasureClient
{
int fRefNum;
jack_time_t fSignaledAt;
jack_time_t fAwakeAt;
jack_time_t fFinishedAt;
jack_client_state_t fStatus;
};
/*!
\brief Timing stucture for a table of clients.
*/
struct JackTimingMeasure
{
unsigned int fAudioCycle;
jack_time_t fEngineTime;
JackTimingMeasureClient fClientTable[CLIENT_NUM];
};
/*!
\brief Engine control in shared memory.
*/
......@@ -83,15 +58,11 @@ struct EXPORT JackEngineControl : public JackShmMem
JackTransportEngine fTransport;
bool fVerbose;
// Timing
JackTimingMeasure fMeasure[TIME_POINTS];
jack_time_t fLastTime;
jack_time_t fCurTime;
jack_time_t fProcessTime;
jack_time_t fLastProcessTime;
// CPU Load
jack_time_t fPrevCycleTime;
jack_time_t fCurCycleTime;
jack_time_t fSpareUsecs;
jack_time_t fMaxUsecs;
unsigned int fAudioCycle;
jack_time_t fRollingClientUsecs[JACK_ENGINE_ROLLING_COUNT];
int fRollingClientUsecsCnt;
int fRollingClientUsecsIndex;
......@@ -118,14 +89,10 @@ struct EXPORT JackEngineControl : public JackShmMem
fRealTime = rt;
fPriority = priority;
fVerbose = verbose;
fLastTime = 0;
fCurTime = 0;
fProcessTime = 0;
fLastProcessTime = 0;
fPrevCycleTime = 0;
fCurCycleTime = 0;
fSpareUsecs = 0;
fMaxUsecs = 0;
fAudioCycle = 0;
ClearTimeMeasures();
ResetRollingUsecs();
snprintf(fServerName, sizeof(fServerName), server_name);
fPeriod = 0;
......@@ -139,7 +106,7 @@ struct EXPORT JackEngineControl : public JackShmMem
// Cycle
void CycleIncTime(jack_time_t callback_usecs);
void CycleBegin(JackClientInterface** table, JackGraphManager* manager, jack_time_t callback_usecs);
void CycleBegin(JackClientInterface** table, JackGraphManager* manager, jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end);
void CycleEnd(JackClientInterface** table);
// Timer
......@@ -152,9 +119,7 @@ struct EXPORT JackEngineControl : public JackShmMem
void ResetXRun();
// Private
void CalcCPULoad(JackClientInterface** table, JackGraphManager* manager);
void GetTimeMeasure(JackClientInterface** table, JackGraphManager* manager, jack_time_t callback_usecs);
void ClearTimeMeasures();
void CalcCPULoad(JackClientInterface** table, JackGraphManager* manager, jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end);
void ResetRollingUsecs();
};
......
/*
Copyright (C) 2003 Paul Davis
Copyright (C) 2004-2008 Grame
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include "JackEngineTiming.h"
#include "JackGraphManager.h"
#include "JackClientControl.h"
#include "JackClientInterface.h"
#include "JackTime.h"
namespace Jack
{
void JackEngineTiming::GetTimeMeasure(JackClientInterface** table,
JackGraphManager* manager,
jack_time_t cur_cycle_begin,
jack_time_t prev_cycle_end)
{
int pos = (++fAudioCycle) % TIME_POINTS;
fPrevCycleTime = fCurCycleTime;
fCurCycleTime = cur_cycle_begin;
if (fPrevCycleTime > 0) {
fMeasure[pos].fEngineTime = fPrevCycleTime;
fMeasure[pos].fAudioCycle = fAudioCycle;
for (int i = 0; i < CLIENT_NUM; i++) {
JackClientInterface* client = table[i];
JackClientTiming* timing = manager->GetClientTiming(i);
if (client && client->GetClientControl()->fActive) {
fMeasure[pos].fClientTable[i].fRefNum = i;
fMeasure[pos].fClientTable[i].fSignaledAt = timing->fSignaledAt;
fMeasure[pos].fClientTable[i].fAwakeAt = timing->fAwakeAt;
fMeasure[pos].fClientTable[i].fFinishedAt = timing->fFinishedAt;
fMeasure[pos].fClientTable[i].fStatus = timing->fStatus;
}
}
}
}
void JackEngineTiming::ClearTimeMeasures()
{
for (int i = 0; i < TIME_POINTS; i++) {
for (int j = 0; j < CLIENT_NUM; j++) {
fMeasure[i].fClientTable[j].fRefNum = 0;
fMeasure[i].fClientTable[j].fSignaledAt = 0;
fMeasure[i].fClientTable[j].fAwakeAt = 0;
fMeasure[i].fClientTable[j].fFinishedAt = 0;
}
}
fPrevCycleTime = fCurCycleTime = 0;
}
} // end of namespace
/*
Copyright (C) 2003 Paul Davis
Copyright (C) 2004-2008 Grame
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __JackEngineTiming__
#define __JackEngineTiming__
#include "types.h"
#include "JackTypes.h"
#include "JackConstants.h"
namespace Jack
{
#define TIME_POINTS 1000
/*!
\brief Timing stucture for a client.
*/
struct JackTimingMeasureClient
{
int fRefNum;
jack_time_t fSignaledAt;
jack_time_t fAwakeAt;
jack_time_t fFinishedAt;
jack_client_state_t fStatus;
};
/*!
\brief Timing stucture for a table of clients.
*/
struct JackTimingMeasure
{
unsigned int fAudioCycle;
jack_time_t fEngineTime;
JackTimingMeasureClient fClientTable[CLIENT_NUM];
};
/*!
\brief Client timing.
*/
class JackClientInterface;
class JackGraphManager;
class JackEngineTiming
{
private:
JackTimingMeasure fMeasure[TIME_POINTS];
unsigned int fAudioCycle;
jack_time_t fPrevCycleTime;
jack_time_t fCurCycleTime;
public:
JackEngineTiming():fAudioCycle(0),fPrevCycleTime(0),fCurCycleTime(0)
{}
~JackEngineTiming()
{}
void GetTimeMeasure(JackClientInterface** table, JackGraphManager* manager, jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end);
void ClearTimeMeasures();
};
} // end of namespace
#endif
......@@ -37,8 +37,8 @@ int JackFreewheelDriver::Process()
{
if (fIsMaster) {
jack_log("JackFreewheelDriver::Process master %lld", fEngineControl->fTimeOutUsecs);
JackDriver::CycleTakeTime();
fEngine->Process(fLastWaitUst);