changeset 170:b23eea68357e

* flesh out StorageAdviser
author Chris Cannam
date Tue, 26 Sep 2006 12:58:12 +0000
parents 603991c63ff6
children ebf55cf0d34d
files base/StorageAdviser.cpp base/StorageAdviser.h base/TempDirectory.cpp data/fft/FFTDataServer.cpp data/fft/FFTFileCache.cpp data/fft/FFTFileCache.h data/fft/FFTMemoryCache.cpp data/fft/FFTMemoryCache.h system/System.cpp system/System.h
diffstat 10 files changed, 197 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/base/StorageAdviser.cpp	Mon Sep 25 20:32:44 2006 +0000
+++ b/base/StorageAdviser.cpp	Tue Sep 26 12:58:12 2006 +0000
@@ -27,15 +27,118 @@
 			  int minimumSize,
 			  int maximumSize)
 {
+    std::cerr << "StorageAdviser::recommend: Criteria " << criteria 
+              << ", minimumSize " << minimumSize
+              << ", maximumSize " << maximumSize << std::endl;
+
     QString path = TempDirectory::getInstance()->getPath();
+    int discFree = GetDiscSpaceMBAvailable(path.toLocal8Bit());
+    int memoryFree, memoryTotal;
+    GetRealMemoryMBAvailable(memoryFree, memoryTotal);
 
-    int discSpace = GetDiscSpaceMBAvailable(path.toLocal8Bit());
-    int memory = GetRealMemoryMBAvailable();
+    std::cerr << "Disc space: " << discFree << ", memory free: " << memoryFree << ", memory total: " << memoryTotal << std::endl;
 
-    std::cerr << "Disc space: " << discSpace << ", memory: " << memory << std::endl;
+    enum StorageStatus {
+        Unknown,
+        Insufficient,
+        Marginal,
+        Sufficient
+    };
 
-    return Recommendation(0);
+    StorageStatus memoryStatus = Unknown;
+    StorageStatus discStatus = Unknown;
+
+    int minmb = minimumSize / 1024 + 1;
+    int maxmb = maximumSize / 1024 + 1;
+
+    if (memoryFree == -1) memoryStatus = Unknown;
+    else if (minmb > (memoryFree * 3) / 4) memoryStatus = Insufficient;
+    else if (maxmb > (memoryFree * 3) / 4) memoryStatus = Marginal;
+    else if (minmb > (memoryFree / 3)) memoryStatus = Marginal;
+    else if (memoryTotal == -1 ||
+             minmb > (memoryTotal / 10)) memoryStatus = Marginal;
+    else memoryStatus = Sufficient;
+
+    if (discFree == -1) discStatus = Unknown;
+    else if (minmb > (discFree * 3) / 4) discStatus = Insufficient;
+    else if (maxmb > (discFree * 3) / 4) discStatus = Marginal;
+    else if (minmb > (discFree / 3)) discStatus = Marginal;
+    else discStatus = Sufficient;
+
+    std::cerr << "Memory status: " << memoryStatus << ", disc status "
+              << discStatus << std::endl;
+
+    int recommendation = NoRecommendation;
+
+    if (memoryStatus == Insufficient || memoryStatus == Unknown) {
+
+        recommendation |= UseDisc;
+
+        if (discStatus == Insufficient && minmb > discFree) {
+            throw InsufficientDiscSpace(path, minmb, discFree);
+        }
+
+        if (discStatus == Insufficient || discStatus == Marginal) {
+            recommendation |= ConserveSpace;
+        } else if (discStatus == Unknown && !(criteria & PrecisionCritical)) {
+            recommendation |= ConserveSpace;
+        } else {
+            recommendation |= UseAsMuchAsYouLike;
+        }
+
+    } else if (memoryStatus == Marginal) {
+
+        if (((criteria & SpeedCritical) ||
+             (criteria & FrequentLookupLikely)) &&
+            !(criteria & PrecisionCritical) &&
+            !(criteria & LongRetentionLikely)) {
+
+            // requirements suggest a preference for memory
+
+            if (discStatus != Insufficient) {
+                recommendation |= PreferMemory;
+            } else {
+                recommendation |= UseMemory;
+            }
+
+            recommendation |= ConserveSpace;
+
+        } else {
+
+            if (discStatus == Insufficient) {
+                recommendation |= (UseMemory | ConserveSpace);
+            } else if (discStatus == Marginal) {
+                recommendation |= (PreferMemory | ConserveSpace);
+            } else if (discStatus == Unknown) {
+                recommendation |= (PreferDisc | ConserveSpace);
+            } else {
+                recommendation |= (UseDisc | UseAsMuchAsYouLike);
+            }
+        }    
+
+    } else {
+
+        if (discStatus == Insufficient) {
+            recommendation |= (UseMemory | ConserveSpace);
+        } else if (discStatus != Sufficient) {
+            recommendation |= (PreferMemory | ConserveSpace);
+        } else {
+
+            if ((criteria & SpeedCritical) ||
+                (criteria & FrequentLookupLikely)) {
+                recommendation |= PreferMemory;
+                if (criteria & PrecisionCritical) {
+                    recommendation |= UseAsMuchAsYouLike;
+                } else {
+                    recommendation |= ConserveSpace;
+                }
+            } else {
+                recommendation |= PreferDisc;
+                recommendation |= UseAsMuchAsYouLike;
+            }
+        }
+    }
+
+    return Recommendation(recommendation);
 }
 
