diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.cpp b/oscar/SleepLib/loader_plugins/prs1_loader.cpp
index 873a0b72..230296d9 100644
--- a/oscar/SleepLib/loader_plugins/prs1_loader.cpp
+++ b/oscar/SleepLib/loader_plugins/prs1_loader.cpp
@@ -1886,7 +1886,7 @@ static QString hex(int i)
     return QString("0x") + QString::number(i, 16).toUpper();
 }
 
-#define ENUMSTRING(ENUM) case ENUM: s = #ENUM; break
+#define ENUMSTRING(ENUM) case ENUM: s = QStringLiteral(#ENUM); break
 static QString parsedEventTypeName(PRS1ParsedEventType t)
 {
     QString s;
@@ -2028,7 +2028,13 @@ static QString timeStr(int t)
     int h = t / 3600;
     int m = (t - (h * 3600)) / 60;
     int s = t % 60;
+#if 1
+    // Optimized after profiling regression tests.
+    return QString::asprintf("%02d:%02d:%02d", h, m, s);
+#else
+    // Unoptimized original, slows down regression tests.
     return QString("%1:%2:%3").arg(h, 2, 10, QChar('0')).arg(m, 2, 10, QChar('0')).arg(s, 2, 10, QChar('0'));
+#endif
 }
 
 static QString byteList(QByteArray data, int limit)
diff --git a/oscar/tests/prs1tests.cpp b/oscar/tests/prs1tests.cpp
index dce2b64f..be15e5e5 100644
--- a/oscar/tests/prs1tests.cpp
+++ b/oscar/tests/prs1tests.cpp
@@ -147,6 +147,23 @@ static QString byteList(QByteArray data, int limit=-1)
     if (limit == -1 || limit > count) limit = count;
     int first = limit / 2;
     int last = limit - first;
+#if 1
+    // Optimized after profiling regression tests.
+    QString s;
+    s.reserve(3 * limit + 4);  // "NN " for each byte + possible "... " in the middle
+    const unsigned char* b = (const unsigned char*) data.constData();
+    for (int i = 0; i < first; i++) {
+        s.append(QString::asprintf("%02X ", b[i]));
+    }
+    if (limit < count) {
+        s.append(QStringLiteral("... "));
+    }
+    for (int i = count - last; i < count; i++) {
+        s.append(QString::asprintf("%02X ", b[i]));
+    }
+    s.resize(s.size() - 1);  // remove trailing space
+#else
+    // Unoptimized original, slows down regression tests.
     QStringList l;
     for (int i = 0; i < first; i++) {
         l.push_back(QString( "%1" ).arg((int) data[i] & 0xFF, 2, 16, QChar('0') ).toUpper());
@@ -156,58 +173,59 @@ static QString byteList(QByteArray data, int limit=-1)
         l.push_back(QString( "%1" ).arg((int) data[i] & 0xFF, 2, 16, QChar('0') ).toUpper());
     }
     QString s = l.join(" ");
+#endif
     return s;
 }
 
 void ChunkToYaml(QTextStream & out, PRS1DataChunk* chunk, bool ok)
 {
     // chunk header
-    out << "chunk:" << endl;
-    out << "  at: " << hex << chunk->m_filepos << endl;
-    out << "  parsed: " << ok << endl;
-    out << "  version: " << dec << chunk->fileVersion << endl;
-    out << "  size: " << chunk->blockSize << endl;
-    out << "  htype: " << chunk->htype << endl;
-    out << "  family: " << chunk->family << endl;
-    out << "  familyVersion: " << chunk->familyVersion << endl;
-    out << "  ext: " << chunk->ext << endl;
-    out << "  session: " << chunk->sessionid << endl;
-    out << "  start: " << ts(chunk->timestamp * 1000L) << endl;
-    out << "  duration: " << dur(chunk->duration * 1000L) << endl;
+    out << "chunk:" << '\n';
+    out << "  at: " << hex << chunk->m_filepos << '\n';
+    out << "  parsed: " << ok << '\n';
+    out << "  version: " << dec << chunk->fileVersion << '\n';
+    out << "  size: " << chunk->blockSize << '\n';
+    out << "  htype: " << chunk->htype << '\n';
+    out << "  family: " << chunk->family << '\n';
+    out << "  familyVersion: " << chunk->familyVersion << '\n';
+    out << "  ext: " << chunk->ext << '\n';
+    out << "  session: " << chunk->sessionid << '\n';
+    out << "  start: " << ts(chunk->timestamp * 1000L) << '\n';
+    out << "  duration: " << dur(chunk->duration * 1000L) << '\n';
 
     // hblock for V3 non-waveform chunks
     if (chunk->fileVersion == 3 && chunk->htype == 0) {
-        out << "  hblock:" << endl;
+        out << "  hblock:" << '\n';
         QMapIterator<unsigned char, short> i(chunk->hblock);
         while (i.hasNext()) {
             i.next();
-            out << "    " << (int) i.key() << ": " << i.value() << endl;
+            out << "    " << (int) i.key() << ": " << i.value() << '\n';
         }
     }
 
     // waveform chunks
     if (chunk->htype == 1) {
-        out << "  intervals: " << chunk->interval_count << endl;
-        out << "  intervalSeconds: " << (int) chunk->interval_seconds << endl;
-        out << "  interleave:" << endl;
+        out << "  intervals: " << chunk->interval_count << '\n';
+        out << "  intervalSeconds: " << (int) chunk->interval_seconds << '\n';
+        out << "  interleave:" << '\n';
         for (int i=0; i < chunk->waveformInfo.size(); i++) {
             const PRS1Waveform & w = chunk->waveformInfo.at(i);
-            out << "    " << i << ": " << w.interleave << endl;
+            out << "    " << i << ": " << w.interleave << '\n';
         }
-        out << "  end: " << ts((chunk->timestamp + chunk->duration) * 1000L) << endl;
+        out << "  end: " << ts((chunk->timestamp + chunk->duration) * 1000L) << '\n';
     }
     
     // header checksum
-    out << "  checksum: " << hex << chunk->storedChecksum << endl;
+    out << "  checksum: " << hex << chunk->storedChecksum << '\n';
     if (chunk->storedChecksum != chunk->calcChecksum) {
-        out << "  calcChecksum: " << hex << chunk->calcChecksum << endl;
+        out << "  calcChecksum: " << hex << chunk->calcChecksum << '\n';
     }
     
     // data
     bool dump_data = true;
     if (chunk->m_parsedData.size() > 0) {
         dump_data = false;
-        out << "  events:" << endl;
+        out << "  events:" << '\n';
         for (auto & e : chunk->m_parsedData) {
             QString name = _PRS1ParsedEventName(e);
             if (name == "raw" || name == "unknown") {
@@ -215,32 +233,32 @@ void ChunkToYaml(QTextStream & out, PRS1DataChunk* chunk, bool ok)
             }
             QMap<QString,QString> contents = _PRS1ParsedEventContents(e);
             if (name == "setting" && contents.size() == 1) {
-                out << "  - set_" << contents.firstKey() << ": " << contents.first() << endl;
+                out << "  - set_" << contents.firstKey() << ": " << contents.first() << '\n';
             }
             else {
-                out << "  - " << name << ":" << endl;
+                out << "  - " << name << ":" << '\n';
                 
                 // Always emit start first if present
                 if (contents.contains("start")) {
-                    out << "      " << "start" << ": " << contents["start"] << endl;
+                    out << "      " << "start" << ": " << contents["start"] << '\n';
                 }
                 for (auto & key : contents.keys()) {
                     if (key == "start") continue;
-                    out << "      " << key << ": " << contents[key] << endl;
+                    out << "      " << key << ": " << contents[key] << '\n';
                 }
             }
         }
     }
     if (dump_data || !ok) {
-        out << "  data: " << byteList(chunk->m_data, 100) << endl;
+        out << "  data: " << byteList(chunk->m_data, 100) << '\n';
     }
     
     // data CRC
-    out << "  crc: " << hex << chunk->storedCrc << endl;
+    out << "  crc: " << hex << chunk->storedCrc << '\n';
     if (chunk->storedCrc != chunk->calcCrc) {
-        out << "  calcCrc: " << hex << chunk->calcCrc << endl;
+        out << "  calcCrc: " << hex << chunk->calcCrc << '\n';
     }
-    out << endl;
+    out << '\n';
 }
 
 void parseAndEmitChunkYaml(const QString & path)
@@ -328,7 +346,7 @@ void parseAndEmitChunkYaml(const QString & path)
                 // Only write unique chunks to the file.
                 if (written[outpath].contains(chunk->hash()) == false) {
                     if (first_chunk_from_file) {
-                        out << "file: " << relative << endl;
+                        out << "file: " << relative << '\n';
                         first_chunk_from_file = false;
                     }
                     bool ok = true;
diff --git a/oscar/tests/sessiontests.cpp b/oscar/tests/sessiontests.cpp
index d66402c8..d76000b8 100644
--- a/oscar/tests/sessiontests.cpp
+++ b/oscar/tests/sessiontests.cpp
@@ -244,14 +244,14 @@ void SessionToYaml(QString filepath, Session* session, bool ok)
     }
     QTextStream out(&file);
 
