The new class cIoThrottle is used to allow I/O intense threads to temporarily suspend their activities in case buffers run full

This commit is contained in:
Klaus Schmidinger 2012-09-22 11:52:33 +02:00
parent e898a28258
commit 72c03260d7
9 changed files with 116 additions and 8 deletions

View File

@ -2891,6 +2891,8 @@ Torsten Lang <info@torstenlang.de>
if the editing point merges two seamlessly fitting parts of the same stream
for reporting a sluggish response when manipulating editing marks while a cutting
thread is running
for suggesting to allow I/O intense threads to temporarily suspend their activities
in case buffers run full
Christian Ruppert <idl0r@gentoo.org>
for some improvements to the Makefiles

View File

@ -7235,7 +7235,7 @@ Video Disk Recorder Revision History
function in order to make use of this new feature. See, for instance, the function
cSkinClassicDisplayMenu::SetButtons() in skinclassic.c for details.
2012-09-19: Version 1.7.31
2012-09-22: Version 1.7.31
- If regenerating an index file fails and no data is written to the file, VDR now
reports this error and removes the empty index file.
@ -7251,3 +7251,8 @@ Video Disk Recorder Revision History
(suggested by Jens Vogel).
- Fixed a leftover frame counter in the LCARS skin's replay display after jumping to
an editing mark and resuming replay.
- The new class cIoThrottle is used to allow I/O intense threads to temporarily
suspend their activities in case buffers run full (suggested by Torsten Lang).
Currently the cutter thread is suspended if the TS or Recorder buffer use more
than 50% of their capacity. Plugin authors may want to participate in this
mechanism if they use intense background I/O.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: cutter.c 2.13 2012/06/10 14:33:36 kls Exp $
* $Id: cutter.c 2.14 2012/09/20 09:12:47 kls Exp $
*/
#include "cutter.h"
@ -88,12 +88,28 @@ void cCuttingThread::Action(void)
bool CheckForSeamlessStream = false;
bool LastMark = false;
bool cutIn = true;
bool suspensionLogged = false;
while (Running()) {
uint16_t FileNumber;
off_t FileOffset;
int Length;
bool Independent;
// Suspend cutting if we have severe throughput problems:
if (cIoThrottle::Engaged()) {
if (!suspensionLogged) {
dsyslog("suspending cutter thread");
suspensionLogged = true;
}
cCondWait::SleepMs(100);
continue;
}
else if (suspensionLogged) {
dsyslog("resuming cutter thread");
suspensionLogged = false;
}
// Make sure there is enough disk space:
AssertFreeDiskSpace(-1);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.c 2.67 2012/09/02 09:26:36 kls Exp $
* $Id: device.c 2.68 2012/09/20 09:32:26 kls Exp $
*/
#include "device.h"
@ -1721,6 +1721,7 @@ cTSBuffer::cTSBuffer(int File, int Size, int CardIndex)
delivered = false;
ringBuffer = new cRingBufferLinear(Size, TS_SIZE, true, "TS");
ringBuffer->SetTimeouts(100, 100);
ringBuffer->SetIoThrottle();
Start();
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recorder.c 2.15 2011/09/04 09:26:44 kls Exp $
* $Id: recorder.c 2.16 2012/09/22 11:52:33 kls Exp $
*/
#include "recorder.h"
@ -33,6 +33,7 @@ cRecorder::cRecorder(const char *FileName, const cChannel *Channel, int Priority
ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE, true, "Recorder");
ringBuffer->SetTimeouts(0, 100);
ringBuffer->SetIoThrottle();
int Pid = Channel->Vpid();
int Type = Channel->Vtype();

View File

@ -7,7 +7,7 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org).
*
* $Id: ringbuffer.c 2.4 2012/09/17 08:23:43 kls Exp $
* $Id: ringbuffer.c 2.5 2012/09/22 11:26:49 kls Exp $
*/
#include "ringbuffer.h"
@ -20,6 +20,8 @@
#define OVERFLOWREPORTDELTA 5 // seconds between reports
#define PERCENTAGEDELTA 10
#define PERCENTAGETHRESHOLD 70
#define IOTHROTTLELOW 20
#define IOTHROTTLEHIGH 50
cRingBuffer::cRingBuffer(int Size, bool Statistics)
{
@ -31,10 +33,12 @@ cRingBuffer::cRingBuffer(int Size, bool Statistics)
putTimeout = getTimeout = 0;
lastOverflowReport = 0;
overflowCount = overflowBytes = 0;
ioThrottle = NULL;
}
cRingBuffer::~cRingBuffer()
{
delete ioThrottle;
if (statistics)
dsyslog("buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
}
@ -50,6 +54,12 @@ void cRingBuffer::UpdatePercentage(int Fill)
lastPercent = percent;
}
}
if (ioThrottle) {
if (percent >= IOTHROTTLEHIGH)
ioThrottle->Activate();
else if (percent < IOTHROTTLELOW)
ioThrottle->Release();
}
}
void cRingBuffer::WaitForPut(void)
@ -82,6 +92,12 @@ void cRingBuffer::SetTimeouts(int PutTimeout, int GetTimeout)
getTimeout = GetTimeout;
}
void cRingBuffer::SetIoThrottle(void)
{
if (!ioThrottle)
ioThrottle = new cIoThrottle;
}
void cRingBuffer::ReportOverflow(int Bytes)
{
overflowCount++;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: ringbuffer.h 2.3 2011/12/04 13:38:17 kls Exp $
* $Id: ringbuffer.h 2.4 2012/09/20 09:29:32 kls Exp $
*/
#ifndef __RINGBUFFER_H
@ -22,6 +22,7 @@ private:
time_t lastOverflowReport;
int overflowCount;
int overflowBytes;
cIoThrottle *ioThrottle;
protected:
tThreadId getThreadTid;
int maxFill;//XXX
@ -40,6 +41,7 @@ public:
cRingBuffer(int Size, bool Statistics = false);
virtual ~cRingBuffer();
void SetTimeouts(int PutTimeout, int GetTimeout);
void SetIoThrottle(void);
void ReportOverflow(int Bytes);
};

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.c 2.4 2012/05/08 11:15:57 kls Exp $
* $Id: thread.c 2.5 2012/09/20 09:05:50 kls Exp $
*/
#include "thread.h"
@ -398,6 +398,48 @@ bool cThreadLock::Lock(cThread *Thread)
return false;
}
// --- cIoThrottle -----------------------------------------------------------
cMutex cIoThrottle::mutex;
int cIoThrottle::count = 0;
cIoThrottle::cIoThrottle(void)
{
active = false;
}
cIoThrottle::~cIoThrottle()
{
Release();
}
void cIoThrottle::Activate(void)
{
if (!active) {
mutex.Lock();
count++;
active = true;
dsyslog("i/o throttle activated, count = %d (tid=%d)", count, cThread::ThreadId());
mutex.Unlock();
}
}
void cIoThrottle::Release(void)
{
if (active) {
mutex.Lock();
count--;
active = false;
dsyslog("i/o throttle released, count = %d (tid=%d)", count, cThread::ThreadId());
mutex.Unlock();
}
}
bool cIoThrottle::Engaged(void)
{
return count > 0;
}
// --- cPipe -----------------------------------------------------------------
// cPipe::Open() and cPipe::Close() are based on code originally received from

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.h 2.1 2009/04/13 13:50:39 kls Exp $
* $Id: thread.h 2.2 2012/09/20 08:46:27 kls Exp $
*/
#ifndef __THREAD_H
@ -157,6 +157,29 @@ public:
#define LOCK_THREAD cThreadLock ThreadLock(this)
class cIoThrottle {
private:
static cMutex mutex;
static int count;
bool active;
public:
cIoThrottle(void);
~cIoThrottle();
void Activate(void);
///< Activates the global I/O throttling mechanism.
///< This function may be called any number of times, but only
///< the first call after an inactive state will have an effect.
void Release(void);
///< Releases the global I/O throttling mechanism.
///< This function may be called any number of times, but only
///< the first call after an active state will have an effect.
bool Active(void) { return active; }
///< Returns true if this I/O throttling object is currently active.
static bool Engaged(void);
///< Returns true if any I/O throttling object is currently active.
};
// cPipe implements a pipe that closes all unnecessary file descriptors in
// the child process.