-
-    
--- a/base/StorageAdviser.h	Mon Sep 25 20:32:44 2006 +0000
+++ b/base/StorageAdviser.h	Tue Sep 26 12:58:12 2006 +0000
@@ -19,6 +19,7 @@
 /**
  * A utility class designed to help decide whether to store cache data
  * (for example FFT outputs) in memory or on disk in the TempDirectory.
+ * This is basically a compendium of simple rules of thumb.
  */
 
 class StorageAdviser
@@ -26,29 +27,33 @@
 public:
     // pass to recommend() zero or more of these OR'd together
     enum Criteria {
-        SpeedCritical       = 1,
-        PrecisionCritical   = 2,
-        RepeatabilityUseful = 4
+        NoCriteria           = 0,
+        SpeedCritical        = 1,
+        PrecisionCritical    = 2,
+        LongRetentionLikely  = 4,
+        FrequentLookupLikely = 8
     };
 
     // recommend() returns one or two of these OR'd together
     enum Recommendation {
-        UseMemory          = 1,
-        UseDisc            = 2,
-        ConserveSpace      = 4,
-        UseAsMuchAsYouLike = 8
+        NoRecommendation   = 0,
+        UseMemory          = 1, // Disc is strongly contraindicated
+        PreferMemory       = 2, // Either would do; memory probably better
+        PreferDisc         = 4, // Either would do; disc probably better
+        UseDisc            = 8, // Probably won't fit in memory
+        ConserveSpace      = 16,// Whatever you choose, keep it compact
+        UseAsMuchAsYouLike = 32 // Take my advice and there'll be space for all
     };
 
