# HG changeset patch # User Chris Cannam # Date 1485431711 0 # Node ID eaab8bab352252e8c88fec6e91a6426a39557bfa # Parent 2954e9952b78004a53d4e8cb9acd70470322c80a Measure time taken to render per pixel, and use the time last time around to decide whether to be time constrained this time around diff -r 2954e9952b78 -r eaab8bab3522 layer/Colour3DPlotLayer.cpp --- 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 diff -r 2954e9952b78 -r eaab8bab3522 layer/Colour3DPlotRenderer.cpp --- 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 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 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 diff -r 2954e9952b78 -r eaab8bab3522 layer/Colour3DPlotRenderer.h --- 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 diff -r 2954e9952b78 -r eaab8bab3522 layer/RenderTimer.h --- 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(t - m_start).count(); + + return elapsed / itemsRendered; + } + private: std::chrono::time_point 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; };