| author | wenzelm | 
| Tue, 14 Mar 2023 10:35:41 +0100 | |
| changeset 77650 | b1ca8975490a | 
| parent 77368 | 7c57d9586f4c | 
| child 77708 | f137bf5d3d94 | 
| 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 | |
| 75393 | 20 | object ML_Statistics {
 | 
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 21 | /* properties */ | 
| 50690 | 22 | |
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 23 |   val Now = new Properties.Double("now")
 | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 24 | def now(props: Properties.T): Double = Now.unapply(props).get | 
| 50697 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 25 | |
| 50690 | 26 | |
| 72138 | 27 | /* memory status */ | 
| 28 | ||
| 29 |   val Heap_Size = new Properties.Long("size_heap")
 | |
| 30 |   val Heap_Free = new Properties.Long("size_heap_free_last_GC")
 | |
| 31 |   val GC_Percent = new Properties.Int("GC_percent")
 | |
| 32 | ||
| 75393 | 33 |   sealed case class Memory_Status(heap_size: Long, heap_free: Long, gc_percent: Int) {
 | 
| 72138 | 34 | def heap_used: Long = (heap_size - heap_free) max 0 | 
| 35 | def heap_used_fraction: Double = | |
| 36 | if (heap_size == 0) 0.0 else heap_used.toDouble / heap_size | |
| 37 | def gc_progress: Option[Double] = | |
| 38 | if (1 <= gc_percent && gc_percent <= 100) Some((gc_percent - 1) * 0.01) else None | |
| 39 | } | |
| 40 | ||
| 75393 | 41 |   def memory_status(props: Properties.T): Memory_Status = {
 | 
| 72138 | 42 | val heap_size = Heap_Size.get(props) | 
| 43 | val heap_free = Heap_Free.get(props) | |
| 44 | val gc_percent = GC_Percent.get(props) | |
| 45 | Memory_Status(heap_size, heap_free, gc_percent) | |
| 46 | } | |
| 47 | ||
| 48 | ||
| 72035 | 49 | /* monitor process */ | 
| 50 | ||
| 51 | def monitor(pid: Long, | |
| 72119 
d115d50a19c0
provide POLYSTATSDIR to keep $HOME/.polyml clean (requires Poly/ML 52881757b127, otherwise ignored);
 wenzelm parents: 
72117diff
changeset | 52 | stats_dir: String = "", | 
| 72035 | 53 | delay: Time = Time.seconds(0.5), | 
| 75393 | 54 | consume: Properties.T => Unit = Console.println | 
| 55 |   ): Unit = {
 | |
| 56 |     def progress_stdout(line: String): Unit = {
 | |
| 77218 | 57 |       val props = space_explode(',', line).flatMap(Properties.Eq.unapply)
 | 
| 72035 | 58 | if (props.nonEmpty) consume(props) | 
| 59 | } | |
| 60 | ||
| 72119 
d115d50a19c0
provide POLYSTATSDIR to keep $HOME/.polyml clean (requires Poly/ML 52881757b127, otherwise ignored);
 wenzelm parents: 
72117diff
changeset | 61 | val env_prefix = | 
| 77368 | 62 | if_proper(stats_dir, "export POLYSTATSDIR=" + Bash.string(stats_dir) + "\n") | 
| 72119 
d115d50a19c0
provide POLYSTATSDIR to keep $HOME/.polyml clean (requires Poly/ML 52881757b127, otherwise ignored);
 wenzelm parents: 
72117diff
changeset | 63 | |
| 73604 | 64 | Bash.process(env_prefix + "\"$POLYML_EXE\" -q --use src/Pure/ML/ml_statistics.ML --eval " + | 
| 72044 
efd169aed4dc
more robust: avoid potential problems with encoding of directory name;
 wenzelm parents: 
72037diff
changeset | 65 |         Bash.string("ML_Statistics.monitor " + ML_Syntax.print_long(pid) + " " +
 | 
| 
efd169aed4dc
more robust: avoid potential problems with encoding of directory name;
 wenzelm parents: 
72037diff
changeset | 66 | ML_Syntax.print_double(delay.seconds)), | 
| 73522 | 67 | cwd = Path.ISABELLE_HOME.file) | 
| 72035 | 68 | .result(progress_stdout = progress_stdout, strict = false).check | 
| 69 | } | |
| 70 | ||
| 71 | ||
| 72112 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 72 | /* protocol handler */ | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 73 | |
| 75393 | 74 |   class Handler extends Session.Protocol_Handler {
 | 
| 72112 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 75 | private var session: Session = null | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 76 | private var monitoring: Future[Unit] = Future.value(()) | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 77 | |
| 75380 | 78 |     override def init(session: Session): Unit = synchronized {
 | 
| 72213 | 79 | this.session = session | 
| 72112 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 80 | } | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 81 | |
| 75380 | 82 |     override def exit(): Unit = synchronized {
 | 
| 72112 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 83 | session = null | 
| 73367 | 84 | monitoring.cancel() | 
| 72112 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 85 | } | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 86 | |
| 75380 | 87 |     private def consume(props: Properties.T): Unit = synchronized {
 | 
| 72136 
98dca728fc9c
removed pointless option "ML_statistics": always enabled;
 wenzelm parents: 
72119diff
changeset | 88 |       if (session != null) {
 | 
| 73031 
f93f0597f4fb
clarified signature: absorb XZ.Cache into XML.Cache;
 wenzelm parents: 
72250diff
changeset | 89 | val props1 = (session.cache.props(props ::: Java_Statistics.jvm_statistics())) | 
| 72149 | 90 | session.runtime_statistics.post(Session.Runtime_Statistics(props1)) | 
| 72112 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 91 | } | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 92 | } | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 93 | |
| 75380 | 94 |     private def ml_statistics(msg: Prover.Protocol_Output): Boolean = synchronized {
 | 
| 72112 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 95 |       msg.properties match {
 | 
| 72119 
d115d50a19c0
provide POLYSTATSDIR to keep $HOME/.polyml clean (requires Poly/ML 52881757b127, otherwise ignored);
 wenzelm parents: 
72117diff
changeset | 96 | case Markup.ML_Statistics(pid, stats_dir) => | 
| 
d115d50a19c0
provide POLYSTATSDIR to keep $HOME/.polyml clean (requires Poly/ML 52881757b127, otherwise ignored);
 wenzelm parents: 
72117diff
changeset | 97 | monitoring = | 
| 
d115d50a19c0
provide POLYSTATSDIR to keep $HOME/.polyml clean (requires Poly/ML 52881757b127, otherwise ignored);
 wenzelm parents: 
72117diff
changeset | 98 |             Future.thread("ML_statistics") {
 | 
| 
d115d50a19c0
provide POLYSTATSDIR to keep $HOME/.polyml clean (requires Poly/ML 52881757b127, otherwise ignored);
 wenzelm parents: 
72117diff
changeset | 99 | monitor(pid, stats_dir = stats_dir, consume = consume) | 
| 
d115d50a19c0
provide POLYSTATSDIR to keep $HOME/.polyml clean (requires Poly/ML 52881757b127, otherwise ignored);
 wenzelm parents: 
72117diff
changeset | 100 | } | 
| 72112 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 101 | true | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 102 | case _ => false | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 103 | } | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 104 | } | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 105 | |
| 75440 | 106 | override val functions: Session.Protocol_Functions = | 
| 107 | List(Markup.ML_Statistics.name -> ml_statistics) | |
| 72112 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 108 | } | 
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 109 | |
| 
3546dd4ade74
ML statistics via external process: allows monitoring RTS while ML program sleeps;
 wenzelm parents: 
72044diff
changeset | 110 | |
| 77121 | 111 | /* memory fields */ | 
| 50690 | 112 | |
| 77118 | 113 | val scale_MiB: Double = 1.0 / 1024 / 1024 | 
| 69832 | 114 | |
| 115 | val CODE_SIZE = "size_code" | |
| 116 | val STACK_SIZE = "size_stacks" | |
| 65858 | 117 | val HEAP_SIZE = "size_heap" | 
| 118 | ||
| 65866 | 119 | |
| 120 | /* standard fields */ | |
| 121 | ||
| 77118 | 122 | sealed case class Fields(title: String, names: List[String], scale: Double = 1.0) | 
| 65051 | 123 | |
| 124 | val tasks_fields: Fields = | |
| 77117 | 125 |     Fields("Future tasks",
 | 
| 68129 | 126 |       List("tasks_ready", "tasks_pending", "tasks_running", "tasks_passive",
 | 
| 127 | "tasks_urgent", "tasks_total")) | |
| 57869 | 128 | |
| 65051 | 129 | val workers_fields: Fields = | 
| 77117 | 130 |     Fields("Worker threads", List("workers_total", "workers_active", "workers_waiting"))
 | 
| 57869 | 131 | |
| 65051 | 132 | val GC_fields: Fields = | 
| 77117 | 133 |     Fields("GCs", List("partial_GCs", "full_GCs", "share_passes"))
 | 
| 50690 | 134 | |
| 65051 | 135 | val heap_fields: Fields = | 
| 77117 | 136 |     Fields("Heap", List(HEAP_SIZE, "size_allocation", "size_allocation_free",
 | 
| 77118 | 137 | "size_heap_free_last_full_GC", "size_heap_free_last_GC"), scale = scale_MiB) | 
| 50690 | 138 | |
| 69822 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 139 | val program_fields: Fields = | 
| 77118 | 140 |     Fields("Program", List("size_code", "size_stacks"), scale = scale_MiB)
 | 
| 69822 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 141 | |
| 65051 | 142 | val threads_fields: Fields = | 
| 77117 | 143 |     Fields("Threads", List("threads_total", "threads_in_ML", "threads_wait_condvar",
 | 
| 50690 | 144 | "threads_wait_IO", "threads_wait_mutex", "threads_wait_signal")) | 
| 145 | ||
| 65051 | 146 | val time_fields: Fields = | 
| 77117 | 147 |     Fields("Time", List("time_elapsed", "time_elapsed_GC", "time_CPU", "time_GC"))
 | 
| 51432 | 148 | |
| 65051 | 149 | val speed_fields: Fields = | 
| 77117 | 150 |     Fields("Speed", List("speed_CPU", "speed_GC"))
 | 
| 50690 | 151 | |
| 69822 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 152 |   private val time_speed = Map("time_CPU" -> "speed_CPU", "time_GC" -> "speed_GC")
 | 
| 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 153 | |
| 72149 | 154 | val java_heap_fields: Fields = | 
| 77117 | 155 |     Fields("Java heap", List("java_heap_size", "java_heap_used"))
 | 
| 72149 | 156 | |
| 157 | val java_thread_fields: Fields = | |
| 77117 | 158 |     Fields("Java threads", List("java_threads_total", "java_workers_total", "java_workers_active"))
 | 
| 72149 | 159 | |
| 65053 | 160 | |
| 72143 | 161 | val main_fields: List[Fields] = | 
| 162 | List(heap_fields, tasks_fields, workers_fields) | |
| 163 | ||
| 72149 | 164 | val other_fields: List[Fields] = | 
| 165 | List(threads_fields, GC_fields, program_fields, time_fields, speed_fields, | |
| 166 | java_heap_fields, java_thread_fields) | |
| 167 | ||
| 168 | val all_fields: List[Fields] = main_fields ::: other_fields | |
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 169 | |
| 77118 | 170 | def field_scale(x: String, y: Double): Double = | 
| 171 |     all_fields.collectFirst({ case fields if fields.names.contains(x) => y * fields.scale })
 | |
| 172 | .getOrElse(y) | |
| 173 | ||
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 174 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 175 | /* content interpretation */ | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 176 | |
| 75393 | 177 |   final case class Entry(time: Double, data: Map[String, Double]) {
 | 
| 65858 | 178 | def get(field: String): Double = data.getOrElse(field, 0.0) | 
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 179 | } | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 180 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 181 | val empty: ML_Statistics = apply(Nil) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 182 | |
| 75393 | 183 | def apply( | 
| 184 | ml_statistics0: List[Properties.T], | |
| 185 | heading: String = "", | |
| 186 | domain: String => Boolean = _ => true | |
| 187 |   ): ML_Statistics = {
 | |
| 73120 
c3589f2dff31
more informative errors: simplify diagnosis of spurious failures reported by users;
 wenzelm parents: 
73031diff
changeset | 188 | require(ml_statistics0.forall(props => Now.unapply(props).isDefined), "missing \"now\" field") | 
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 189 | |
| 72224 | 190 | val ml_statistics = ml_statistics0.sortBy(now) | 
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 191 | 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 | 192 | 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 | 193 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 194 | val fields = | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 195 | SortedSet.empty[String] ++ | 
| 67760 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 196 |         (for {
 | 
| 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 197 | props <- ml_statistics.iterator | 
| 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 198 | (x, _) <- props.iterator | 
| 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 199 | if x != Now.name && domain(x) } yield x) | 
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 200 | |
| 75393 | 201 |     val content = {
 | 
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 202 | var last_edge = Map.empty[String, (Double, Double, Double)] | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 203 | val result = new mutable.ListBuffer[ML_Statistics.Entry] | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 204 |       for (props <- ml_statistics) {
 | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 205 | val time = now(props) - time_start | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 206 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 207 | // rising edges -- relative speed | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 208 | val speeds = | 
| 67760 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 209 |           (for {
 | 
| 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 210 | (key, value) <- props.iterator | 
| 69822 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 211 | key1 <- time_speed.get(key) | 
| 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 212 | if domain(key1) | 
| 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 213 |           } yield {
 | 
| 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 214 | val (x0, y0, s0) = last_edge.getOrElse(key, (0.0, 0.0, 0.0)) | 
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 215 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 216 | val x1 = time | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 217 | val y1 = java.lang.Double.parseDouble(value) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 218 | 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 | 219 | |
| 67760 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 220 |             if (y1 > y0) {
 | 
| 69822 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 221 | last_edge += (key -> (x1, y1, s1)) | 
| 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 222 | (key1, s1.toString) | 
| 67760 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 223 | } | 
| 69822 
8c587dd44f51
updated to polyml-5.8-20190220 (pre-release of Poly/ML 5.8);
 wenzelm parents: 
68129diff
changeset | 224 | else (key1, s0.toString) | 
| 67760 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 225 | }).toList | 
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 226 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 227 | val data = | 
| 67760 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 228 | SortedMap.empty[String, Double] ++ | 
| 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 229 |             (for {
 | 
| 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 230 | (x, y) <- props.iterator ++ speeds.iterator | 
| 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 231 | if x != Now.name && domain(x) | 
| 
553d9ad7d679
more compact ML_Statistics, to make build_status work with less than 2GB heap;
 wenzelm parents: 
65866diff
changeset | 232 | z = java.lang.Double.parseDouble(y) if z != 0.0 | 
| 77121 | 233 |             } yield { (x.intern, z) })
 | 
| 65866 | 234 | |
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 235 | result += ML_Statistics.Entry(time, data) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 236 | } | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 237 | result.toList | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 238 | } | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 239 | |
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 240 | new ML_Statistics(heading, fields, content, time_start, duration) | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 241 | } | 
| 50685 | 242 | } | 
| 50688 
f02864682307
some support for ML statistics content interpretation;
 wenzelm parents: 