-    // May throw InsufficientDiscSpace exception if it looks like
-    // minimumSize won't fit on the disc.  
-
     /**
      * Recommend where to store some data, given certain storage and
      * recall criteria.  The minimum size is the approximate amount of
-     * data in bytes that will be stored if the recommendation is to
-     * ConserveSpace; the maximum size is approximately the amount
+     * data in kilobytes that will be stored if the recommendation is
+     * to ConserveSpace; the maximum size is approximately the amount
      * that will be used if UseAsMuchAsYouLike is returned.
-     **!!! sizes should be longer types
+     *
+     * May throw InsufficientDiscSpace exception if there appears to
+     * be nowhere the minimum amount of data can be stored.
      */
     static Recommendation recommend(Criteria criteria,
                                     int minimumSize,
--- a/base/TempDirectory.cpp	Mon Sep 25 20:32:44 2006 +0000
+++ b/base/TempDirectory.cpp	Tue Sep 26 12:58:12 2006 +0000
@@ -20,6 +20,7 @@
 #include <QDir>
 #include <QFile>
 #include <QMutexLocker>
+#include <QSettings>
 
 #include <iostream>
 #include <cassert>
@@ -58,16 +59,23 @@
     
     if (m_tmpdir != "") return m_tmpdir;
 
+    QSettings settings;
+    settings.beginGroup("TempDirectory");
+    QString svDirParent = settings.value("create-in", "$HOME").toString();
+    settings.endGroup();
+
+    svDirParent.replace("$HOME", QDir::home().absolutePath());
+
     QString svDirBase = ".sv1";
-    QString svDir = QDir::home().filePath(svDirBase);
+    QString svDir = QDir(svDirParent).filePath(svDirBase);
     if (!QFileInfo(svDir).exists()) {
-        if (!QDir::home().mkdir(svDirBase)) {
-            throw DirectoryCreationFailed(QString("%1 directory in $HOME")
-                                          .arg(svDirBase));
+        if (!QDir(svDirParent).mkdir(svDirBase)) {
+            throw DirectoryCreationFailed(QString("%1 directory in %2")
+                                          .arg(svDirBase).arg(svDirParent));
         }
     } else if (!QFileInfo(svDir).isDir()) {
-        throw DirectoryCreationFailed(QString("$HOME/%1 is not a directory")
-                                      .arg(svDirBase));
+        throw DirectoryCreationFailed(QString("%1/%2 is not a directory")
+                                      .arg(svDirParent).arg(svDirBase));
     }
 
     cleanupAbandonedDirectories(svDir);
--- a/data/fft/FFTDataServer.cpp	Mon Sep 25 20:32:44 2006 +0000
+++ b/data/fft/FFTDataServer.cpp	Tue Sep 26 12:58:12 2006 +0000
@@ -75,12 +75,19 @@
         return server;
     }
 
+    StorageAdviser::Criteria criteria =
+        StorageAdviser::Criteria
+        (StorageAdviser::SpeedCritical | StorageAdviser::LongRetentionLikely);
 
-    //!!!
+    int cells = fftSize * ((model->getEndFrame() - model->getStartFrame())
+                           / windowIncrement + 1);
+    int minimumSize = (cells / 1024) * sizeof(uint16_t); // kb
+    int maximumSize = (cells / 1024) * sizeof(float); // kb
+    
+    StorageAdviser::Recommendation recommendation =
+        StorageAdviser::recommend(criteria, minimumSize, maximumSize);
 
-    StorageAdviser::Recommendation recommendation =
-        StorageAdviser::recommend(StorageAdviser::Criteria(0), 0, 0);
-
+    std::cerr << "Recommendation was: " << recommendation << std::endl;
 
     m_servers[n] = ServerCountPair
         (new FFTDataServer(n,
--- a/data/fft/FFTFileCache.cpp	Mon Sep 25 20:32:44 2006 +0000
+++ b/data/fft/FFTFileCache.cpp	Tue Sep 26 12:58:12 2006 +0000
@@ -286,3 +286,11 @@
     m_mfc->setColumnAt(x, m_writebuf);
 }
 
+size_t
+FFTFileCache::getCacheSize(size_t width, size_t height, StorageType type)
+{
+    return (height * 2 + 1) * width *
+        (type == Compact ? sizeof(uint16_t) : sizeof(float)) +
+        2 * sizeof(size_t); // matrix file header size
+}
+
--- a/data/fft/FFTFileCache.h	Mon Sep 25 20:32:44 2006 +0000
+++ b/data/fft/FFTFileCache.h	Tue Sep 26 12:58:12 2006 +0000
@@ -56,6 +56,8 @@
 
     virtual void suspend() { m_mfc->suspend(); }
 
+    static size_t getCacheSize(size_t width, size_t height, StorageType type);
+
 protected:
     char *m_writebuf;
     mutable char *m_readbuf;
--- a/data/fft/FFTMemoryCache.cpp	Mon Sep 25 20:32:44 2006 +0000
+++ b/data/fft/FFTMemoryCache.cpp	Tue Sep 26 12:58:12 2006 +0000
@@ -113,3 +113,9 @@
     setColumnAt(x, reals, imags, max);
 }
 
+size_t
+FFTMemoryCache::getCacheSize(size_t width, size_t height)
+{
+    return (height * 2 + 1) * width * sizeof(uint16_t);
+}
+
--- a/data/fft/FFTMemoryCache.h	Mon Sep 25 20:32:44 2006 +0000
+++ b/data/fft/FFTMemoryCache.h	Tue Sep 26 12:58:12 2006 +0000
@@ -112,6 +112,8 @@
 
     virtual void setColumnAt(size_t x, float *reals, float *imags);
 
+    static size_t getCacheSize(size_t width, size_t height);
+
 private:
     size_t m_width;
     size_t m_height;
--- a/system/System.cpp	Mon Sep 25 20:32:44 2006 +0000
+++ b/system/System.cpp	Tue Sep 26 12:58:12 2006 +0000
@@ -18,6 +18,8 @@
 #include <QStringList>
 #include <QString>
 
+#include <stdint.h>
+
 #ifndef _WIN32
 #include <signal.h>
 #include <sys/statvfs.h>
@@ -74,17 +76,21 @@
 #endif
 }
 
