Hi, the attached patches speed up starting and stopping VDR on slow machines with huge channels.conf files, by avoiding some n / 2 * (n + 1) loops. Please test them and report bugs here. Bye. -- Dipl.-Inform. (FH) Reinhard Nissl mailto:rnissl@xxxxxx
--- ../vdr-1.5.12-orig/channels.h 2007-09-02 12:23:11.000000000 +0200 +++ channels.h 2007-12-23 14:50:09.000000000 +0100 @@ -147,9 +147,12 @@ private: int modification; mutable const cSchedule *schedule; cLinkChannels *linkChannels; - cChannel *refChannel; + cLinkChannels *refChannels; cString ParametersToString(void) const; bool StringToParameters(const char *s); + void AddRefChannel(cChannel *RefChannel); + void DelRefChannel(cChannel *RefChannel); + void DelLinkChannel(cChannel *RefChannel); public: cChannel(void); cChannel(const cChannel &Channel); @@ -198,7 +201,8 @@ public: int Guard(void) const { return guard; } int Hierarchy(void) const { return hierarchy; } const cLinkChannels* LinkChannels(void) const { return linkChannels; } - const cChannel *RefChannel(void) const { return refChannel; } + const cChannel *RefChannel(void) const { return refChannels ? refChannels->Last()->Channel() : 0; } + const cLinkChannels* RefChannels(void) const { return refChannels; } bool IsCable(void) const { return cSource::IsCable(source); } bool IsSat(void) const { return cSource::IsSat(source); } bool IsTerr(void) const { return cSource::IsTerr(source); } @@ -216,7 +220,6 @@ public: void SetCaIds(const int *CaIds); // list must be zero-terminated void SetCaDescriptors(int Level); void SetLinkChannels(cLinkChannels *LinkChannels); - void SetRefChannel(cChannel *RefChannel); }; class cChannels : public cRwLock, public cConfig<cChannel> { --- ../vdr-1.5.12-orig/channels.c 2007-10-12 16:40:53.000000000 +0200 +++ channels.c 2007-12-23 14:50:09.000000000 +0100 @@ -178,7 +178,7 @@ cChannel::cChannel(void) modification = CHANNELMOD_NONE; schedule = NULL; linkChannels = NULL; - refChannel = NULL; + refChannels = NULL; } cChannel::cChannel(const cChannel &Channel) @@ -189,28 +189,26 @@ cChannel::cChannel(const cChannel &Chann portalName = NULL; schedule = NULL; linkChannels = NULL; - refChannel = NULL; + refChannels = NULL; *this = Channel; } cChannel::~cChannel() { - delete linkChannels; - linkChannels = NULL; // more than one channel can link to this one, so we need the following loop - for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) { - if (Channel->linkChannels) { - for (cLinkChannel *lc = Channel->linkChannels->First(); lc; lc = Channel->linkChannels->Next(lc)) { - if (lc->Channel() == this) { - Channel->linkChannels->Del(lc); - break; - } - } - if (Channel->linkChannels->Count() == 0) { - delete Channel->linkChannels; - Channel->linkChannels = NULL; - } - } - } + if (linkChannels) { + // in all channels which we link to remove the reference to us + for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) + lc->Channel()->DelRefChannel(this); + delete linkChannels; + linkChannels = NULL; + } + if (refChannels) { + // in all channels which reference us remove their link to us + for (cLinkChannel *lc = refChannels->First(); lc; lc = refChannels->Next(lc)) + lc->Channel()->DelLinkChannel(this); + delete refChannels; + refChannels = NULL; + } free(name); free(shortName); free(provider); @@ -556,7 +554,7 @@ void cChannel::SetLinkChannels(cLinkChan q += sprintf(q, "linking channel %d from", Number()); if (linkChannels) { for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { - lc->Channel()->SetRefChannel(NULL); + lc->Channel()->DelRefChannel(this); q += sprintf(q, " %d", lc->Channel()->Number()); } delete linkChannels; @@ -567,7 +565,7 @@ void cChannel::SetLinkChannels(cLinkChan linkChannels = LinkChannels; if (linkChannels) { for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { - lc->Channel()->SetRefChannel(this); + lc->Channel()->AddRefChannel(this); q += sprintf(q, " %d", lc->Channel()->Number()); //dsyslog("link %4d -> %4d: %s", Number(), lc->Channel()->Number(), lc->Channel()->Name()); } @@ -577,9 +575,39 @@ void cChannel::SetLinkChannels(cLinkChan dsyslog(buffer); } -void cChannel::SetRefChannel(cChannel *RefChannel) +void cChannel::AddRefChannel(cChannel *RefChannel) +{ + if (!refChannels) + refChannels = new cLinkChannels; + refChannels->Add(new cLinkChannel(RefChannel)); +} + +void cChannel::DelRefChannel(cChannel *RefChannel) { - refChannel = RefChannel; + for (cLinkChannel *lc = refChannels->First(); lc; lc = refChannels->Next(lc)) { + if (lc->Channel() == RefChannel) { + refChannels->Del(lc); + if (refChannels->Count() <= 0) { + delete refChannels; + refChannels = NULL; + } + return; + } + } +} + +void cChannel::DelLinkChannel(cChannel *LinkChannel) +{ + for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { + if (lc->Channel() == LinkChannel) { + linkChannels->Del(lc); + if (linkChannels->Count() <= 0) { + delete linkChannels; + linkChannels = NULL; + } + return; + } + } } static int PrintParameter(char *p, char Name, int Value)
--- ../vdr-1.5.12-orig/epg.h 2006-10-07 15:47:19.000000000 +0200 +++ epg.h 2007-12-23 22:10:31.000000000 +0100 @@ -164,11 +164,15 @@ class cSchedules : public cList<cSchedul friend class cSchedulesLock; private: cRwLock rwlock; + cHash<cSchedule> schedulesHash; static cSchedules schedules; static const char *epgDataFileName; static time_t lastCleanup; static time_t lastDump; static time_t modified; + void HashSchedule(cSchedule *Schedule); + void UnhashSchedule(cSchedule *Schedule); + static unsigned int HashKey(tChannelID ChannelID); public: static void SetEpgDataFileName(const char *FileName); static const cSchedules *Schedules(cSchedulesLock &SchedulesLock); --- ../vdr-1.5.12-orig/epg.c 2007-06-10 14:52:19.000000000 +0200 +++ epg.c 2007-12-23 22:10:31.000000000 +0100 @@ -1045,6 +1045,7 @@ cSchedule *cSchedules::AddSchedule(tChan if (!p) { p = new cSchedule(ChannelID); Add(p); + HashSchedule(p); cChannel *channel = Channels.GetByChannelID(ChannelID); if (channel) channel->schedule = p; @@ -1055,10 +1056,14 @@ cSchedule *cSchedules::AddSchedule(tChan const cSchedule *cSchedules::GetSchedule(tChannelID ChannelID) const { ChannelID.ClrRid(); - for (cSchedule *p = First(); p; p = Next(p)) { - if (p->ChannelID() == ChannelID) - return p; - } + cList<cHashObject> *list = schedulesHash.GetList(HashKey(ChannelID)); + if (list) { + for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) { + cSchedule *p = (cSchedule *)hobj->Object(); + if (p->ChannelID() == ChannelID) + return p; + } + } return NULL; } @@ -1074,7 +1079,23 @@ const cSchedule *cSchedules::GetSchedule if (Channel->schedule == &DummySchedule && AddIfMissing) { cSchedule *Schedule = new cSchedule(Channel->GetChannelID()); ((cSchedules *)this)->Add(Schedule); + ((cSchedules *)this)->HashSchedule(Schedule); Channel->schedule = Schedule; } return Channel->schedule != &DummySchedule? Channel->schedule : NULL; } + +void cSchedules::HashSchedule(cSchedule *Schedule) +{ + schedulesHash.Add(Schedule, HashKey(Schedule->ChannelID().ClrRid())); +} + +void cSchedules::UnhashSchedule(cSchedule *Schedule) +{ + schedulesHash.Del(Schedule, HashKey(Schedule->ChannelID().ClrRid())); +} + +unsigned int cSchedules::HashKey(tChannelID ChannelID) +{ + return (unsigned int)((ChannelID.Nid() << 16 | ChannelID.Source()) ^ (ChannelID.Tid() << 16 | ChannelID.Sid()) ^ ChannelID.Rid()); +}
_______________________________________________ vdr mailing list vdr@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr