changeset 1221:eaab8bab3522

Measure time taken to render per pixel, and use the time last time around to decide whether to be time constrained this time around
author Chris Cannam
date Thu, 26 Jan 2017 11:55:11 +0000
parents 2954e9952b78
children 3ef162c9df00
files layer/Colour3DPlotLayer.cpp layer/Colour3DPlotRenderer.cpp layer/Colour3DPlotRenderer.h layer/RenderTimer.h
diffstat 4 files changed, 81 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/layer/Colour3DPlotLayer.cpp	Thu Jan 26 10:41:50 2017 +0000
+++ b/layer/Colour3DPlotLayer.cpp	Thu Jan 26 11:55:11 2017 +0000
@@ -1110,12 +1110,11 @@
         }
     }
     
-    cerr << "mag range in this view: "
-         << m_viewMags[v->getId()].getMin()
-         << " -> "
-         << m_viewMags[v->getId()].getMax()
-         << endl;
-        
+    SVDEBUG << "Colour3DPlotRenderer::paintWithRenderer: mag range in this view: "
+            << m_viewMags[v->getId()].getMin()
+            << " -> "
+            << m_viewMags[v->getId()].getMax()
+            << endl;
 }
 
 void
--- a/layer/Colour3DPlotRenderer.cpp	Thu Jan 26 10:41:50 2017 +0000
+++ b/layer/Colour3DPlotRenderer.cpp	Thu Jan 26 11:55:11 2017 +0000
@@ -95,14 +95,30 @@
 {
     RenderType renderType = decideRenderType(v);
 
-    if (renderType != DrawBufferPixelResolution) {
-        // Rendering should be fast in bin-resolution and direct draw
-        // cases because we are quite well zoomed-in, and the sums are
-        // easier this way. Calculating boundaries later will be
-        // fiddly for partial paints otherwise.
-        timeConstrained = false;
+    if (timeConstrained) {
+        if (renderType != DrawBufferPixelResolution) {
+            // Rendering should be fast in bin-resolution and direct
+            // draw cases because we are quite well zoomed-in, and the
+            // sums are easier this way. Calculating boundaries later
+            // will be fiddly for partial paints otherwise.
+            timeConstrained = false;
+
+        } else if (m_secondsPerXPixelValid) {
+            double predicted = m_secondsPerXPixel * rect.width();
+#ifdef DEBUG_COLOUR_PLOT_REPAINT
+            SVDEBUG << "Predicted time for width " << rect.width() << " = "
+                    << predicted << endl;
+#endif
+            if (predicted < 0.1) {
+#ifdef DEBUG_COLOUR_PLOT_REPAINT
+                SVDEBUG << "Predicted time looks fast enough: no partial renders"
+                        << endl;
+#endif
+                timeConstrained = false;
+            }
+        }
     }
-
+            
     int x0 = v->getXForViewX(rect.x());
     int x1 = v->getXForViewX(rect.x() + rect.width());
     if (x0 < 0) x0 = 0;
@@ -882,7 +898,7 @@
         step = -1;
     }
 
-    int columnCount = 0;
+    int xPixelCount = 0;
     
     vector<float> preparedColumn;
 
@@ -897,7 +913,7 @@
         // x is the on-canvas pixel coord; sx (later) will be the
         // source column index
         
-        ++columnCount;
+        ++xPixelCount;
         
         if (binforx[x] < 0) continue;
 
@@ -978,16 +994,18 @@
             m_magRanges.push_back(magRange);
         }
 
-        double fractionComplete = double(columnCount) / double(w);
+        double fractionComplete = double(xPixelCount) / double(w);
         if (timer.outOfTime(fractionComplete)) {
 #ifdef DEBUG_COLOUR_PLOT_REPAINT
             SVDEBUG << "out of time" << endl;
 #endif
-            return columnCount;
+            updateTimings(timer, xPixelCount);
+            return xPixelCount;
         }
     }
 
-    return columnCount;
+    updateTimings(timer, xPixelCount);
+    return xPixelCount;
 }
 
 int
@@ -1003,7 +1021,7 @@
     // fft model exists)
     
     RenderTimer timer(timeConstrained ?
-                      RenderTimer::FastRender :
+                      RenderTimer::SlowRender :
                       RenderTimer::NoTimeout);
 
     const FFTModel *fft = m_sources.fft;
@@ -1031,7 +1049,7 @@
         step = -1;
     }
     
