diff layer/RenderTimer.h @ 1074:6f98aa5291d4 spectrogram-minor-refactor

Pull out render timer
author Chris Cannam
date Wed, 29 Jun 2016 14:04:57 +0100
parents
children eaab8bab3522
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/layer/RenderTimer.h	Wed Jun 29 14:04:57 2016 +0100
@@ -0,0 +1,102 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef RENDER_TIMER_H
+#define RENDER_TIMER_H
+
+#include <chrono>
+
+class RenderTimer
+{
+public:
+    enum Type {
+	/// A normal rendering operation with normal responsiveness demands
+	FastRender,
+
+	/// An operation that the user might accept being slower
+	SlowRender,
+
+	/// An operation that should always complete, i.e. as if there
+	/// were no RenderTimer in use, but without having to change
+	/// client code structurally
+	NoTimeout
+    };
+    
+    /**
+     * Create a new RenderTimer and start timing. Make one of these
+     * before rendering, and then call outOfTime() regularly during
+     * rendering. If outOfTime() returns true, abandon rendering!  and
+     * schedule the rest for after some user responsiveness has
+     * happened.
+     */
+    RenderTimer(Type t) :
+	m_start(std::chrono::steady_clock::now()),
+	m_haveLimits(true),
+	m_minFraction(0.1),
+	m_softLimit(0.1),
+	m_hardLimit(0.2),
+	m_softLimitOverridden(false) {
+
+	if (t == NoTimeout) {
+	    m_haveLimits = false;
+	} else if (t == SlowRender) {
+	    m_softLimit = 0.2;
+	    m_hardLimit = 0.4;
+	}
+    }
+
+
+    /**
+     * Return true if we have run out of time and should suspend
+     * rendering and handle user events instead. Call this regularly
+     * during rendering work: fractionComplete should be an estimate
+     * of how much of the work has been done as of this call, as a
+     * number between 0.0 (none of it) and 1.0 (all of it).
+     */
+    bool outOfTime(double fractionComplete) {
+
+	if (!m_haveLimits || fractionComplete < m_minFraction) {
+	    return false;
+	}
+	
+	auto t = std::chrono::steady_clock::now();
+	double elapsed = std::chrono::duration<double>(t - m_start).count();
+	
+	if (elapsed > m_hardLimit) {
+	    return true;
+	} else if (!m_softLimitOverridden && elapsed > m_softLimit) {
+	    if (fractionComplete > 0.6) {
+		// If we're significantly more than half way by the
+		// time we reach the soft limit, ignore it (though
+		// always respect the hard limit, above). Otherwise
+		// respect the soft limit and report out of time now.
+		m_softLimitOverridden = true;
+	    } else {
+		return true;
+	    }
+	}
+
+	return false;
+    }
+
+private:
+    std::chrono::time_point<std::chrono::steady_clock> m_start;
+    bool m_haveLimits;
+    double m_minFraction;
+    double m_softLimit;
+    double m_hardLimit;
+    bool m_softLimitOverridden;
+};
+
+#endif