[banshee] [extras/metrics] Better analysis



commit 424a345b1cbde80b9bfb15b32580d224df576507
Author: Gabriel Burt <gabriel burt gmail com>
Date:   Sat Feb 27 16:29:19 2010 -0800

    [extras/metrics] Better analysis
    
    Use SqliteModelCache to select the most recent sample for each user
    for each metric.

 extras/metrics/Database.cs        |   16 +++-
 extras/metrics/MetaMetrics.cs     |  177 ++++++++++++++++++++++--------------
 extras/metrics/MultiUserSample.cs |   22 +++--
 3 files changed, 133 insertions(+), 82 deletions(-)
---
diff --git a/extras/metrics/Database.cs b/extras/metrics/Database.cs
index f325702..8bad4ad 100644
--- a/extras/metrics/Database.cs
+++ b/extras/metrics/Database.cs
@@ -41,20 +41,25 @@ namespace metrics
 
         public static HyenaSqliteConnection Open ()
         {
+            HyenaSqliteCommand.LogAll = ApplicationContext.CommandLine.Contains ("debug-sql");
             var db =  new HyenaSqliteConnection (db_path);
             db.Execute ("PRAGMA cache_size = ?", 32768 * 2);
             db.Execute ("PRAGMA synchronous = OFF");
             db.Execute ("PRAGMA temp_store = MEMORY");
             db.Execute ("PRAGMA count_changes = OFF");
+            SampleProvider = new SqliteModelProvider<MultiUserSample> (db, "Samples", true);
             return db;
         }
 
         public static bool Exists { get { return System.IO.File.Exists (db_path); } }
 
+        public static SqliteModelProvider<MultiUserSample> SampleProvider { get; private set; }
+
         public static void Import ()
         {
             using (var db = Open ()) {
-                MultiUserSample.Provider = new SqliteModelProvider<MultiUserSample> (db, "Samples", true);
+                var sample_provider = SampleProvider;
+                db.BeginTransaction ();
                 foreach (var file in System.IO.Directory.GetFiles ("data")) {
                     Log.InformationFormat ("Importing {0}", file);
 
@@ -69,23 +74,21 @@ namespace metrics
                         }
 
                         var metrics = o["Metrics"] as JsonObject;
-                        db.BeginTransaction ();
                         try {
                             foreach (string metric_name in metrics.Keys) {
                                 var samples = metrics[metric_name] as JsonArray;
                                 foreach (JsonArray sample in samples) {
-                                    MultiUserSample.Import (user_id, metric_name, (string)sample[0], (object)sample[1]);
+                                    sample_provider.Save (MultiUserSample.Import (user_id, metric_name, (string)sample[0], (object)sample[1]));
                                 }
                             }
-                            db.CommitTransaction ();
                         } catch {
-                            db.RollbackTransaction ();
                             throw;
                         }
                     } catch (Exception e) {
                         Log.Exception (String.Format ("Failed to read {0}", file), e);
                     }
                 }
+                db.CommitTransaction ();
             }
         }
     }
@@ -123,6 +126,9 @@ namespace metrics
         public override object Final (object contextData)
         {
             var list = contextData as List<T>;
+            if (list == null || list.Count == 0)
+                return null;
+
             list.Sort ();
             return list[list.Count / 2];
         }
