| author | paulson <lp15@cam.ac.uk> | 
| Tue, 19 Sep 2017 16:37:19 +0100 | |
| changeset 66660 | bc3584f7ac0c | 
| parent 65866 | 00e8b836d4db | 
| child 67760 | 553d9ad7d679 | 
| permissions | -rw-r--r-- | 
| 65477 | 1 | /* Title: Pure/ML/ml_statistics.scala | 
| 50685 | 2 | Author: Makarius | 
| 3 | ||
| 4 | ML runtime statistics. | |
| 5 | */ | |
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 65858 | 10 | import scala.annotation.tailrec | 
| 51432 | 11 | import scala.collection.mutable | 
| 50688 
f02864682307
some support for ML statistics content interpretation;
 wenzelm parents: 
50685diff
changeset | 12 | import scala.collection.immutable.{SortedSet, SortedMap}
 | 
| 50691 | 13 | import scala.swing.{Frame, Component}
 | 
| 50688 
f02864682307
some support for ML statistics content interpretation;
 wenzelm parents: 
50685diff
changeset | 14 | |
| 50689 | 15 | import org.jfree.data.xy.{XYSeries, XYSeriesCollection}
 | 
| 16 | import org.jfree.chart.{JFreeChart, ChartPanel, ChartFactory}
 | |
| 17 | import org.jfree.chart.plot.PlotOrientation | |
| 18 | ||
| 50688 
f02864682307
some support for ML statistics content interpretation;
 wenzelm parents: 