-    int columnCount = 0;
+    int xPixelCount = 0;
     
     vector<float> preparedColumn;
 
@@ -1057,7 +1075,7 @@
         // x is the on-canvas pixel coord; sx (later) will be the
         // source column index
         
-        ++columnCount;
+        ++xPixelCount;
         
         if (binforx[x] < 0) continue;
 
@@ -1098,8 +1116,8 @@
         if (!pixelPeakColumn.empty()) {
 
 #ifdef DEBUG_COLOUR_PLOT_REPAINT
-            SVDEBUG << "found " << peakfreqs.size() << " peak freqs at column "
-                    << sx0 << endl;
+//            SVDEBUG << "found " << peakfreqs.size() << " peak freqs at column "
+//                    << sx0 << endl;
 #endif
 
             for (FFTModel::PeakSet::const_iterator pi = peakfreqs.begin();
@@ -1139,16 +1157,32 @@
 #endif
         }
 
-        double fractionComplete = double(columnCount) / double(w);
+        double fractionComplete = double(xPixelCount) / double(w);
         if (timer.outOfTime(fractionComplete)) {
 #ifdef DEBUG_COLOUR_PLOT_REPAINT
             SVDEBUG << "out of time" << endl;
 #endif
-            return columnCount;
+            updateTimings(timer, xPixelCount);
+            return xPixelCount;
         }
     }
 
-    return columnCount;
+    updateTimings(timer, xPixelCount);
+    return xPixelCount;
+}
+
+void
+Colour3DPlotRenderer::updateTimings(const RenderTimer &timer, int xPixelCount)
+{
+    m_secondsPerXPixel = timer.secondsPerItem(xPixelCount);
+    m_secondsPerXPixelValid = (xPixelCount > 10);
+
+#ifdef DEBUG_COLOUR_PLOT_REPAINT
+    SVDEBUG << "seconds per x pixel = " << m_secondsPerXPixel
+            << " (enough data? " << (m_secondsPerXPixelValid ? "yes" : "no")
+            << ")" << endl;
+#endif
+    
 }
 
 void
--- a/layer/Colour3DPlotRenderer.h	Thu Jan 26 10:41:50 2017 +0000
+++ b/layer/Colour3DPlotRenderer.h	Thu Jan 26 11:55:11 2017 +0000
@@ -32,6 +32,7 @@
 class DenseThreeDimensionalModel;
 class Dense3DModelPeakCache;
 class FFTModel;
+class RenderTimer;
 
 enum class BinDisplay {
     AllBins,
@@ -111,7 +112,9 @@
     
     Colour3DPlotRenderer(Sources sources, Parameters parameters) :
         m_sources(sources),
-	m_params(parameters)
+	m_params(parameters),
+        m_secondsPerXPixel(0.0),
+        m_secondsPerXPixelValid(false)
     { }
 
     struct RenderResult {
@@ -263,6 +266,9 @@
     // valid range in the magnitude cache, but not necessarily vice
     // versa (as the image cache is limited to contiguous ranges).
     ScrollableMagRangeCache m_magCache;
+
+    double m_secondsPerXPixel;
+    bool m_secondsPerXPixelValid;
     
     RenderResult render(const LayerGeometryProvider *v,
                         QPainter &paint, QRect rect, bool timeConstrained);
@@ -310,6 +316,8 @@
 
     void getPreferredPeakCache(const LayerGeometryProvider *,
                                int &peakCacheIndex, int &binsPerPeak) const;
+
+    void updateTimings(const RenderTimer &timer, int xPixelCount);
 };
 
 #endif
--- a/layer/RenderTimer.h	Thu Jan 26 10:41:50 2017 +0000
+++ b/layer/RenderTimer.h	Thu Jan 26 11:55:11 2017 +0000
@@ -90,12 +90,22 @@
 	return false;
     }
 
+    double secondsPerItem(int itemsRendered) const {
+
+        if (itemsRendered == 0) return 0.0;
+
+	auto t = std::chrono::steady_clock::now();
+	double elapsed = std::chrono::duration<double>(t - m_start).count();
+
+        return elapsed / itemsRendered;
+    }
+
 private:
     std::chrono::time_point<std::chrono::steady_clock> m_start;
     bool m_haveLimits;
-    double m_minFraction;
-    double m_softLimit;
-    double m_hardLimit;
+    double m_minFraction; // proportion, 0.0 -> 1.0
+    double m_softLimit; // seconds
+    double m_hardLimit; // seconds
     bool m_softLimitOverridden;
 };