-int
-GetRealMemoryMBAvailable()
+void
+GetRealMemoryMBAvailable(int &available, int &total)
 {
+    available = -1;
+    total = -1;
+
     FILE *meminfo = fopen("/proc/meminfo", "r");
-    if (!meminfo) return -1;
+    if (!meminfo) return;
 
     char buf[256];
     while (!feof(meminfo)) {
         fgets(buf, 256, meminfo);
-        if (strncmp(buf, "MemFree:", 8)) {
-            fclose(meminfo);
+        bool isMemFree = (strncmp(buf, "MemFree:", 8) == 0);
+        bool isMemTotal = (!isMemFree && (strncmp(buf, "MemTotal:", 9) == 0));
+        if (isMemFree || isMemTotal) {
             QString line = QString(buf).trimmed();
             QStringList elements = line.split(' ', QString::SkipEmptyParts);
             QString unit = "kB";
@@ -92,14 +98,20 @@
             int size = elements[1].toInt();
 //            std::cerr << "have size \"" << size << "\", unit \""
 //                      << unit.toStdString() << "\"" << std::endl;
-            if (unit.toLower() == "gb") return size * 1024;
-            if (unit.toLower() == "mb") return size;
-            if (unit.toLower() == "kb") return size / 1024;
-            return size / 1048576;
+            if (unit.toLower() == "gb") size = size * 1024;
+            else if (unit.toLower() == "mb") size = size;
+            else if (unit.toLower() == "kb") size = size / 1024;
+            else size = size / 1048576;
+
+            if (isMemFree) available = size;
+            else total = size;
+        }
+        if (available != -1 && total != -1) {
+            fclose(meminfo);
+            return;
         }
     }
     fclose(meminfo);
-    return -1;
 }
 
 int
@@ -109,6 +121,7 @@
     __int64 available, total, totalFree;
     if (GetDiskFreeSpaceEx(path, &available, &total, &totalFree)) {
         available /= 1048576;
+        if (available > INT_MAX) available = INT_MAX;
         return int(available);
     } else {
         std::cerr << "WARNING: GetDiskFreeSpaceEx failed: error code "
@@ -121,7 +134,9 @@
         // do the multiplies and divides in this order to reduce the
         // likelihood of arithmetic overflow
         std::cerr << "statvfs(" << path << ") says available: " << buf.f_bavail << ", block size: " << buf.f_bsize << std::endl;
-        return ((buf.f_bavail / 1024) * buf.f_bsize) / 1024;
+        uint64_t available = ((buf.f_bavail / 1024) * buf.f_bsize) / 1024;
+        if (available > INT_MAX) available = INT_MAX;
+        return int(available);
     } else {
         perror("statvfs failed");
         return -1;
--- a/system/System.h	Mon Sep 25 20:32:44 2006 +0000
+++ b/system/System.h	Tue Sep 26 12:58:12 2006 +0000
@@ -77,7 +77,7 @@
 
 // Return a vague approximation to the number of free megabytes of real memory.
 // Return -1 if unknown.
-extern int GetRealMemoryMBAvailable();
+extern void GetRealMemoryMBAvailable(int &available, int &total);
 
 // Return a vague approximation to the number of free megabytes of disc space
 // on the partition containing the given path.  Return -1 if unknown.