-    out << "session:" << endl;
-    out << "  id: " << session->session() << endl;
-    out << "  start: " << ts(session->first()) << endl;
-    out << "  end: " << ts(session->last()) << endl;
-    out << "  valid: " << ok << endl;
+    out << "session:" << '\n';
+    out << "  id: " << session->session() << '\n';
+    out << "  start: " << ts(session->first()) << '\n';
+    out << "  end: " << ts(session->last()) << '\n';
+    out << "  valid: " << ok << '\n';
     
     if (!session->m_slices.isEmpty()) {
-        out << "  slices:" << endl;
+        out << "  slices:" << '\n';
         for (auto & slice : session->m_slices) {
             QString s;
             switch (slice.status) {
@@ -260,9 +260,9 @@ void SessionToYaml(QString filepath, Session* session, bool ok)
             case EquipmentOff: s = "equipment off"; break;
             default: s = "unknown"; break;
             }
-            out << "  - status: " << s << endl;
-            out << "    start: " << ts(slice.start) << endl;
-            out << "    end: " << ts(slice.end) << endl;
+            out << "  - status: " << s << '\n';
+            out << "    start: " << ts(slice.start) << '\n';
+            out << "    end: " << ts(slice.end) << '\n';
         }
     }
     qint64 total_time = 0;
@@ -272,9 +272,9 @@ void SessionToYaml(QString filepath, Session* session, bool ok)
         total_time = day.total_time();
         day.removeSession(session);
     }
-    out << "  total_time: " << dur(total_time) << endl;
+    out << "  total_time: " << dur(total_time) << '\n';
 
-    out << "  settings:" << endl;
+    out << "  settings:" << '\n';
 
     // We can't get deterministic ordering from QHash iterators, so we need to create a list
     // of sorted ChannelIDs.
@@ -288,15 +288,15 @@ void SessionToYaml(QString filepath, Session* session, bool ok)
         } else {
             s = value.toString();
         }
-        out << "    " << settingChannel(*key) << ": " << s << endl;
+        out << "    " << settingChannel(*key) << ": " << s << '\n';
     }
 
-    out << "  events:" << endl;
+    out << "  events:" << '\n';
 
     keys = session->eventlist.keys();
     std::sort(keys.begin(), keys.end());
     for (QList<ChannelID>::iterator key = keys.begin(); key != keys.end(); key++) {
-        out << "    " << eventChannel(*key) << ": " << endl;
+        out << "    " << eventChannel(*key) << ": " << '\n';
 
         // Note that this is a vector of lists
         QVector<EventList *> &ev = session->eventlist[*key];
@@ -316,30 +316,30 @@ void SessionToYaml(QString filepath, Session* session, bool ok)
 
         for (int j = 0; j < ev_size; j++) {
             e = *ev[j];
-            out << "    - count: "  << (qint32)e.count() << endl;
+            out << "    - count: "  << (qint32)e.count() << '\n';
             if (e.count() == 0)
                 continue;
-            out << "      first: " << ts(e.first()) << endl;
-            out << "      last: " << ts(e.last()) << endl;
-            out << "      type: " << eventListTypeName(e.type()) << endl;
-            out << "      rate: " << e.rate() << endl;
-            out << "      gain: " << e.gain() << endl;
-            out << "      offset: " << e.offset() << endl;
+            out << "      first: " << ts(e.first()) << '\n';
+            out << "      last: " << ts(e.last()) << '\n';
+            out << "      type: " << eventListTypeName(e.type()) << '\n';
+            out << "      rate: " << e.rate() << '\n';
+            out << "      gain: " << e.gain() << '\n';
+            out << "      offset: " << e.offset() << '\n';
             if (!e.dimension().isEmpty()) {
-                out << "      dimension: " << e.dimension() << endl;
+                out << "      dimension: " << e.dimension() << '\n';
             }
-            out << "      data:" << endl;
-            out << "        min: " << e.Min() << endl;
-            out << "        max: " << e.Max() << endl;
-            out << "        raw: " << intList((EventStoreType*) e.m_data.data(), e.count(), 100) << endl;
+            out << "      data:" << '\n';
+            out << "        min: " << e.Min() << '\n';
+            out << "        max: " << e.Max() << '\n';
+            out << "        raw: " << intList((EventStoreType*) e.m_data.data(), e.count(), 100) << '\n';
             if (e.type() != EVL_Waveform) {
-                out << "        delta: " << intList((quint32*) e.m_time.data(), e.count(), 100) << endl;
+                out << "        delta: " << intList((quint32*) e.m_time.data(), e.count(), 100) << '\n';
             }
             if (e.hasSecondField()) {
-                out << "      data2:" << endl;
-                out << "        min: " << e.min2() << endl;
-                out << "        max: " << e.max2() << endl;
-                out << "        raw: " << intList((EventStoreType*) e.m_data2.data(), e.count(), 100) << endl;
+                out << "      data2:" << '\n';
+                out << "        min: " << e.min2() << '\n';
+                out << "        max: " << e.max2() << '\n';
+                out << "        raw: " << intList((EventStoreType*) e.m_data2.data(), e.count(), 100) << '\n';
             }
         }
     }