diff --git a/sleepyhead/SleepLib/common.cpp b/sleepyhead/SleepLib/common.cpp index 7afd8d17..02979de9 100644 --- a/sleepyhead/SleepLib/common.cpp +++ b/sleepyhead/SleepLib/common.cpp @@ -585,7 +585,7 @@ QByteArray gCompress(const QByteArray& data) // Pinched from http://stackoverflow.com/questions/2690328/qt-quncompress-gzip-data -QByteArray gUncompress(const QByteArray &data) +QByteArray gUncompress(const QByteArray & data) { if (data.size() <= 4) { qWarning("gUncompress: Input data is truncated"); @@ -596,7 +596,7 @@ QByteArray gUncompress(const QByteArray &data) int ret; z_stream strm; - static const int CHUNK_SIZE = 1024; + static const int CHUNK_SIZE = 1048576; char out[CHUNK_SIZE]; /* allocate inflate state */ diff --git a/sleepyhead/SleepLib/day.cpp b/sleepyhead/SleepLib/day.cpp index 601e4e3d..f399a156 100644 --- a/sleepyhead/SleepLib/day.cpp +++ b/sleepyhead/SleepLib/day.cpp @@ -1046,6 +1046,20 @@ EventDataType Day::count(ChannelID code) return total; } +bool Day::noSettings(Machine * mach) +{ + for (auto & sess : sessions) { + if ((mach == nullptr) && sess->noSettings()) { + // If this day generally has just summary data. + return true; + } else if ((mach == sess->machine()) && sess->noSettings()) { + // Focus only on machine mach + return true; + } + } + return false; +} + bool Day::summaryOnly(Machine * mach) { for (auto & sess : sessions) { diff --git a/sleepyhead/SleepLib/day.h b/sleepyhead/SleepLib/day.h index 67a91fa4..84b27d0a 100644 --- a/sleepyhead/SleepLib/day.h +++ b/sleepyhead/SleepLib/day.h @@ -190,6 +190,9 @@ class Day //! \brief Check if day contains SummaryOnly records bool summaryOnly(Machine * mach = nullptr); + //! \brief Check if day has missing Summary/Settings records + bool noSettings(Machine * mach = nullptr); + //! \brief Finds and returns the index of a session, otherwise -1 if it's not there int find(Session *sess) { return sessions.indexOf(sess); } diff --git a/sleepyhead/SleepLib/event.cpp b/sleepyhead/SleepLib/event.cpp index f9bf66ae..8ebb48d1 100644 --- a/sleepyhead/SleepLib/event.cpp +++ b/sleepyhead/SleepLib/event.cpp @@ -1,4 +1,4 @@ -/* SleepLib Event Class Implementation +/* SleepLib Event Class Implementation * * Copyright (c) 2011-2018 Mark Watkins <mark@jedimark.net> * @@ -162,27 +162,24 @@ void EventList::AddWaveform(qint64 start, qint16 *data, int recs, qint64 duratio // EventStoreType *edata = m_data.data(); EventStoreType raw; - // qint16 *ep = data + recs; - qint16 *sp = data; + const qint16 *sp = data; + const qint16 *ep = data + recs; + EventStoreType *dp = (EventStoreType *)m_data.data()+r; // EventStoreType *dp = &edata[r]; if (m_update_minmax) { EventDataType min = m_min, max = m_max, val, gain = m_gain; - for (int i=0; i < recs; ++i) { - m_data[r++] = raw = *sp++; - val = EventDataType(raw) * gain + m_offset; + memcpy(dp, sp, recs*2); + + for (sp = data; sp < ep; ++sp) { +// *dp++ = raw = *sp; + val = EventDataType(*sp) * gain + m_offset; + if (min > val) { min = val; } + if (max < val) { max = val; } } -// for (sp = data; sp < ep; ++sp) { -// *dp++ = raw = *sp; -// val = EventDataType(raw) * gain + m_offset; - -// if (min > val) { min = val; } - -// if (max < val) { max = val; } -// } m_min = min; m_max = max; diff --git a/sleepyhead/SleepLib/event.h b/sleepyhead/SleepLib/event.h index e3bc3ea4..4aef0338 100644 --- a/sleepyhead/SleepLib/event.h +++ b/sleepyhead/SleepLib/event.h @@ -1,4 +1,4 @@ -/* SleepLib Event Class Header +/* SleepLib Event Class Header * * Copyright (C) 2011-2018 Mark Watkins <mark@jedimark.net> * diff --git a/sleepyhead/SleepLib/loader_plugins/edfparser.cpp b/sleepyhead/SleepLib/loader_plugins/edfparser.cpp index 20941b6b..f2756fb0 100644 --- a/sleepyhead/SleepLib/loader_plugins/edfparser.cpp +++ b/sleepyhead/SleepLib/loader_plugins/edfparser.cpp @@ -228,7 +228,7 @@ bool EDFParser::Open(const QString & name) } if (name.endsWith(STR_ext_gz)) { - filename = name.mid(0, -3); // DoubleCheck: why am I cropping the extension? this is used for debugging + filename = name; //name.mid(0, -3); // DoubleCheck: why am I cropping the extension? this is used for debugging // Open and decempress file data = gUncompress(fi.readAll()); @@ -243,7 +243,6 @@ bool EDFParser::Open(const QString & name) if (filesize > EDFHeaderSize) { header = (EDFHeader *)data.constData(); - //memcpy((char *)&header, (char *)data.constData(), sizeof(EDFHeader)); buffer = (char *)data.constData() + EDFHeaderSize; datasize = filesize - EDFHeaderSize; } else goto badfile; diff --git a/sleepyhead/SleepLib/loader_plugins/prs1_loader.cpp b/sleepyhead/SleepLib/loader_plugins/prs1_loader.cpp index 416bd253..18971014 100644 --- a/sleepyhead/SleepLib/loader_plugins/prs1_loader.cpp +++ b/sleepyhead/SleepLib/loader_plugins/prs1_loader.cpp @@ -3165,7 +3165,6 @@ QList<PRS1DataChunk *> PRS1Loader::ParseFile(const QString & path) int cruft = 0; int firstsession = 0; - int extra_bytes = 0; int htype,family,familyVersion,ext,header_size = 0; quint8 achk=0; quint32 sessionid=0, timestamp=0; diff --git a/sleepyhead/SleepLib/loader_plugins/resmed_loader.cpp b/sleepyhead/SleepLib/loader_plugins/resmed_loader.cpp index f6ee4b13..7c170a61 100644 --- a/sleepyhead/SleepLib/loader_plugins/resmed_loader.cpp +++ b/sleepyhead/SleepLib/loader_plugins/resmed_loader.cpp @@ -845,6 +845,10 @@ ResmedLoader::ResmedLoader() m_pixmaps[STR_ResMed_AirCurve10] = QPixmap(RM10C_ICON); m_pixmap_paths[STR_ResMed_AirCurve10] = RM10C_ICON; m_type = MT_CPAP; + + timeInTimeDelta = timeInLoadBRP = timeInLoadPLD = timeInLoadEVE = 0; + timeInLoadCSL = timeInLoadSAD = timeInEDFParser = timeInEDFOpen = timeInAddWaveform = 0; + } ResmedLoader::~ResmedLoader() { @@ -1502,9 +1506,8 @@ int ResmedLoader::scanFiles(Machine * mach, const QString & datalog_path) #endif return resdayList.size(); -} - /*// Check for duplicates - if (newfiles.contains(filename)) { +} /*// Check for duplicates + if (newfiles.contains(filename)) { // Not sure what to do with it.. delete it? check compress status and delete the other one? // Either way we don't want to process so skip it qDebug() << "Duplicate EDF file detected" << filename; @@ -2222,7 +2225,7 @@ void ResDayTask::run() } } - sess->settings[CPAP_BrokenSummary] = true; + sess->setNoSettings(true); if (!foundprev) { // We have no Summary or Settings data... we need to do something to indicate this, and detect the mode @@ -2593,6 +2596,18 @@ int ResmedLoader::Open(const QString & dirpath) } reimporting = true; + } else if (day->noSettings(mach) && resday.str.date.isValid()) { + // STR is present now, it wasn't before... we don't need to trash the files, but we do want the official settings. + // Do it right here + for (auto & sess : day->sessions) { + if (sess->machine() != mach) continue; + + qDebug() << "Adding STR.edf information to session" << sess->session(); + StoreSettings(sess, resday.str); + sess->setNoSettings(false); + sess->SetChanged(true); + sess->StoreSummary(); + } } else { continue; } @@ -2722,7 +2737,7 @@ int ResmedLoader::Open(const QString & dirpath) { qint64 totalbytes = 0; qint64 totalns = 0; - qDebug() << "Time Delta Efficiency Information"; + qDebug() << "Performance / Efficiency Information"; for (auto it = channel_efficiency.begin(), end=channel_efficiency.end(); it != end; it++) { ChannelID code = it.key(); @@ -2736,8 +2751,17 @@ int ResmedLoader::Open(const QString & dirpath) QString::number(qAbs(value)) + " bytes and took " + QString::number(secs, 'f', 4) + "s"; } - qDebug() << "Total toTimeDelta function usage:" << totalbytes << "in" << double( - totalns) / 1000000000.0 << "seconds"; + qDebug() << "Total toTimeDelta function usage:" << totalbytes << "in" << double(totalns) / 1000000000.0 << "seconds"; + + qDebug() << "Total CPU time in EDF Open" << timeInEDFOpen; + qDebug() << "Total CPU time in EDF Parser" << timeInEDFParser; + qDebug() << "Total CPU time in LoadBRP" << timeInLoadBRP; + qDebug() << "Total CPU time in LoadPLD" << timeInLoadPLD; + qDebug() << "Total CPU time in LoadSAD" << timeInLoadSAD; + qDebug() << "Total CPU time in LoadEVE" << timeInLoadEVE; + qDebug() << "Total CPU time in LoadCSL" << timeInLoadCSL; + qDebug() << "Total CPU time in (BRP) AddWaveform" << timeInAddWaveform; + qDebug() << "Total CPU time in TimeDelta function" << timeInTimeDelta; } #endif @@ -2822,9 +2846,21 @@ QString ResmedLoader::backup(const QString & fullname, const QString & backup_pa bool ResmedLoader::LoadCSL(Session *sess, const QString & path) { +#ifdef DEBUG_EFFICIENCY + QTime time; + time.start(); +#endif ResMedEDFParser edf(path); +#ifdef DEBUG_EFFICIENCY + int edfopentime = time.elapsed(); + time.start(); +#endif if (!edf.Parse()) return false; +#ifdef DEBUG_EFFICIENCY + int edfparsetime = time.elapsed(); + time.start(); +#endif QString t; @@ -2961,15 +2997,34 @@ bool ResmedLoader::LoadCSL(Session *sess, const QString & path) } Q_UNUSED(duration) +#ifdef DEBUG_EFFICIENCY + timeMutex.lock(); + timeInLoadCSL += time.elapsed(); + timeInEDFOpen += edfopentime; + timeInEDFParser += edfparsetime; + timeMutex.unlock(); +#endif return true; } bool ResmedLoader::LoadEVE(Session *sess, const QString & path) { +#ifdef DEBUG_EFFICIENCY + QTime time; + time.start(); +#endif ResMedEDFParser edf(path); +#ifdef DEBUG_EFFICIENCY + int edfopentime = time.elapsed(); + time.start(); +#endif if (!edf.Parse()) return false; +#ifdef DEBUG_EFFICIENCY + int edfparsetime = time.elapsed(); + time.start(); +#endif QString t; @@ -3115,18 +3170,38 @@ bool ResmedLoader::LoadEVE(Session *sess, const QString & path) } } +#ifdef DEBUG_EFFICIENCY + timeMutex.lock(); + timeInLoadEVE += time.elapsed(); + timeInEDFOpen += edfopentime; + timeInEDFParser += edfparsetime; + timeMutex.unlock(); +#endif return true; } bool ResmedLoader::LoadBRP(Session *sess, const QString & path) { +#ifdef DEBUG_EFFICIENCY + QTime time; + time.start(); +#endif ResMedEDFParser edf(path); +#ifdef DEBUG_EFFICIENCY + int edfopentime = time.elapsed(); + time.start(); +#endif if (!edf.Parse()) return false; - +#ifdef DEBUG_EFFICIENCY + int edfparsetime = time.elapsed(); + time.start(); + int AddWavetime = 0; +#endif sess->updateFirst(edf.startdate); + QTime time2; qint64 duration = edf.GetNumDataRecords() * edf.GetDuration(); sess->updateLast(edf.startdate + duration); @@ -3158,7 +3233,14 @@ bool ResmedLoader::LoadBRP(Session *sess, const QString & path) double rate = double(duration) / double(recs); EventList *a = sess->AddEventList(code, EVL_Waveform, es.gain, es.offset, 0, 0, rate); a->setDimension(es.physical_dimension); +#ifdef DEBUG_EFFICIENCY + time2.start(); +#endif a->AddWaveform(edf.startdate, es.data, recs, duration); +#ifdef DEBUG_EFFICIENCY + AddWavetime+= time2.elapsed(); +#endif + EventDataType min = a->Min(); EventDataType max = a->Max(); @@ -3173,6 +3255,15 @@ bool ResmedLoader::LoadBRP(Session *sess, const QString & path) } } +#ifdef DEBUG_EFFICIENCY + timeMutex.lock(); + timeInLoadBRP += time.elapsed(); + timeInEDFOpen += edfopentime; + timeInEDFParser += edfparsetime; + timeInAddWaveform += AddWavetime; + timeMutex.unlock(); +#endif + return true; } @@ -3307,6 +3398,7 @@ void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &e } #ifdef DEBUG_EFFICIENCY + timeMutex.lock(); if (el != nullptr) { qint64 t = time.nsecsElapsed(); int cnt = el->count(); @@ -3322,15 +3414,29 @@ void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &e channel_time[code] += t; } } + timeInTimeDelta += time.elapsed(); + timeMutex.unlock(); #endif } // Load SAD Oximetry Signals bool ResmedLoader::LoadSAD(Session *sess, const QString & path) { +#ifdef DEBUG_EFFICIENCY + QTime time; + time.start(); +#endif ResMedEDFParser edf(path); +#ifdef DEBUG_EFFICIENCY + int edfopentime = time.elapsed(); + time.start(); +#endif if (!edf.Parse()) return false; +#ifdef DEBUG_EFFICIENCY + int edfparsetime = time.elapsed(); + time.start(); +#endif sess->updateFirst(edf.startdate); qint64 duration = edf.GetNumDataRecords() * edf.GetDuration(); @@ -3369,15 +3475,34 @@ bool ResmedLoader::LoadSAD(Session *sess, const QString & path) } } +#ifdef DEBUG_EFFICIENCY + timeMutex.lock(); + timeInLoadSAD += time.elapsed(); + timeInEDFOpen += edfopentime; + timeInEDFParser += edfparsetime; + timeMutex.unlock(); +#endif return true; } bool ResmedLoader::LoadPLD(Session *sess, const QString & path) { +#ifdef DEBUG_EFFICIENCY + QTime time; + time.start(); +#endif ResMedEDFParser edf(path); +#ifdef DEBUG_EFFICIENCY + int edfopentime = time.elapsed(); + time.start(); +#endif if (!edf.Parse()) return false; +#ifdef DEBUG_EFFICIENCY + int edfparsetime = time.elapsed(); + time.start(); +#endif // Is it save to assume the order does not change here? enum PLDType { MaskPres = 0, TherapyPres, ExpPress, Leak, RR, Vt, Mv, SnoreIndex, FFLIndex, U1, U2 }; @@ -3510,6 +3635,13 @@ bool ResmedLoader::LoadPLD(Session *sess, const QString & path) } } +#ifdef DEBUG_EFFICIENCY + timeMutex.lock(); + timeInLoadPLD += time.elapsed(); + timeInEDFOpen += edfopentime; + timeInEDFParser += edfparsetime; + timeMutex.unlock(); +#endif return true; } diff --git a/sleepyhead/SleepLib/loader_plugins/resmed_loader.h b/sleepyhead/SleepLib/loader_plugins/resmed_loader.h index 9813443e..7097483c 100644 --- a/sleepyhead/SleepLib/loader_plugins/resmed_loader.h +++ b/sleepyhead/SleepLib/loader_plugins/resmed_loader.h @@ -460,6 +460,18 @@ protected: #ifdef DEBUG_EFFICIENCY QHash<ChannelID, qint64> channel_efficiency; QHash<ChannelID, qint64> channel_time; + volatile qint64 timeInLoadBRP; + volatile qint64 timeInLoadPLD; + volatile qint64 timeInLoadEVE; + volatile qint64 timeInLoadCSL; + volatile qint64 timeInLoadSAD; + volatile qint64 timeInEDFOpen; + volatile qint64 timeInEDFParser; + volatile qint64 timeInAddWaveform; + volatile qint64 timeInTimeDelta; + QMutex timeMutex; + + #endif }; diff --git a/sleepyhead/SleepLib/session.cpp b/sleepyhead/SleepLib/session.cpp index 3888e2e7..d3de17be 100644 --- a/sleepyhead/SleepLib/session.cpp +++ b/sleepyhead/SleepLib/session.cpp @@ -23,7 +23,7 @@ using namespace std; // This is the uber important database version for SleepyHeads internal storage // Increment this after stuffing with Session's save & load code. -const quint16 summary_version = 17; +const quint16 summary_version = 18; const quint16 events_version = 10; Session::Session(Machine *m, SessionID session) @@ -46,7 +46,7 @@ Session::Session(Machine *m, SessionID session) s_first = s_last = 0; s_evchecksum_checked = false; - s_summaryOnly = false; + s_noSettings = s_summaryOnly = false; destroyed = false; } @@ -361,6 +361,8 @@ bool Session::StoreSummary() out << s_summaryOnly; // 13 -> + out << s_noSettings; // 18 + out << m_slices; file.close(); @@ -609,6 +611,11 @@ bool Session::LoadSummary() } else if (version > 13) { in >> s_summaryOnly; } + if (version >= 18) { + in >> s_noSettings; + } else { + s_noSettings = (settings.size() == 0); + } if (version == 16) { QList<SessionSlice> slices; diff --git a/sleepyhead/SleepLib/session.h b/sleepyhead/SleepLib/session.h index 682d7913..67d7d72c 100644 --- a/sleepyhead/SleepLib/session.h +++ b/sleepyhead/SleepLib/session.h @@ -1,4 +1,4 @@ -/* SleepLib Session Header +/* SleepLib Session Header * * This stuff contains the session calculation smarts * @@ -386,13 +386,11 @@ class Session Machine *machine() { return s_machine; } //! \brief Returns true if session only contains summary data - inline bool summaryOnly() { - return s_summaryOnly; - } + inline bool summaryOnly() { return s_summaryOnly; } + inline bool noSettings() { return s_noSettings; } - inline void setSummaryOnly(bool b) { - s_summaryOnly = b; - } + inline void setSummaryOnly(bool b) { s_summaryOnly = b; } + inline void setNoSettings(bool b) { s_noSettings = b; } void setOpened(bool b = true) { s_events_loaded = b; @@ -432,6 +430,7 @@ protected: bool s_evchecksum_checked; bool _first_session; bool s_summaryOnly; + bool s_noSettings; bool s_summary_loaded; bool s_events_loaded; diff --git a/sleepyhead/daily.cpp b/sleepyhead/daily.cpp index 01e910c5..22e994a0 100644 --- a/sleepyhead/daily.cpp +++ b/sleepyhead/daily.cpp @@ -987,7 +987,9 @@ QString Daily::getMachineSettings(Day * day) { html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>").arg(tr("Machine Settings")); html+="<tr><td colspan=5> </td></tr>"; - if ((day->settingExists(CPAP_BrokenSummary))) { + if (day->noSettings(cpap)) { + html+="<tr><td colspan=5 align=center><i>"+tr("<b>Please Note:</b> All settings shown below are based on assumptions that nothing's changed since previous days.")+"</i></td></tr>\n"; + } else if ((day->settingExists(CPAP_BrokenSummary))) { html+="<tr><td colspan=5 align=center><i>"+tr("Machine Settings Unavailable")+"</i></td></tr></table><hr/>\n"; return html; } @@ -1147,9 +1149,9 @@ QString Daily::getCPAPInformation(Day * day) html+=tr("PAP Mode: %1<br/>").arg(day->getCPAPMode()); html+= day->getPressureSettings(); html+="</td></tr>\n"; - if ((day->settingExists(CPAP_BrokenSummary))) { - html+="<tr><td> </td></tr>\n"; - html+=QString("<tr><td colspan=2><i>%1</i></td></tr>").arg("<b>"+STR_MessageBox_PleaseNote+":</b> "+ tr("This day has missing pressure, mode and settings data.")); + if (day->noSettings(cpap)) { // (day->settingExists(CPAP_BrokenSummary))) { + //html+="<tr><td> </td></tr>\n"; + html+=QString("<tr><td colspan=2 align=center><i>%1</i></td></tr>").arg(tr("(Mode/Pressure settings are guessed on this day.)")); } html+="</table>\n"; @@ -1257,7 +1259,7 @@ QString Daily::getStatisticsInfo(Day * day) if (GraphView->isEmpty() && ((ccnt>0) || (cpap && day->summaryOnly()))) { html+="<tr><td colspan=5> </td></tr>\n"; - html+=QString("<tr><td colspan=5 align=center><i>%1</i></td></tr>").arg("<b>"+STR_MessageBox_PleaseNote+"</b> "+ tr("This day just contains summary data, only limited information is available .")); + html+=QString("<tr><td colspan=5 align=center><i>%1</i></td></tr>").arg("<b>"+STR_MessageBox_PleaseNote+"</b> "+ tr("This day just contains summary data, only limited information is available.")); } else if (cpap) { html+="<tr><td colspan=5> </td></tr>";