50685diff
changeset | 243 | |
| 65855 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 244 | final class ML_Statistics private( | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 245 | val heading: String, | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 246 | val fields: Set[String], | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 247 | val content: List[ML_Statistics.Entry], | 
| 
33b3e76114f8
store processed content instead of somewhat bulky properties;
 wenzelm parents: 
65854diff
changeset | 248 | val time_start: Double, | 
| 75393 | 249 | val duration: Double | 
| 250 | ) {
 | |
| 74853 | 251 | override def toString: String = | 
| 252 | if (content.isEmpty) "ML_Statistics.empty" | |
| 253 | else "ML_Statistics(length = " + content.length + ", fields = " + fields.size + ")" | |
| 254 | ||
| 255 | ||
| 65858 | 256 | /* content */ | 
| 257 | ||
| 258 | def maximum(field: String): Double = | |
| 73359 | 259 |     content.foldLeft(0.0) { case (m, e) => m max e.get(field) }
 | 
| 65858 | 260 | |
| 75393 | 261 |   def average(field: String): Double = {
 | 
| 65858 | 262 | @tailrec def sum(t0: Double, list: List[ML_Statistics.Entry], acc: Double): Double = | 
| 263 |       list match {
 | |
| 264 | case Nil => acc | |
| 265 | case e :: es => | |
| 266 | val t = e.time | |
| 267 | sum(t, es, (t - t0) * e.get(field) + acc) | |
| 268 | } | |
| 269 |     content match {
 | |
| 270 | case Nil => 0.0 | |
| 271 | case List(e) => e.get(field) | |
| 272 | case e :: es => sum(e.time, es, 0.0) / duration | |
| 273 | } | |
| 274 | } | |
| 275 | ||
| 50689 | 276 | |
| 277 | /* charts */ | |
| 278 | ||
| 75393 | 279 |   def update_data(data: XYSeriesCollection, selected_fields: List[String]): Unit = {
 | 
| 74852 | 280 | data.removeAllSeries() | 
| 69832 | 281 |     for (field <- selected_fields) {
 | 
| 282 | val series = new XYSeries(field) | |
| 77121 | 283 | content.foreach(e => series.add(e.time, ML_Statistics.field_scale(field, e.get(field)))) | 
| 50689 | 284 | data.addSeries(series) | 
| 285 | } | |
| 50697 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 286 | } | 
| 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 287 | |
| 75393 | 288 |   def chart(title: String, selected_fields: List[String]): JFreeChart = {
 | 
| 50697 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 289 | val data = new XYSeriesCollection | 
| 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 290 | update_data(data, selected_fields) | 
| 50689 | 291 | |
| 292 | ChartFactory.createXYLineChart(title, "time", "value", data, | |
| 293 | PlotOrientation.VERTICAL, true, true, true) | |
| 294 | } | |
| 295 | ||
| 65051 | 296 | def chart(fields: ML_Statistics.Fields): JFreeChart = | 
| 77117 | 297 | chart(fields.title, fields.names) | 
| 50691 | 298 | |
| 65053 | 299 | def show_frames(fields: List[ML_Statistics.Fields] = ML_Statistics.main_fields): Unit = | 
| 71601 | 300 | fields.map(chart).foreach(c => | 
| 57612 
990ffb84489b
clarified module name: facilitate alternative GUI frameworks;
 wenzelm parents: 
53189diff
changeset | 301 |       GUI_Thread.later {
 | 
| 50854 | 302 |         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 | 303 | iconImage = GUI.isabelle_image() | 
| 65851 | 304 | title = heading | 
| 50854 | 305 | contents = Component.wrap(new ChartPanel(c)) | 
| 306 | visible = true | |
| 307 | } | |
| 50697 
82e9178e6a98
improved Monitor_Dockable, based on ML_Statistics operations;
 wenzelm parents: 
50691diff
changeset | 308 | }) | 
| 50688 
f02864682307
some support for ML statistics content interpretation;
 wenzelm parents: 
50685diff
changeset | 309 | } |