Ticket #3326: 3326-multimap-sched-v1.patch

File 3326-multimap-sched-v1.patch, 12.4 KB (added by danielk, 12 years ago)

Adds a range map for finding conflicts, 3% speedup

  • programs/mythbackend/scheduler.h

     
    22#define SCHEDULER_H_
    33
    44// C++ headers
     5#include <map>
    56#include <deque>
    67#include <vector>
    78using namespace std;
     
    3536typedef RecList::iterator RecIter;
    3637
    3738typedef vector<int> InputGroupList;
     39typedef QMap<int, RecList> CardListMap;
    3840
     41typedef multimap<uint64_t, ProgramInfo*> ConflictMap;
     42
    3943class Scheduler : public QObject
    4044{
    4145  public:
     
    7781    void EnableScheduling(void) { schedulingEnabled = true; }
    7882    void GetNextLiveTVDir(int cardid);
    7983
     84    // constants
     85    static const int kConflictMapInterval;
     86    static const int kConflictMapHalfInterval;
     87
    8088  protected:
    8189    void RunScheduler(void);
    8290    static void *SchedulerThread(void *param);
     
    100108    void BuildListMaps(void);
    101109    void ClearListMaps(void);
    102110
     111    bool IsConflicting(const ProgramInfo *p, const ProgramInfo *q,
     112                       bool openEnd) const;
     113
    103114    bool IsSameProgram(const ProgramInfo *a, const ProgramInfo *b) const;
    104115
    105116    bool FindNextConflict(const RecList &cardlist,
    106117                          const ProgramInfo *p, RecConstIter &iter,
    107118                          bool openEnd = false) const;
    108     const ProgramInfo *FindConflict(const QMap<int, RecList> &reclists,
    109                                     const ProgramInfo *p, bool openEnd = false) const;
     119
     120    ProgramInfo *FindAnyConflict(
     121        ConflictMap &map, const ProgramInfo *p, bool openend) const;
     122
     123    RecList FindAllConflicts(
     124        ConflictMap &map, const ProgramInfo *p, bool openend) const;
     125
    110126    void MarkOtherShowings(ProgramInfo *p);
    111127    void MarkShowingsList(RecList &showinglist, ProgramInfo *p);
    112128    void BackupRecStatus(void);
     
    140156    RecList reclist;
    141157    RecList worklist;
    142158    RecList retrylist;
    143     QMap<int, RecList> cardlistmap;
     159    ConflictMap conflictmap;
    144160    QMap<int, RecList> recordidlistmap;
    145161    QMap<QString, RecList> titlelistmap;
    146162    QMap<int, InputGroupList> inputgroupmap;
  • programs/mythbackend/scheduler.cpp

     
    3838#define LOC QString("Scheduler: ")
    3939#define LOC_ERR QString("Scheduler, Error: ")
    4040
     41const int Scheduler::kConflictMapInterval     = 1920;
     42const int Scheduler::kConflictMapHalfInterval = 960;
     43
    4144Scheduler::Scheduler(bool runthread, QMap<int, EncoderLink *> *tvList,
    4245                     QString tmptable, Scheduler *master_sched) :
    4346    livetvTime(QDateTime())
     
    750753    erase_nulls(worklist);
    751754}
    752755
     756static uint insert(ConflictMap &cmap, const InputGroupList &input_groups,
     757                   ProgramInfo *p)
     758{
     759    uint insert_cnt = 0;
     760    uint64_t btimeX = min(p->recstartts.toTime_t(),
     761                          p->startts.toTime_t());
     762    uint64_t etimeX = max(p->recendts.toTime_t(),
     763                          p->endts.toTime_t());
     764
     765    InputGroupList::const_iterator it = input_groups.begin();
     766    for (; it != input_groups.end(); ++it)
     767    {
     768        uint64_t btime = (((uint64_t)(*it)) << 32) + btimeX;
     769        uint64_t etime = (((uint64_t)(*it)) << 32) + etimeX;
     770        for (; btime < etime; btime += Scheduler::kConflictMapInterval)
     771        {
     772            cmap.insert(pair<uint64_t, ProgramInfo*>(btime, p));
     773            insert_cnt++;
     774        }
     775        cmap.insert(pair<uint64_t, ProgramInfo*>(etime, p));
     776        insert_cnt++;
     777    }
     778
     779    return insert_cnt;
     780}
     781
    753782void Scheduler::BuildListMaps(void)
    754783{
    755784    RecIter i = worklist.begin();
     
    760789            p->recstatus == rsWillRecord ||
    761790            p->recstatus == rsUnknown)
    762791        {
    763             cardlistmap[p->cardid].push_back(p);
     792            insert(conflictmap, inputgroupmap[p->inputid], p);
    764793            titlelistmap[p->title].push_back(p);
    765794            recordidlistmap[p->recordid].push_back(p);
    766795        }
     
    769798
    770799void Scheduler::ClearListMaps(void)
    771800{
    772     cardlistmap.clear();
     801    conflictmap.clear();
    773802    titlelistmap.clear();
    774803    recordidlistmap.clear();
    775     VERBOSE(VB_IMPORTANT, "cache_is_same_program: "
    776             <<cache_is_same_program.size());
    777804    cache_is_same_program.clear();
    778805}
    779806
     807bool Scheduler::IsConflicting(
     808    const ProgramInfo *p, const ProgramInfo *q, bool openEnd) const
     809{
     810    if (!Recording(q))
     811        return false;
     812
     813    if (p == q)
     814        return false;
     815
     816    if (p->cardid != 0 && (p->cardid != q->cardid) &&
     817        !GetSharedInputGroup(p->inputid, q->inputid))
     818    {
     819        return false;
     820    }
     821
     822    if (openEnd && p->chanid != q->chanid)
     823    {
     824        if (p->recendts < q->recstartts || p->recstartts > q->recendts)
     825        {
     826            return false;
     827        }
     828    }
     829    else
     830    {
     831        if (p->recendts <= q->recstartts || p->recstartts >= q->recendts)
     832        {
     833            return false;
     834        }
     835    }
     836
     837    // if two inputs are in the same input group we have a conflict
     838    // unless the programs are on the same multiplex.
     839    if (p->cardid && (p->cardid != q->cardid) &&
     840        GetSharedInputGroup(p->inputid, q->inputid) &&
     841        p->GetMplexID() && (p->GetMplexID() == q->GetMplexID()))
     842    {
     843        return false;
     844    }
     845
     846    return true;
     847}
     848
    780849bool Scheduler::IsSameProgram(
    781850    const ProgramInfo *a, const ProgramInfo *b) const
    782851{
     
    799868    RecConstIter      &j,
    800869    bool               openEnd) const
    801870{
    802     bool is_conflict_dbg = false;
    803 
    804871    for ( ; j != cardlist.end(); j++)
    805872    {
    806         const ProgramInfo *q = *j;
     873        if (IsConflicting(p, *j, openEnd))
     874            return true;
     875    }
    807876
    808         if (p == q)
    809             continue;
     877    return false;
     878}
    810879
    811         if (!Recording(q))
    812             continue;
     880ProgramInfo *Scheduler::FindAnyConflict(
     881    ConflictMap &cmap, const ProgramInfo *p, bool openend) const
     882{
     883    QMap<ProgramInfo*,ProgramInfo*> dups;
     884    uint64_t btimeX = p->recstartts.toTime_t() - kConflictMapHalfInterval - 30;
     885    uint64_t etimeX = p->recendts.toTime_t()   + kConflictMapHalfInterval + 30;
    813886
    814         if (is_conflict_dbg)
    815             cout << QString("\n  comparing with '%1' ").arg(q->title);
     887    const InputGroupList &ingrp = inputgroupmap[p->inputid];
     888    InputGroupList::const_iterator grpit = ingrp.begin();
     889    const ProgramInfo *last = NULL;
     890    for (; grpit != ingrp.end(); ++grpit)
     891    {
     892        uint64_t btime = btimeX | (((uint64_t)*grpit) << 32);
     893        ConflictMap::iterator beg = cmap.lower_bound(btime);
     894        uint64_t etime = etimeX | (((uint64_t)*grpit) << 32);
     895        ConflictMap::iterator end = cmap.upper_bound(etime);
    816896
    817         if (p->cardid != 0 && (p->cardid != q->cardid) &&
    818             !GetSharedInputGroup(p->inputid, q->inputid))
     897        ConflictMap::iterator it = beg;
     898        for (; it != end; ++it)
    819899        {
    820             if (is_conflict_dbg)
    821                 cout << "  cardid== ";
    822             continue;
    823         }
    824 
    825         if (openEnd && p->chanid != q->chanid)
    826         {
    827             if (p->recendts < q->recstartts || p->recstartts > q->recendts)
    828             {
    829                 if (is_conflict_dbg)
    830                     cout << "  no-overlap ";
     900            if ((it->second == last) || dups[it->second])
    831901                continue;
    832             }
     902            last = dups[it->second] = it->second;
     903            if (IsConflicting(p, it->second, openend))
     904                return it->second;
    833905        }
    834         else
    835         {
    836             if (p->recendts <= q->recstartts || p->recstartts >= q->recendts)
    837             {
    838                 if (is_conflict_dbg)
    839                     cout << "  no-overlap ";
    840                 continue;
    841             }
    842         }
    843 
    844         if (is_conflict_dbg)
    845             cout << "\n" <<
    846                 QString("  cardid's: %1, %2 ").arg(p->cardid).arg(q->cardid) +
    847                 QString("Shared input group: %1 ")
    848                 .arg(GetSharedInputGroup(p->inputid, q->inputid)) +
    849                 QString("mplexid's: %1, %2")
    850                 .arg(p->GetMplexID()).arg(q->GetMplexID());
    851 
    852         // if two inputs are in the same input group we have a conflict
    853         // unless the programs are on the same multiplex.
    854         if (p->cardid && (p->cardid != q->cardid) &&
    855             GetSharedInputGroup(p->inputid, q->inputid) &&
    856             p->GetMplexID() && (p->GetMplexID() == q->GetMplexID()))
    857         {
    858             continue;
    859         }
    860 
    861         if (is_conflict_dbg)
    862             cout << "\n  Found conflict" << endl;
    863 
    864         return true;
    865906    }
    866907
    867     if (is_conflict_dbg)
    868         cout << "\n  No conflict" << endl;
    869 
    870     return false;
     908    return NULL;
    871909}
    872910
    873 const ProgramInfo *Scheduler::FindConflict(
    874     const QMap<int, RecList> &reclists,
    875     const ProgramInfo        *p,
    876     bool openend) const
     911RecList Scheduler::FindAllConflicts(
     912    ConflictMap &cmap, const ProgramInfo *p, bool openend) const
    877913{
    878     bool is_conflict_dbg = false;
     914    RecList list;
    879915
    880     QMap<int, RecList>::const_iterator it = reclists.begin();
    881     for (; it != reclists.end(); ++it)
     916    QMap<ProgramInfo*,ProgramInfo*> dups;
     917    uint64_t btimeX = p->recstartts.toTime_t() - kConflictMapHalfInterval - 30;
     918    uint64_t etimeX = p->recendts.toTime_t()   + kConflictMapHalfInterval + 30;
     919
     920    const InputGroupList &ingrp = inputgroupmap[p->inputid];
     921    InputGroupList::const_iterator grpit = ingrp.begin();
     922    const ProgramInfo *last = NULL;
     923    for (; grpit != ingrp.end(); ++grpit)
    882924    {
    883         if (is_conflict_dbg)
     925        uint64_t btime = btimeX | (((uint64_t)*grpit) << 32);
     926        ConflictMap::iterator beg = cmap.lower_bound(btime);
     927        uint64_t etime = etimeX | (((uint64_t)*grpit) << 32);
     928        ConflictMap::iterator end = cmap.upper_bound(etime);
     929
     930        ConflictMap::iterator it = beg;
     931        for (; it != end; ++it)
    884932        {
    885             cout << QString("Checking '%1' for conflicts on cardid %2")
    886                 .arg(p->title).arg(it.key());
    887         }
     933            if ((it->second == last) || dups[it->second])
     934                continue;
     935            last = dups[it->second] = it->second;
    888936
    889         const RecList &cardlist = *it;
    890         RecConstIter k = cardlist.begin();
    891         if (FindNextConflict(cardlist, p, k, openend))
    892         {
    893             return *k;
     937            const ProgramInfo *q = last;
     938            if (openend && p->chanid != q->chanid)
     939            {
     940                if (p->recendts < q->recstartts || p->recstartts > q->recendts)
     941                    continue;
     942            }
     943            else
     944            {
     945                if (p->recendts <= q->recstartts ||
     946                    p->recstartts >= q->recendts)
     947                    continue;
     948            }
     949
     950            if (IsConflicting(p, it->second, openend))
     951                list.push_back(it->second);
    894952        }
    895953    }
    896954
    897     return NULL;
     955    return list;
    898956}
    899957
    900958void Scheduler::MarkOtherShowings(ProgramInfo *p)
     
    10511109            }
    10521110        }
    10531111
    1054         const ProgramInfo *conflict = FindConflict(cardlistmap, q);
     1112        const ProgramInfo *conflict = FindAnyConflict(conflictmap, q, false);
    10551113        if (conflict)
    10561114        {
    10571115            PrintRec(conflict, "        !");
     
    11001158            MarkOtherShowings(p);
    11011159        else if (p->recstatus == rsUnknown)
    11021160        {
    1103             const ProgramInfo *conflict = FindConflict(cardlistmap, p, openEnd);
     1161            const ProgramInfo *conflict =
     1162                FindAnyConflict(conflictmap, p, openEnd);
     1163
    11041164            if (!conflict)
    11051165            {
    11061166                p->recstatus = rsWillRecord;
     
    11601220        if (move_this)
    11611221            MarkOtherShowings(p);
    11621222
    1163         RecList cardlist;
    1164         QMap<int, RecList>::const_iterator it = cardlistmap.begin();
    1165         for (; it != cardlistmap.end(); ++it)
     1223        RecList conflicts = FindAllConflicts(conflictmap, p, false);
     1224        RecList::iterator k = conflicts.begin();
     1225        for (; k != conflicts.end(); ++k)
    11661226        {
    1167             RecConstIter it2 = (*it).begin();
    1168             for (; it2 != (*it).end(); ++it2)
    1169                 cardlist.push_back(*it2);
    1170         }
    1171        
    1172         RecConstIter k = cardlist.begin();
    1173         for ( ; FindNextConflict(cardlist, p, k); k++)
    1174         {
    11751227            if ((p->recpriority < (*k)->recpriority && !schedMoveHigher &&
    11761228                move_this) || !TryAnotherShowing(*k, !move_this))
    11771229            {