A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using System;
5using System.Collections.Specialized;
6using System.Linq;
7using osu.Framework.Bindables;
8using osu.Framework.Logging;
9
10namespace osu.Framework.Statistics
11{
12 /// <summary>
13 /// A store that can be used to track application-wide statistics and monitor runtime components.
14 /// </summary>
15 public static class GlobalStatistics
16 {
17 /// <summary>
18 /// An event which is raised when the available statistics change.
19 /// </summary>
20 internal static event NotifyCollectionChangedEventHandler StatisticsChanged;
21
22 private static readonly BindableList<IGlobalStatistic> statistics = new BindableList<IGlobalStatistic>();
23
24 static GlobalStatistics()
25 {
26 statistics.BindCollectionChanged((o, e) => StatisticsChanged?.Invoke(o, e));
27 }
28
29 /// <summary>
30 /// Retrieve a <see cref="IGlobalStatistic"/> of specified type.
31 /// If no matching statistic already exists, a new instance is created and registered automatically.
32 /// </summary>
33 /// <param name="group">The group specification.</param>
34 /// <param name="name">The name specification.</param>
35 /// <typeparam name="T">The type.</typeparam>
36 public static GlobalStatistic<T> Get<T>(string group, string name)
37 {
38 lock (statistics)
39 {
40 var existing = statistics.OfType<GlobalStatistic<T>>().FirstOrDefault(s => s.Name == name && s.Group == group);
41 if (existing != null)
42 return existing;
43
44 var newStat = new GlobalStatistic<T>(group, name);
45 register(newStat);
46 return newStat;
47 }
48 }
49
50 /// <summary>
51 /// Clear all statistics.
52 /// </summary>
53 /// <param name="group">An optional group identifier, limiting the clear operation to the matching group.</param>
54 public static void Clear(string group = null)
55 {
56 lock (statistics)
57 {
58 for (int i = 0; i < statistics.Count; i++)
59 {
60 if (group?.Equals(statistics[i].Group, StringComparison.Ordinal) != false)
61 statistics.RemoveAt(i--);
62 }
63 }
64 }
65
66 /// <summary>
67 /// Remove a specific statistic.
68 /// </summary>
69 /// <param name="statistic">The statistic to remove.</param>
70 public static void Remove(IGlobalStatistic statistic)
71 {
72 lock (statistics)
73 statistics.Remove(statistic);
74 }
75
76 /// <summary>
77 /// Register a new statistic type.
78 /// </summary>
79 /// <param name="stat">The statistic to register.</param>
80 private static void register(IGlobalStatistic stat)
81 {
82 lock (statistics)
83 statistics.Add(stat);
84 }
85
86 public static void OutputToLog()
87 {
88 var statisticsSnapshot = GetStatistics();
89
90 Logger.Log("----- Global Statistics -----", LoggingTarget.Performance);
91
92 foreach (var group in statisticsSnapshot.GroupBy(s => s.Group))
93 {
94 Logger.Log($"# {group.Key}", LoggingTarget.Performance);
95
96 foreach (var i in group)
97 Logger.Log($"{i.Name.PadRight(30)}: {i.DisplayValue}", LoggingTarget.Performance);
98 }
99
100 Logger.Log("--- Global Statistics End ---", LoggingTarget.Performance);
101 }
102
103 internal static IGlobalStatistic[] GetStatistics()
104 {
105 lock (statistics)
106 return statistics.ToArray();
107 }
108 }
109}