50685diff
changeset | 19 | |
| 50685 | 20 | object ML_Statistics | 
| 21 | {
 | |
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 22 | /* properties */ | 
| 50690 | 23 | |
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 24 |   val Now = new Properties.Double("now")
 | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 25 | def now(props: Properties.T): Double = Now.unapply(props).get | 
| 50697 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 26 | |
| 50690 | 27 | |
| 65866 | 28 | /* heap */ | 
| 50690 | 29 | |
| 65858 | 30 | val HEAP_SIZE = "size_heap" | 
| 31 | ||
| 65866 | 32 | def heap_scale(x: Long): Long = x / 1024 / 1024 | 
| 33 | def heap_scale(x: Double): Double = heap_scale(x.toLong).toLong | |
| 34 | ||
| 35 | ||
| 36 | /* standard fields */ | |
| 37 | ||
| 65864 | 38 | type Fields = (String, List[String]) | 
| 65051 | 39 | |
| 40 | val tasks_fields: Fields = | |
| 60610 
f52b4b0c10c4
improved scheduling for urgent tasks, using farm of replacement threads (may lead to factor 2 overloading, but CPUs are usually hyperthreaded);
 wenzelm parents: 
57869diff
changeset | 41 |     ("Future tasks",
 | 
| 
f52b4b0c10c4
improved scheduling for urgent tasks, using farm of replacement threads (may lead to factor 2 overloading, but CPUs are usually hyperthreaded);
 wenzelm parents: 
57869diff
changeset | 42 |       List("tasks_ready", "tasks_pending", "tasks_running", "tasks_passive", "tasks_urgent"))
 | 
| 57869 | 43 | |
| 65051 | 44 | val workers_fields: Fields = | 
| 57869 | 45 |     ("Worker threads", List("workers_total", "workers_active", "workers_waiting"))
 | 
| 46 | ||
| 65051 | 47 | val GC_fields: Fields = | 
| 48 |     ("GCs", List("partial_GCs", "full_GCs"))
 | |
| 50690 | 49 | |
| 65051 | 50 | val heap_fields: Fields = | 
| 65858 | 51 |     ("Heap", List(HEAP_SIZE, "size_allocation", "size_allocation_free",
 | 
| 50690 | 52 | "size_heap_free_last_full_GC", "size_heap_free_last_GC")) | 
| 53 | ||
| 65051 | 54 | val threads_fields: Fields = | 
| 50690 | 55 |     ("Threads", List("threads_total", "threads_in_ML", "threads_wait_condvar",
 | 
| 56 | "threads_wait_IO", "threads_wait_mutex", "threads_wait_signal")) | |
| 57 | ||
| 65051 | 58 | val time_fields: Fields = | 
| 59 |     ("Time", List("time_CPU", "time_GC"))
 | |
| 51432 | 60 | |
| 65051 | 61 | val speed_fields: Fields = | 
| 62 |     ("Speed", List("speed_CPU", "speed_GC"))
 | |
| 50690 | 63 | |
| 65053 | 64 | |
| 65 | val all_fields: List[Fields] = | |
| 57869 | 66 | List(tasks_fields, workers_fields, GC_fields, heap_fields, threads_fields, | 
| 67 | time_fields, speed_fields) | |
| 65053 | 68 | |
| 69 | val main_fields: List[Fields] = | |
| 70 | List(tasks_fields, workers_fields, heap_fields) | |
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 71 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 72 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 73 | /* content interpretation */ | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 74 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 75 | final case class Entry(time: Double, data: Map[String, Double]) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 76 |   {
 | 
| 65858 | 77 | def get(field: String): Double = data.getOrElse(field, 0.0) | 
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 78 | } | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 79 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 80 | val empty: ML_Statistics = apply(Nil) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 81 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 82 | def apply(ml_statistics: List[Properties.T], heading: String = ""): ML_Statistics = | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 83 |   {
 | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 84 | require(ml_statistics.forall(props => Now.unapply(props).isDefined)) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 85 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 86 | val time_start = if (ml_statistics.isEmpty) 0.0 else now(ml_statistics.head) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 87 | val duration = if (ml_statistics.isEmpty) 0.0 else now(ml_statistics.last) - time_start | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 88 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 89 | val fields = | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 90 | SortedSet.empty[String] ++ | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 91 | (for (props <- ml_statistics.iterator; (x, _) <- props.iterator if x != Now.name) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 92 | yield x) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 93 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 94 | val content = | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 95 |     {
 | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 96 | var last_edge = Map.empty[String, (Double, Double, Double)] | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 97 | val result = new mutable.ListBuffer[ML_Statistics.Entry] | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 98 |       for (props <- ml_statistics) {
 | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 99 | val time = now(props) - time_start | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 100 | require(time >= 0.0) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 101 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 102 | // rising edges -- relative speed | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 103 | val speeds = | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 104 |           for ((key, value) <- props; a <- Library.try_unprefix("time", key)) yield {
 | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 105 | val (x0, y0, s0) = last_edge.getOrElse(a, (0.0, 0.0, 0.0)) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 106 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 107 | val x1 = time | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 108 | val y1 = java.lang.Double.parseDouble(value) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 109 | val s1 = if (x1 == x0) 0.0 else (y1 - y0) / (x1 - x0) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 110 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 111 |             val b = ("speed" + a).intern
 | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 112 |             if (y1 > y0) { last_edge += (a -> (x1, y1, s1)); (b, s1) } else (b, s0)
 | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 113 | } | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 114 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 115 | val data = | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 116 | SortedMap.empty[String, Double] ++ speeds ++ | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 117 | (for ((x, y) <- props.iterator if x != Now.name) | 
| 65866 | 118 |              yield {
 | 
| 119 | val z = java.lang.Double.parseDouble(y) | |
| 120 | (x.intern, if (heap_fields._2.contains(x)) heap_scale(z) else z) | |
| 121 | }) | |
| 122 | ||
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 123 | result += ML_Statistics.Entry(time, data) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 124 | } | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 125 | result.toList | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 126 | } | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 127 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 128 | new ML_Statistics(heading, fields, content, time_start, duration) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 129 | } | 
| 50685 | 130 | } | 
| 50688 
f02864682307
some support for ML statistics content interpretation;
 wenzelm parents: 