diff --git a/extras/metrics/MetaMetrics.cs b/extras/metrics/MetaMetrics.cs
index e4040a7..00ce9a3 100644
--- a/extras/metrics/MetaMetrics.cs
+++ b/extras/metrics/MetaMetrics.cs
@@ -30,51 +30,125 @@ using System.Collections;
 
 namespace metrics
 {
-    public class MetaMetrics
+    public class SampleModel : ICacheableDatabaseModel
     {
-        private HyenaSqliteConnection db;
+        public string ReloadFragment { get; set; }
+        public string SelectAggregates { get; set; }
+        public string JoinTable { get; set; }
+        public string JoinFragment { get; set; }
+        public string JoinPrimaryKey { get; set; }
+        public string JoinColumn { get; set; }
+        public bool CachesJoinTableEntries { get; set; }
+        public bool CachesValues { get; set; }
+
+        public int FetchCount {
+            get { return 10; }
+        }
+        public Hyena.Collections.Selection Selection { get; private set; }
 
-        public DateTime FirstReport { get; private set; }
-        public DateTime LastReport  { get; private set; }
+        public SqliteModelCache<MultiUserSample> Cache { get; private set; }
 
-        public MetaMetrics (HyenaSqliteConnection db)
+        private static int id;
+
+        public SampleModel (string condition, HyenaSqliteConnection db, string aggregates)
         {
-            this.db = db;
-            FirstReport = db.Query<DateTime> ("SELECT Stamp FROM Samples ORDER BY STAMP ASC");
-            LastReport  = db.Query<DateTime> ("SELECT Stamp FROM Samples ORDER BY STAMP DESC");
+            Selection = new Hyena.Collections.Selection ();
+            ReloadFragment = String.Format ("FROM Samples {0}", condition);
+            SelectAggregates = aggregates;
+            Cache = new SqliteModelCache<MultiUserSample> (db, (id++).ToString (), this, Database.SampleProvider);
+        }
 
-            Console.WriteLine ("First report was on {0}", FirstReport);
-            Console.WriteLine ("Last report was on {0}", LastReport);
-            Console.WriteLine ("Total unique users: {0}", db.Query<long> ("SELECT COUNT(DISTINCT(UserId)) FROM Samples"));
+        public void Reload ()
+        {
+            Cache.Reload ();
+            Cache.UpdateAggregates ();
+        }
+    }
 
-            var metrics = db.QueryEnumerable<string> ("SELECT DISTINCT(MetricName) as name FROM Samples ORDER BY name ASC");
+    public class MetricSampleModel : SampleModel
+    {
+        public string MetricName { get; private set; }
 
-            foreach (var metric in metrics) {
-                //var pieces = metric.Split ('/');
-                //var name = pieces[pieces.Length - 1];
+        private string condition;
+        public MetricSampleModel (SqliteModelCache<MultiUserSample> limiter, HyenaSqliteConnection db, string aggregates) : base (null, db, aggregates)
+        {
+            condition = String.Format (
+                "FROM Samples, HyenaCache WHERE Samples.MetricName = '{0}' AND HyenaCache.ModelID = {1} AND Samples.ID = HyenaCache.ItemID",
+                "{0}", limiter.CacheId
+            );
+        }
+
+        public void ChangeMetric (string metricName)
+        {
+            MetricName = metricName;
+            ReloadFragment = String.Format (condition, metricName);
+            Reload ();
+        }
+    }
+
+    public class MetaMetrics
+    {
+        string fmt = "{0,20:N1}";
 
+        public MetaMetrics (HyenaSqliteConnection db)
+        {
+            var latest_samples = new SampleModel ("GROUP BY UserID, MetricName ORDER BY stamp desc", db, "COUNT(DISTINCT(UserID)), MIN(Stamp), MAX(Stamp)");
+            latest_samples.Cache.AggregatesUpdated += (reader) => {
+                Console.WriteLine ("Total unique users for this time slice: {0}", reader[1]);
+                Console.WriteLine ("First report was on {0}", SqliteUtils.FromDbFormat (typeof(DateTime), reader[2]));
+                Console.WriteLine ("Last report was on {0}", SqliteUtils.FromDbFormat (typeof(DateTime), reader[3]));
+                Console.WriteLine ();
+            };
+            latest_samples.Reload ();
+
+            var string_summary = new MetricSampleModel (latest_samples.Cache, db,
+                @"COUNT(DISTINCT(UserID))"
+            );
+            string_summary.Cache.AggregatesUpdated += (agg_reader) => {
+                Console.WriteLine (String.Format ("   Users:  {0}", fmt), agg_reader[1]);
+                using (var reader = new HyenaDataReader (db.Query (
+                    @"SELECT COUNT(DISTINCT(UserId)) as users, Value FROM Samples, HyenaCache
+                        WHERE MetricName = ? AND HyenaCache.ModelID = ? AND HyenaCache.ItemID = Samples.ID
+                        GROUP BY Value ORDER BY users DESC", string_summary.MetricName, string_summary.Cache.CacheId))) {
+                    while (reader.Read ()) {
+                        Console.WriteLine ("   {0,-5}: {1,-20}", reader.Get<long> (0), reader.Get<string> (1));
+                    }
+                }
+            };
+
+            var numeric_slice = new MetricSampleModel (latest_samples.Cache, db,
+                @"MIN(CAST(Value as NUMERIC)), MAX(CAST(Value as NUMERIC)),
+                  AVG(CAST(Value as NUMERIC)), HYENA_METRICS_MEDIAN_DOUBLE(CAST(Value as NUMERIC)), COUNT(DISTINCT(UserID))"
+            );
+
+            numeric_slice.Cache.AggregatesUpdated += (reader) => {
+                Console.WriteLine (String.Format ("   Users:  {0}", fmt), reader[5]);
+                Console.WriteLine (String.Format ("   Min:    {0}", fmt), reader[1]);
+                Console.WriteLine (String.Format ("   Avg:    {0}", fmt), reader[3]);
+                Console.WriteLine (String.Format ("   Median: {0}", fmt), reader[4]);
+                Console.WriteLine (String.Format ("   Max:    {0}", fmt), reader[2]);
+                Console.WriteLine ();
+            };
+            
+            var metrics = db.QueryEnumerable<string> ("SELECT DISTINCT(MetricName) as name FROM Samples ORDER BY name ASC");
+            foreach (var metric in metrics) {
                 switch (GetMetricType (metric)) {
-                    case "string": SummarizeTextual (metric); break;
-                    case "timespan" : SummarizeNumeric<TimeSpan> (metric); break;
-                    case "datetime" : SummarizeNumeric<DateTime> (metric); break;
-                    case "fixed": SummarizeNumeric<long> (metric); break;
-                    case "float": SummarizeNumeric<double> (metric); break;
+                case "string":
+                    Console.WriteLine ("{0}:", metric);
+                    string_summary.ChangeMetric (metric);
+                    break;
+                //case "timespan" : SummarizeNumeric<TimeSpan> (metric); break;
+                //case "datetime" : SummarizeNumeric<DateTime> (metric); break;
+                case "float":
+                    Console.WriteLine ("{0}:", metric);
+                    //SummarizeNumeric<long> (metric_cache);
+                    numeric_slice.ChangeMetric (metric);
+                    break;
+                //case "float":
+                    //SummarizeNumeric<double> (metric_cache);
+                    //break;
                 }
             }
-
-            /*SummarizeTextual ("Env/CultureInfo");
-            SummarizeTextual ("Banshee/Configuration/core/io_provider");
-
-            SummarizeNumeric<TimeSpan> ("Banshee/RunDuration");
-
-            SummarizeNumeric<long> ("Banshee/Screen/Width");
-            SummarizeNumeric<long> ("Banshee/Screen/Height");
-            SummarizeNumeric<long> ("Banshee/Screen/NMonitors");
-            SummarizeTextual ("Banshee/Screen/IsComposited");*/
-
-            /*foreach (var metric in db.QueryEnumerable<string> ("SELECT DISTINCT(MetricName) as name FROM Samples ORDER BY name ASC")) {
-                Console.WriteLine (metric);
-            }*/
         }
 
         private string GetMetricType (string name)
@@ -93,40 +167,5 @@ namespace metrics
 
             return "string";
         }
-
-        private void SummarizeNumeric<T> (string metric_name)
-        {
-            Console.WriteLine ("{0}:", metric_name);
-            var t = typeof(T);
-            string fmt = t == typeof(DateTime) ? "{0}" : "{0,10:N1}";
-            string median_func = "HYENA_METRICS_MEDIAN_" + (t == typeof(DateTime) ? "DATETIME" : t == typeof(long) ? "LONG" : "DOUBLE");
-
-            using (var reader = new HyenaDataReader (db.Query (String.Format (@"
-                    SELECT
-                        MIN(CAST(Value as NUMERIC)), MAX(CAST(Value as NUMERIC)),
-                        AVG(CAST(Value as NUMERIC)), {0}(CAST(Value as NUMERIC))
-                    FROM Samples WHERE MetricName = ?", median_func), metric_name))) {
-                if (reader.Read ()) {
-                    Console.WriteLine (String.Format ("   Min:    {0}", fmt), reader.Get<T> (0));
-                    Console.WriteLine (String.Format ("   Avg:    {0}", fmt), reader.Get<T> (2));
-                    Console.WriteLine (String.Format ("   Median: {0}", fmt), reader.Get<T> (3));
-                    Console.WriteLine (String.Format ("   Max:    {0}", fmt), reader.Get<T> (1));
-                }
-            }
-
-            Console.WriteLine ();
-        }
-
-        private void SummarizeTextual (string metric_name)
-        {
-            Console.WriteLine ("{0}:", metric_name);
-            //Console.WriteLine ("   Unique Values: {0,-20}", db.Query<long> ("SELECT COUNT(DISTINCT(Value)) FROM Samples WHERE MetricName = ?", metric_name));
-            using (var reader = new HyenaDataReader (db.Query ("SELECT COUNT(DISTINCT(UserId)) as users, Value FROM Samples WHERE MetricName = ? GROUP BY Value ORDER BY users DESC", metric_name))) {
-                while (reader.Read ()) {
-                    Console.WriteLine ("   {0,-5}: {1,-20}", reader.Get<long> (0), reader.Get<string> (1));
-                }
-            }
-            Console.WriteLine ();
-        }
     }
 }
\ No newline at end of file
diff --git a/extras/metrics/MultiUserSample.cs b/extras/metrics/MultiUserSample.cs
index 0eac2c8..8fd2f0d 100644
--- a/extras/metrics/MultiUserSample.cs
+++ b/extras/metrics/MultiUserSample.cs
@@ -33,30 +33,36 @@ using Hyena.Json;
 
 namespace metrics
 {
-    public class MultiUserSample : Sample
+    public class MultiUserSample : Sample, Hyena.Data.ICacheableItem
     {
-        public static SqliteModelProvider<MultiUserSample> Provider;
-
-        [DatabaseColumn]
+        [DatabaseColumn (Index = "SampleUserIdIndex")]
         public string UserId;
 
+        // ICacheableItem
+        public object CacheEntryId { get; set; }
+        public long CacheModelId { get; set; }
+
         public MultiUserSample ()
         {
         }
 
         static DateTime value_dt;
         static TimeSpan value_span;
-        public static void Import (string user_id, string metric_name, string stamp, object val)
+        public static MultiUserSample Import (string user_id, string metric_name, string stamp, object val)
         {
             var sample = new MultiUserSample ();
             sample.UserId = user_id;
+
+            // TODO collapse various DAP and DAAP library stats?
             sample.MetricName = metric_name;
 
             DateTime stamp_dt;
-            if (DateTimeUtil.TryParseInvariant (stamp, out stamp_dt)) {
-                sample.Stamp = stamp_dt;
+            if (!DateTimeUtil.TryParseInvariant (stamp, out stamp_dt)) {
+                Hyena.Log.Error ("Invalid stamp: ", stamp);
+                return null;
             }
 
+            sample.Stamp = stamp_dt;
 
             string value_str = val as string;
             if (value_str != null) {
@@ -72,7 +78,7 @@ namespace metrics
                 sample.SetValue (val);
             }
 
-            Provider.Save (sample);
+            return sample;
         }
     }
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]