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 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 for reporting a sluggish response when manipulating editing marks while a cutting
thread is running 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> Christian Ruppert <idl0r@gentoo.org>
for some improvements to the Makefiles 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 function in order to make use of this new feature. See, for instance, the function
cSkinClassicDisplayMenu::SetButtons() in skinclassic.c for details. 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 - 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. reports this error and removes the empty index file.
@ -7251,3 +7251,8 @@ Video Disk Recorder Revision History
(suggested by Jens Vogel). (suggested by Jens Vogel).
- Fixed a leftover frame counter in the LCARS skin's replay display after jumping to - Fixed a leftover frame counter in the LCARS skin's replay display after jumping to
an editing mark and resuming replay. 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 * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "cutter.h"
@ -88,12 +88,28 @@ void cCuttingThread::Action(void)
bool CheckForSeamlessStream = false; bool CheckForSeamlessStream = false;
bool LastMark = false; bool LastMark = false;
bool cutIn = true; bool cutIn = true;
bool suspensionLogged = false;
while (Running()) { while (Running()) {
uint16_t FileNumber; uint16_t FileNumber;
off_t FileOffset; off_t FileOffset;
int Length; int Length;
bool Independent; 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: // Make sure there is enough disk space:
AssertFreeDiskSpace(-1); AssertFreeDiskSpace(-1);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "device.h"
@ -1721,6 +1721,7 @@ cTSBuffer::cTSBuffer(int File, int Size, int CardIndex)
delivered = false; delivered = false;
ringBuffer = new cRingBufferLinear(Size, TS_SIZE, true, "TS"); ringBuffer = new cRingBufferLinear(Size, TS_SIZE, true, "TS");
ringBuffer->SetTimeouts(100, 100); ringBuffer->SetTimeouts(100, 100);
ringBuffer->SetIoThrottle();
Start(); Start();
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #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 = new cRingBufferLinear(RECORDERBUFSIZE, MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE, true, "Recorder");
ringBuffer->SetTimeouts(0, 100); ringBuffer->SetTimeouts(0, 100);
ringBuffer->SetIoThrottle();
int Pid = Channel->Vpid(); int Pid = Channel->Vpid();
int Type = Channel->Vtype(); int Type = Channel->Vtype();

View File

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

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __RINGBUFFER_H
@ -22,6 +22,7 @@ private:
time_t lastOverflowReport; time_t lastOverflowReport;
int overflowCount; int overflowCount;
int overflowBytes; int overflowBytes;
cIoThrottle *ioThrottle;
protected: protected:
tThreadId getThreadTid; tThreadId getThreadTid;
int maxFill;//XXX int maxFill;//XXX
@ -40,6 +41,7 @@ public:
cRingBuffer(int Size, bool Statistics = false); cRingBuffer(int Size, bool Statistics = false);
virtual ~cRingBuffer(); virtual ~cRingBuffer();
void SetTimeouts(int PutTimeout, int GetTimeout); void SetTimeouts(int PutTimeout, int GetTimeout);
void SetIoThrottle(void);
void ReportOverflow(int Bytes); void ReportOverflow(int Bytes);
}; };

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "thread.h"
@ -398,6 +398,48 @@ bool cThreadLock::Lock(cThread *Thread)
return false; 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 -----------------------------------------------------------------
// cPipe::Open() and cPipe::Close() are based on code originally received from // 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 * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __THREAD_H
@ -157,6 +157,29 @@ public:
#define LOCK_THREAD cThreadLock ThreadLock(this) #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 // cPipe implements a pipe that closes all unnecessary file descriptors in
// the child process. // the child process.