50685diff
changeset | 131 | |
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 132 | final class ML_Statistics private( | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 133 | val heading: String, | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 134 | val fields: Set[String], | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 135 | val content: List[ML_Statistics.Entry], | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 136 | val time_start: Double, | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 137 | val duration: Double) | 
| 50688 
f02864682307
some support for ML statistics content interpretation;
 wenzelm parents: 
50685diff
changeset | 138 | {
 | 
| 65858 | 139 | /* content */ | 
| 140 | ||
| 141 | def maximum(field: String): Double = | |
| 142 |     (0.0 /: content)({ case (m, e) => m max e.get(field) })
 | |
| 143 | ||
| 144 | def average(field: String): Double = | |
| 145 |   {
 | |
| 146 | @tailrec def sum(t0: Double, list: List[ML_Statistics.Entry], acc: Double): Double = | |
| 147 |       list match {
 | |
| 148 | case Nil => acc | |
| 149 | case e :: es => | |
| 150 | val t = e.time | |
| 151 | sum(t, es, (t - t0) * e.get(field) + acc) | |
| 152 | } | |
| 153 |     content match {
 | |
| 154 | case Nil => 0.0 | |
| 155 | case List(e) => e.get(field) | |
| 156 | case e :: es => sum(e.time, es, 0.0) / duration | |
| 157 | } | |
| 158 | } | |
| 159 | ||
| 160 | def maximum_heap_size: Long = maximum(ML_Statistics.HEAP_SIZE).toLong | |
| 161 | def average_heap_size: Long = average(ML_Statistics.HEAP_SIZE).toLong | |
| 65854 | 162 | |
| 50689 | 163 | |
| 164 | /* charts */ | |
| 165 | ||
| 65864 | 166 | def update_data(data: XYSeriesCollection, selected_fields: List[String]) | 
| 50689 | 167 |   {
 | 
| 50697 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 168 | data.removeAllSeries | 
| 50689 | 169 |     for {
 | 
| 50690 | 170 | field <- selected_fields.iterator | 
| 50689 | 171 | series = new XYSeries(field) | 
| 172 |     } {
 | |
| 173 | content.foreach(entry => series.add(entry.time, entry.data(field))) | |
| 174 | data.addSeries(series) | |
| 175 | } | |
| 50697 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 176 | } | 
| 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 177 | |
| 65864 | 178 | def chart(title: String, selected_fields: List[String]): JFreeChart = | 
| 50697 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 179 |   {
 | 
| 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 180 | val data = new XYSeriesCollection | 
| 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 181 | update_data(data, selected_fields) | 
| 50689 | 182 | |
| 183 | ChartFactory.createXYLineChart(title, "time", "value", data, | |
| 184 | PlotOrientation.VERTICAL, true, true, true) | |
| 185 | } | |
| 186 | ||
| 65051 | 187 | def chart(fields: ML_Statistics.Fields): JFreeChart = | 
| 188 | chart(fields._1, fields._2) | |
| 50691 | 189 | |
| 65053 | 190 | def show_frames(fields: List[ML_Statistics.Fields] = ML_Statistics.main_fields): Unit = | 
| 65051 | 191 | fields.map(chart(_)).foreach(c => | 
| 57612 
990ffb84489b
clarified module name: facilitate alternative GUI frameworks;
 wenzelm parents: 
53189diff
changeset | 192 |       GUI_Thread.later {
 | 
| 50854 | 193 |         new Frame {
 | 
| 51615 
072a7249e1ac
separate module "GUI", to keep this out of the way of generic Isabelle_System operations, notably for non-Isabelle/jEdit applications;
 wenzelm parents: 
51432diff
changeset | 194 | iconImage = GUI.isabelle_image() | 
| 65851 | 195 | title = heading | 
| 50854 | 196 | contents = Component.wrap(new ChartPanel(c)) | 
| 197 | visible = true | |
| 198 | } | |
| 50697 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 199 | }) | 
| 50688 
f02864682307
some support for ML statistics content interpretation;
 wenzelm parents: 
50685diff
changeset | 200 | } |