| author | wenzelm | 
| Tue, 14 Mar 2017 11:16:23 +0100 | |
| changeset 65223 | 844c067bc3d4 | 
| parent 65052 | 7f825cc6debf | 
| child 65276 | fa1a5efee2ec | 
| permissions | -rw-r--r-- | 
| 64160 | 1 | /* Title: Pure/Admin/build_log.scala | 
| 64045 | 2 | Author: Makarius | 
| 3 | ||
| 64110 | 4 | Build log parsing for current and historic formats. | 
| 64045 | 5 | */ | 
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 64100 | 10 | import java.io.{File => JFile}
 | 
| 11 | import java.time.ZoneId | |
| 64110 | 12 | import java.time.format.{DateTimeFormatter, DateTimeParseException}
 | 
| 64096 | 13 | import java.util.Locale | 
| 64061 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 14 | |
| 64054 | 15 | import scala.collection.mutable | 
| 16 | import scala.util.matching.Regex | |
| 17 | ||
| 18 | ||
| 64045 | 19 | object Build_Log | 
| 20 | {
 | |
| 64298 | 21 | /** content **/ | 
| 64101 | 22 | |
| 64298 | 23 | /* properties */ | 
| 64150 | 24 | |
| 64298 | 25 | object Prop | 
| 26 |   {
 | |
| 64303 
605351c7ef97
another attempt to squeeze a list into a property list entry;
 wenzelm parents: 
64300diff
changeset | 27 | val separator = '\u000b' | 
| 
605351c7ef97
another attempt to squeeze a list into a property list entry;
 wenzelm parents: 
64300diff
changeset | 28 | |
| 64300 
3073688abbe9
clarified multiple props: result needs to fit on a single line within the log file;
 wenzelm parents: 
64299diff
changeset | 29 | def multiple(name: String, args: List[String]): Properties.T = | 
| 
3073688abbe9
clarified multiple props: result needs to fit on a single line within the log file;
 wenzelm parents: 
64299diff
changeset | 30 | if (args.isEmpty) Nil | 
| 64303 
605351c7ef97
another attempt to squeeze a list into a property list entry;
 wenzelm parents: 
64300diff
changeset | 31 | else List(name -> args.mkString(separator.toString)) | 
| 64299 | 32 | |
| 64300 
3073688abbe9
clarified multiple props: result needs to fit on a single line within the log file;
 wenzelm parents: 
64299diff
changeset | 33 | val build_tags = "build_tags" // multiple | 
| 
3073688abbe9
clarified multiple props: result needs to fit on a single line within the log file;
 wenzelm parents: 
64299diff
changeset | 34 | val build_args = "build_args" // multiple | 
| 64298 | 35 | val build_group_id = "build_group_id" | 
| 36 | val build_id = "build_id" | |
| 37 | val build_engine = "build_engine" | |
| 38 | val build_host = "build_host" | |
| 39 | val build_start = "build_start" | |
| 40 | val build_end = "build_end" | |
| 41 | val isabelle_version = "isabelle_version" | |
| 42 | val afp_version = "afp_version" | |
| 43 | } | |
| 64150 | 44 | |
| 45 | ||
| 64298 | 46 | /* settings */ | 
| 64080 | 47 | |
| 64081 | 48 | object Settings | 
| 49 |   {
 | |
| 50 |     val build_settings = List("ISABELLE_BUILD_OPTIONS")
 | |
| 51 |     val ml_settings = List("ML_PLATFORM", "ML_HOME", "ML_SYSTEM", "ML_OPTIONS")
 | |
| 52 | val all_settings = build_settings ::: ml_settings | |
| 53 | ||
| 54 | type Entry = (String, String) | |
| 55 | type T = List[Entry] | |
| 64080 | 56 | |
| 64081 | 57 | object Entry | 
| 58 |     {
 | |
| 59 | def unapply(s: String): Option[Entry] = | |
| 60 |         s.indexOf('=') match {
 | |
| 61 | case -1 => None | |
| 62 | case i => | |
| 63 | val a = s.substring(0, i) | |
| 64 | val b = Library.perhaps_unquote(s.substring(i + 1)) | |
| 65 | Some((a, b)) | |
| 66 | } | |
| 67 | def apply(a: String, b: String): String = a + "=" + quote(b) | |
| 68 | def getenv(a: String): String = apply(a, Isabelle_System.getenv(a)) | |
| 69 | } | |
| 64080 | 70 | |
| 64081 | 71 | def show(): String = | 
| 72 | cat_lines( | |
| 73 |         build_settings.map(Entry.getenv(_)) ::: List("") ::: ml_settings.map(Entry.getenv(_)))
 | |
| 64080 | 74 | } | 
| 75 | ||
| 76 | ||
| 64298 | 77 | /* file names */ | 
| 78 | ||
| 79 | def log_date(date: Date): String = | |
| 80 | String.format(Locale.ROOT, "%s.%05d", | |
| 81 |       DateTimeFormatter.ofPattern("yyyy-MM-dd").format(date.rep),
 | |
| 82 | new java.lang.Long((date.time - date.midnight.time).ms / 1000)) | |
| 83 | ||
| 84 | def log_subdir(date: Date): Path = | |
| 85 |     Path.explode("log") + Path.explode(date.rep.getYear.toString)
 | |
| 86 | ||
| 87 | def log_filename(engine: String, date: Date, more: List[String] = Nil): Path = | |
| 88 |     Path.explode((engine :: log_date(date) :: more).mkString("", "_", ".log"))
 | |
| 89 | ||
| 90 | ||
| 91 | /* log file collections */ | |
| 92 | ||
| 93 | def is_log(file: JFile): Boolean = | |
| 94 |     List(".log", ".log.gz", ".log.xz").exists(ext => file.getName.endsWith(ext))
 | |
| 95 | ||
| 96 | def isatest_files(dir: Path): List[JFile] = | |
| 97 |     File.find_files(dir.file, file => is_log(file) && file.getName.startsWith("isatest-makeall-"))
 | |
| 98 | ||
| 99 | def afp_test_files(dir: Path): List[JFile] = | |
| 100 |     File.find_files(dir.file, file => is_log(file) && file.getName.startsWith("afp-test-devel-"))
 | |
| 101 | ||
| 102 | ||
| 64100 | 103 | |
| 64062 | 104 | /** log file **/ | 
| 64045 | 105 | |
| 64155 | 106 | def print_date(date: Date): String = Log_File.Date_Format(date) | 
| 107 | ||
| 64062 | 108 | object Log_File | 
| 109 |   {
 | |
| 110 | def apply(name: String, lines: List[String]): Log_File = | |
| 111 | new Log_File(name, lines) | |
| 112 | ||
| 113 | def apply(name: String, text: String): Log_File = | |
| 64063 | 114 | Log_File(name, Library.trim_split_lines(text)) | 
| 64090 | 115 | |
| 116 | def apply(file: JFile): Log_File = | |
| 117 |     {
 | |
| 118 | val name = file.getName | |
| 119 | val (base_name, text) = | |
| 120 |         Library.try_unsuffix(".gz", name) match {
 | |
| 121 | case Some(base_name) => (base_name, File.read_gzip(file)) | |
| 122 | case None => | |
| 123 |             Library.try_unsuffix(".xz", name) match {
 | |
| 124 | case Some(base_name) => (base_name, File.read_xz(file)) | |
| 125 | case None => (name, File.read(file)) | |
| 126 | } | |
| 127 | } | |
| 128 | apply(base_name, text) | |
| 129 | } | |
| 130 | ||
| 131 | def apply(path: Path): Log_File = apply(path.file) | |
| 64101 | 132 | |
| 64110 | 133 | |
| 134 | /* date format */ | |
| 135 | ||
| 64101 | 136 | val Date_Format = | 
| 137 |     {
 | |
| 138 | val fmts = | |
| 139 | Date.Formatter.variants( | |
| 64116 | 140 |           List("EEE MMM d HH:mm:ss O yyyy", "EEE MMM d HH:mm:ss VV yyyy"),
 | 
| 64104 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 141 | List(Locale.ENGLISH, Locale.GERMAN)) ::: | 
| 64110 | 142 | List( | 
| 143 | DateTimeFormatter.RFC_1123_DATE_TIME, | |
| 144 |           Date.Formatter.pattern("EEE MMM d HH:mm:ss yyyy").withZone(ZoneId.of("Europe/Berlin")))
 | |
| 64101 | 145 | |
| 64104 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 146 | def tune_timezone(s: String): String = | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 147 |         s match {
 | 
| 64101 | 148 | case "CET" | "MET" => "GMT+1" | 
| 149 | case "CEST" | "MEST" => "GMT+2" | |
| 64104 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 150 | case "EST" => "Europe/Berlin" | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 151 | case _ => s | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 152 | } | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 153 | def tune_weekday(s: String): String = | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 154 |         s match {
 | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 155 | case "Die" => "Di" | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 156 | case "Mit" => "Mi" | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 157 | case "Don" => "Do" | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 158 | case "Fre" => "Fr" | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 159 | case "Sam" => "Sa" | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 160 | case "Son" => "So" | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 161 | case _ => s | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 162 | } | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 163 | |
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 164 | def tune(s: String): String = | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 165 | Word.implode( | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 166 |           Word.explode(s) match {
 | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 167 | case a :: "M\uFFFDr" :: bs => tune_weekday(a) :: "Mär" :: bs.map(tune_timezone(_)) | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 168 | case a :: bs => tune_weekday(a) :: bs.map(tune_timezone(_)) | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 169 | case Nil => Nil | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 170 | } | 
| 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 171 | ) | 
| 64101 | 172 | |
| 173 | Date.Format.make(fmts, tune) | |
| 174 | } | |
| 64117 | 175 | |
| 176 | ||
| 177 | /* inlined content */ | |
| 178 | ||
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 179 | def print_props(marker: String, props: Properties.T): String = | 
| 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 180 | marker + YXML.string_of_body(XML.Encode.properties(props)) | 
| 64102 | 181 | } | 
| 182 | ||
| 183 | class Log_File private(val name: String, val lines: List[String]) | |
| 184 |   {
 | |
| 185 | log_file => | |
| 186 | ||
| 187 | override def toString: String = name | |
| 188 | ||
| 189 | def text: String = cat_lines(lines) | |
| 190 | ||
| 191 | def err(msg: String): Nothing = | |
| 192 |       error("Error in log file " + quote(name) + ": " + msg)
 | |
| 193 | ||
| 194 | ||
| 195 | /* date format */ | |
| 64101 | 196 | |
| 197 | object Strict_Date | |
| 198 |     {
 | |
| 199 | def unapply(s: String): Some[Date] = | |
| 64102 | 200 |         try { Some(Log_File.Date_Format.parse(s)) }
 | 
| 64101 | 201 |         catch { case exn: DateTimeParseException => log_file.err(exn.getMessage) }
 | 
| 202 | } | |
| 203 | ||
| 204 | ||
| 64062 | 205 | /* inlined content */ | 
| 206 | ||
| 207 | def find[A](f: String => Option[A]): Option[A] = | |
| 208 | lines.iterator.map(f).find(_.isDefined).map(_.get) | |
| 209 | ||
| 64196 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 210 | def find_line(marker: String): Option[String] = | 
| 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 211 | find(Library.try_unprefix(marker, _)) | 
| 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 212 | |
| 64062 | 213 | def find_match(regex: Regex): Option[String] = | 
| 214 | lines.iterator.map(regex.unapplySeq(_)).find(res => res.isDefined && res.get.length == 1). | |
| 215 | map(res => res.get.head) | |
| 216 | ||
| 217 | ||
| 218 | /* settings */ | |
| 219 | ||
| 64091 | 220 | def get_setting(a: String): Option[Settings.Entry] = | 
| 221 |       lines.find(_.startsWith(a + "=")) match {
 | |
| 222 | case Some(line) => Settings.Entry.unapply(line) | |
| 223 | case None => None | |
| 224 | } | |
| 64045 | 225 | |
| 64091 | 226 | def get_settings(as: List[String]): Settings.T = | 
| 227 |       for { a <- as; entry <- get_setting(a) } yield entry
 | |
| 64062 | 228 | |
| 229 | ||
| 230 | /* properties (YXML) */ | |
| 231 | ||
| 232 | val xml_cache = new XML.Cache() | |
| 233 | ||
| 234 | def parse_props(text: String): Properties.T = | |
| 235 | xml_cache.props(XML.Decode.properties(YXML.parse_body(text))) | |
| 236 | ||
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 237 | def filter_props(marker: String): List[Properties.T] = | 
| 64196 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 238 |       for {
 | 
| 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 239 | line <- lines | 
| 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 240 | s <- Library.try_unprefix(marker, line) | 
| 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 241 | if YXML.detect(s) | 
| 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 242 | } yield parse_props(s) | 
| 64062 | 243 | |
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 244 | def find_props(marker: String): Option[Properties.T] = | 
| 64196 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 245 |       find_line(marker) match {
 | 
| 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 246 | case Some(text) if YXML.detect(text) => Some(parse_props(text)) | 
| 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 247 | case _ => None | 
| 
6688b9cd443b
more robust wrt. old versions that use clear-text properties (e.g. Timing in build_history_base);
 wenzelm parents: 
64193diff
changeset | 248 | } | 
| 64062 | 249 | |
| 250 | ||
| 251 | /* parse various formats */ | |
| 252 | ||
| 64105 | 253 | def parse_meta_info(): Meta_Info = Build_Log.parse_meta_info(log_file) | 
| 254 | ||
| 255 | def parse_build_info(): Build_Info = Build_Log.parse_build_info(log_file) | |
| 256 | ||
| 64082 | 257 | def parse_session_info( | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 258 | default_name: String = "", | 
| 64082 | 259 | command_timings: Boolean = false, | 
| 260 | ml_statistics: Boolean = false, | |
| 261 | task_statistics: Boolean = false): Session_Info = | |
| 262 | Build_Log.parse_session_info( | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 263 | log_file, default_name, command_timings, ml_statistics, task_statistics) | 
| 64045 | 264 | } | 
| 265 | ||
| 266 | ||
| 64098 | 267 | |
| 64105 | 268 | /** meta info **/ | 
| 64045 | 269 | |
| 64108 | 270 | object Meta_Info | 
| 64099 | 271 |   {
 | 
| 64108 | 272 | val empty: Meta_Info = Meta_Info(Nil, Nil) | 
| 64099 | 273 | } | 
| 64098 | 274 | |
| 64108 | 275 | sealed case class Meta_Info(props: Properties.T, settings: List[(String, String)]) | 
| 64103 | 276 |   {
 | 
| 277 | def is_empty: Boolean = props.isEmpty && settings.isEmpty | |
| 278 | } | |
| 64061 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 279 | |
| 64095 | 280 | object Isatest | 
| 281 |   {
 | |
| 64108 | 282 | val engine = "isatest" | 
| 64109 | 283 |     val Start = new Regex("""^------------------- starting test --- (.+) --- (.+)$""")
 | 
| 284 |     val End = new Regex("""^------------------- test (?:successful|FAILED) --- (.+) --- .*$""")
 | |
| 64095 | 285 |     val Isabelle_Version = new Regex("""^Isabelle version: (\S+)$""")
 | 
| 286 |     val No_AFP_Version = new Regex("""$.""")
 | |
| 287 | } | |
| 288 | ||
| 64109 | 289 | object AFP_Test | 
| 64061 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 290 |   {
 | 
| 64108 | 291 | val engine = "afp-test" | 
| 64109 | 292 |     val Start = new Regex("""^Start test(?: for .+)? at ([^,]+), (.*)$""")
 | 
| 293 |     val Start_Old = new Regex("""^Start test(?: for .+)? at ([^,]+)$""")
 | |
| 294 |     val End = new Regex("""^End test on (.+), .+, elapsed time:.*$""")
 | |
| 64087 | 295 |     val Isabelle_Version = new Regex("""^Isabelle version: .* -- hg id (\S+)$""")
 | 
| 296 |     val AFP_Version = new Regex("""^AFP version: .* -- hg id (\S+)$""")
 | |
| 64104 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 297 |     val Bad_Init = new Regex("""^cp:.*: Disc quota exceeded$""")
 | 
| 64061 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 298 | } | 
| 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 299 | |
| 64110 | 300 | object Jenkins | 
| 301 |   {
 | |
| 302 | val engine = "jenkins" | |
| 303 |     val Start = new Regex("""^Started .*$""")
 | |
| 304 |     val Start_Date = new Regex("""^Build started at (.+)$""")
 | |
| 305 |     val No_End = new Regex("""$.""")
 | |
| 306 |     val Isabelle_Version = new Regex("""^Isabelle id (\S+)$""")
 | |
| 307 |     val AFP_Version = new Regex("""^AFP id (\S+)$""")
 | |
| 308 | val CONFIGURATION = "=== CONFIGURATION ===" | |
| 309 | val BUILD = "=== BUILD ===" | |
| 310 | val FINISHED = "Finished: " | |
| 311 | } | |
| 312 | ||
| 64105 | 313 | private def parse_meta_info(log_file: Log_File): Meta_Info = | 
| 64061 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 314 |   {
 | 
| 64108 | 315 | def parse(engine: String, host: String, start: Date, | 
| 64109 | 316 | End: Regex, Isabelle_Version: Regex, AFP_Version: Regex): Meta_Info = | 
| 64091 | 317 |     {
 | 
| 64296 
544481988e65
explicit identification of builds and correlated build groups;
 wenzelm parents: 
64196diff
changeset | 318 | val build_id = | 
| 
544481988e65
explicit identification of builds and correlated build groups;
 wenzelm parents: 
64196diff
changeset | 319 |       {
 | 
| 
544481988e65
explicit identification of builds and correlated build groups;
 wenzelm parents: 
64196diff
changeset | 320 | val prefix = if (host != "") host else if (engine != "") engine else "" | 
| 
544481988e65
explicit identification of builds and correlated build groups;
 wenzelm parents: 
64196diff
changeset | 321 | (if (prefix == "") "build" else prefix) + ":" + start.time.ms | 
| 
544481988e65
explicit identification of builds and correlated build groups;
 wenzelm parents: 
64196diff
changeset | 322 | } | 
| 64298 | 323 | val build_engine = if (engine == "") Nil else List(Prop.build_engine -> engine) | 
| 324 | val build_host = if (host == "") Nil else List(Prop.build_host -> host) | |
| 64108 | 325 | |
| 64298 | 326 | val start_date = List(Prop.build_start -> start.toString) | 
| 64091 | 327 | val end_date = | 
| 328 |         log_file.lines.last match {
 | |
| 64109 | 329 | case End(log_file.Strict_Date(end_date)) => | 
| 64298 | 330 | List(Prop.build_end -> end_date.toString) | 
| 64091 | 331 | case _ => Nil | 
| 332 | } | |
| 333 | ||
| 334 | val isabelle_version = | |
| 64298 | 335 | log_file.find_match(Isabelle_Version).map(Prop.isabelle_version -> _) | 
| 64091 | 336 | val afp_version = | 
| 64298 | 337 | log_file.find_match(AFP_Version).map(Prop.afp_version -> _) | 
| 64062 | 338 | |
| 64298 | 339 | Meta_Info((Prop.build_id -> build_id) :: build_engine ::: build_host ::: | 
| 64108 | 340 | start_date ::: end_date ::: isabelle_version.toList ::: afp_version.toList, | 
| 64091 | 341 | log_file.get_settings(Settings.all_settings)) | 
| 342 | } | |
| 343 | ||
| 344 |     log_file.lines match {
 | |
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 345 | case line :: _ if line.startsWith(Build_History.META_INFO_MARKER) => | 
| 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 346 | Meta_Info(log_file.find_props(Build_History.META_INFO_MARKER).get, | 
| 64117 | 347 | log_file.get_settings(Settings.all_settings)) | 
| 348 | ||
| 64109 | 349 | case Isatest.Start(log_file.Strict_Date(start), host) :: _ => | 
| 350 | parse(Isatest.engine, host, start, Isatest.End, | |
| 64108 | 351 | Isatest.Isabelle_Version, Isatest.No_AFP_Version) | 
| 64099 | 352 | |
| 64109 | 353 | case AFP_Test.Start(log_file.Strict_Date(start), host) :: _ => | 
| 354 | parse(AFP_Test.engine, host, start, AFP_Test.End, | |
| 355 | AFP_Test.Isabelle_Version, AFP_Test.AFP_Version) | |
| 64099 | 356 | |
| 64109 | 357 | case AFP_Test.Start_Old(log_file.Strict_Date(start)) :: _ => | 
| 358 | parse(AFP_Test.engine, "", start, AFP_Test.End, | |
| 359 | AFP_Test.Isabelle_Version, AFP_Test.AFP_Version) | |
| 64099 | 360 | |
| 64110 | 361 | case Jenkins.Start() :: _ | 
| 362 | if log_file.lines.contains(Jenkins.CONFIGURATION) || | |
| 363 | log_file.lines.last.startsWith(Jenkins.FINISHED) => | |
| 364 |         log_file.lines.dropWhile(_ != Jenkins.BUILD) match {
 | |
| 365 | case Jenkins.BUILD :: _ :: Jenkins.Start_Date(log_file.Strict_Date(start)) :: _ => | |
| 64111 | 366 |             parse(Jenkins.engine, "", start.to(ZoneId.of("Europe/Berlin")), Jenkins.No_End,
 | 
| 64110 | 367 | Jenkins.Isabelle_Version, Jenkins.AFP_Version) | 
| 368 | case _ => Meta_Info.empty | |
| 369 | } | |
| 370 | ||
| 64341 | 371 |       case line :: _ if line.startsWith("\u0000") => Meta_Info.empty
 | 
| 64109 | 372 | case List(Isatest.End(_)) => Meta_Info.empty | 
| 373 | case _ :: AFP_Test.Bad_Init() :: _ => Meta_Info.empty | |
| 64105 | 374 | case Nil => Meta_Info.empty | 
| 64104 
b70fa05d6746
more permissive: accept all historic isatest and afp-test logs;
 wenzelm parents: 
64103diff
changeset | 375 | |
| 64110 | 376 |       case _ => log_file.err("cannot detect log file format")
 | 
| 64061 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 377 | } | 
| 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 378 | } | 
| 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 379 | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 380 | |
| 64098 | 381 | |
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 382 | /** build info: produced by isabelle build or build_history **/ | 
| 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 383 | |
| 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 384 | val ML_STATISTICS_MARKER = "\fML_statistics = " | 
| 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 385 | val SESSION_NAME = "session_name" | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 386 | |
| 64061 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 387 | object Session_Status extends Enumeration | 
| 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 388 |   {
 | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 389 |     val EXISTING = Value("existing")
 | 
| 64061 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 390 |     val FINISHED = Value("finished")
 | 
| 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 391 |     val FAILED = Value("failed")
 | 
| 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 392 |     val CANCELLED = Value("cancelled")
 | 
| 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 393 | } | 
| 
1bbea2b55d22
some support for header and data fields, notably from afp-test;
 wenzelm parents: 
64054diff
changeset | 394 | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 395 | sealed case class Session_Entry( | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 396 | chapter: String, | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 397 | groups: List[String], | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 398 | threads: Option[Int], | 
| 64089 | 399 | timing: Timing, | 
| 400 | ml_timing: Timing, | |
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 401 | ml_statistics: List[Properties.T], | 
| 64120 | 402 | heap_size: Option[Long], | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 403 | status: Session_Status.Value) | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 404 |   {
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 405 | def finished: Boolean = status == Session_Status.FINISHED | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 406 | } | 
| 64054 | 407 | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 408 | sealed case class Build_Info(sessions: Map[String, Session_Entry]) | 
| 64054 | 409 |   {
 | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 410 | def session(name: String): Session_Entry = sessions(name) | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 411 | def get_session(name: String): Option[Session_Entry] = sessions.get(name) | 
| 64054 | 412 | |
| 64089 | 413 | def get_default[A](name: String, f: Session_Entry => A, x: A): A = | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 414 |       get_session(name) match {
 | 
| 64089 | 415 | case Some(entry) => f(entry) | 
| 416 | case None => x | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 417 | } | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 418 | |
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 419 | def finished_sessions: List[String] = sessions.keySet.iterator.filter(finished(_)).toList | 
| 64089 | 420 | def finished(name: String): Boolean = get_default(name, _.finished, false) | 
| 421 | def timing(name: String): Timing = get_default(name, _.timing, Timing.zero) | |
| 422 | def ml_timing(name: String): Timing = get_default(name, _.ml_timing, Timing.zero) | |
| 65052 | 423 | def ml_statistics(name: String): ML_Statistics = | 
| 424 | get_default(name, entry => ML_Statistics(name, entry.ml_statistics), ML_Statistics.empty) | |
| 64054 | 425 | } | 
| 426 | ||
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 427 | private def parse_build_info(log_file: Log_File): Build_Info = | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 428 |   {
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 429 | object Chapter_Name | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 430 |     {
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 431 | def unapply(s: String): Some[(String, String)] = | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 432 |         space_explode('/', s) match {
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 433 | case List(chapter, name) => Some((chapter, name)) | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 434 |           case _ => Some(("", s))
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 435 | } | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 436 | } | 
| 64054 | 437 | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 438 |     val Session_No_Groups = new Regex("""^Session (\S+)$""")
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 439 |     val Session_Groups = new Regex("""^Session (\S+) \((.*)\)$""")
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 440 | val Session_Finished1 = | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 441 |       new Regex("""^Finished (\S+) \((\d+):(\d+):(\d+) elapsed time, (\d+):(\d+):(\d+) cpu time.*$""")
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 442 | val Session_Finished2 = | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 443 |       new Regex("""^Finished (\S+) \((\d+):(\d+):(\d+) elapsed time.*$""")
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 444 | val Session_Timing = | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 445 |       new Regex("""^Timing (\S+) \((\d) threads, (\d+\.\d+)s elapsed time, (\d+\.\d+)s cpu time, (\d+\.\d+)s GC time.*$""")
 | 
| 64086 
ac7ae5067783
clarified status: started sessions may bomb without explicit FAILED or CANCELLED (cf. in afp-test-devel-2016-01-03.log);
 wenzelm parents: 
64085diff
changeset | 446 |     val Session_Started = new Regex("""^(?:Running|Building) (\S+) \.\.\.$""")
 | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 447 |     val Session_Failed = new Regex("""^(\S+) FAILED""")
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 448 |     val Session_Cancelled = new Regex("""^(\S+) CANCELLED""")
 | 
| 64120 | 449 |     val Heap = new Regex("""^Heap (\S+) \((\d+) bytes\)$""")
 | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 450 | |
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 451 | var chapter = Map.empty[String, String] | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 452 | var groups = Map.empty[String, List[String]] | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 453 | var threads = Map.empty[String, Int] | 
| 64054 | 454 | var timing = Map.empty[String, Timing] | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 455 | var ml_timing = Map.empty[String, Timing] | 
| 64086 
ac7ae5067783
clarified status: started sessions may bomb without explicit FAILED or CANCELLED (cf. in afp-test-devel-2016-01-03.log);
 wenzelm parents: 
64085diff
changeset | 456 | var started = Set.empty[String] | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 457 | var failed = Set.empty[String] | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 458 | var cancelled = Set.empty[String] | 
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 459 | var ml_statistics = Map.empty[String, List[Properties.T]] | 
| 64120 | 460 | var heap_sizes = Map.empty[String, Long] | 
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 461 | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 462 | def all_sessions: Set[String] = | 
| 64120 | 463 | chapter.keySet ++ groups.keySet ++ threads.keySet ++ timing.keySet ++ ml_timing.keySet ++ | 
| 464 | failed ++ cancelled ++ started ++ ml_statistics.keySet ++ heap_sizes.keySet | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 465 | |
| 64054 | 466 | |
| 64062 | 467 |     for (line <- log_file.lines) {
 | 
| 64054 | 468 |       line match {
 | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 469 | case Session_No_Groups(Chapter_Name(chapt, name)) => | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 470 | chapter += (name -> chapt) | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 471 | groups += (name -> Nil) | 
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 472 | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 473 | case Session_Groups(Chapter_Name(chapt, name), grps) => | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 474 | chapter += (name -> chapt) | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 475 | groups += (name -> Word.explode(grps)) | 
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 476 | |
| 64086 
ac7ae5067783
clarified status: started sessions may bomb without explicit FAILED or CANCELLED (cf. in afp-test-devel-2016-01-03.log);
 wenzelm parents: 
64085diff
changeset | 477 | case Session_Started(name) => | 
| 
ac7ae5067783
clarified status: started sessions may bomb without explicit FAILED or CANCELLED (cf. in afp-test-devel-2016-01-03.log);
 wenzelm parents: 
64085diff
changeset | 478 | started += name | 
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 479 | |
| 64054 | 480 | case Session_Finished1(name, | 
| 481 | Value.Int(e1), Value.Int(e2), Value.Int(e3), | |
| 482 | Value.Int(c1), Value.Int(c2), Value.Int(c3)) => | |
| 483 | val elapsed = Time.hms(e1, e2, e3) | |
| 484 | val cpu = Time.hms(c1, c2, c3) | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 485 | timing += (name -> Timing(elapsed, cpu, Time.zero)) | 
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 486 | |
| 64054 | 487 | case Session_Finished2(name, | 
| 488 | Value.Int(e1), Value.Int(e2), Value.Int(e3)) => | |
| 489 | val elapsed = Time.hms(e1, e2, e3) | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 490 | timing += (name -> Timing(elapsed, Time.zero, Time.zero)) | 
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 491 | |
| 64054 | 492 | case Session_Timing(name, | 
| 493 | Value.Int(t), Value.Double(e), Value.Double(c), Value.Double(g)) => | |
| 494 | val elapsed = Time.seconds(e) | |
| 495 | val cpu = Time.seconds(c) | |
| 496 | val gc = Time.seconds(g) | |
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 497 | ml_timing += (name -> Timing(elapsed, cpu, gc)) | 
| 64054 | 498 | threads += (name -> t) | 
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 499 | |
| 64120 | 500 | case Heap(name, Value.Long(size)) => | 
| 501 | heap_sizes += (name -> size) | |
| 502 | ||
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 503 | case _ if line.startsWith(ML_STATISTICS_MARKER) => | 
| 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 504 | val (name, props) = | 
| 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 505 |             Library.try_unprefix(ML_STATISTICS_MARKER, line).map(log_file.parse_props(_)) match {
 | 
| 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 506 | case Some((SESSION_NAME, session_name) :: props) => (session_name, props) | 
| 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 507 |               case _ => log_file.err("malformed ML_statistics " + quote(line))
 | 
| 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 508 | } | 
| 64120 | 509 | ml_statistics += (name -> (props :: ml_statistics.getOrElse(name, Nil))) | 
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 510 | |
| 64054 | 511 | case _ => | 
| 512 | } | |
| 513 | } | |
| 514 | ||
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 515 | val sessions = | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 516 | Map( | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 517 |         (for (name <- all_sessions.toList) yield {
 | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 518 | val status = | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 519 | if (failed(name)) Session_Status.FAILED | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 520 | else if (cancelled(name)) Session_Status.CANCELLED | 
| 64086 
ac7ae5067783
clarified status: started sessions may bomb without explicit FAILED or CANCELLED (cf. in afp-test-devel-2016-01-03.log);
 wenzelm parents: 
64085diff
changeset | 521 | else if (timing.isDefinedAt(name) || ml_timing.isDefinedAt(name)) | 
| 
ac7ae5067783
clarified status: started sessions may bomb without explicit FAILED or CANCELLED (cf. in afp-test-devel-2016-01-03.log);
 wenzelm parents: 
64085diff
changeset | 522 | Session_Status.FINISHED | 
| 
ac7ae5067783
clarified status: started sessions may bomb without explicit FAILED or CANCELLED (cf. in afp-test-devel-2016-01-03.log);
 wenzelm parents: 
64085diff
changeset | 523 | else if (started(name)) Session_Status.FAILED | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 524 | else Session_Status.EXISTING | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 525 | val entry = | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 526 | Session_Entry( | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 527 | chapter.getOrElse(name, ""), | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 528 | groups.getOrElse(name, Nil), | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 529 | threads.get(name), | 
| 64089 | 530 | timing.getOrElse(name, Timing.zero), | 
| 531 | ml_timing.getOrElse(name, Timing.zero), | |
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 532 | ml_statistics.getOrElse(name, Nil).reverse, | 
| 64120 | 533 | heap_sizes.get(name), | 
| 64085 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 534 | status) | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 535 | (name -> entry) | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 536 | }):_*) | 
| 
1c451e5c145f
clarified parse_build_info: isabelle build output;
 wenzelm parents: 
64083diff
changeset | 537 | Build_Info(sessions) | 
| 64054 | 538 | } | 
| 64099 | 539 | |
| 540 | ||
| 541 | ||
| 542 | /** session info: produced by "isabelle build" **/ | |
| 543 | ||
| 544 | sealed case class Session_Info( | |
| 545 | session_name: String, | |
| 546 | session_timing: Properties.T, | |
| 547 | command_timings: List[Properties.T], | |
| 548 | ml_statistics: List[Properties.T], | |
| 549 | task_statistics: List[Properties.T]) | |
| 550 | ||
| 551 | private def parse_session_info( | |
| 552 | log_file: Log_File, | |
| 553 | default_name: String, | |
| 554 | command_timings: Boolean, | |
| 555 | ml_statistics: Boolean, | |
| 556 | task_statistics: Boolean): Session_Info = | |
| 557 |   {
 | |
| 558 | val xml_cache = new XML.Cache() | |
| 559 | ||
| 560 | val session_name = | |
| 561 |       log_file.find_line("\fSession.name = ") match {
 | |
| 562 | case None => default_name | |
| 563 | case Some(name) if default_name == "" || default_name == name => name | |
| 564 |         case Some(name) => log_file.err("log from different session " + quote(name))
 | |
| 565 | } | |
| 566 |     val session_timing = log_file.find_props("\fTiming = ") getOrElse Nil
 | |
| 567 | val command_timings_ = | |
| 568 |       if (command_timings) log_file.filter_props("\fcommand_timing = ") else Nil
 | |
| 569 | val ml_statistics_ = | |
| 64119 
8094eaa38d4b
inline session ML statistics into main build log;
 wenzelm parents: 
64117diff
changeset | 570 | if (ml_statistics) log_file.filter_props(ML_STATISTICS_MARKER) else Nil | 
| 64099 | 571 | val task_statistics_ = | 
| 572 |       if (task_statistics) log_file.filter_props("\ftask_statistics = ") else Nil
 | |
| 573 | ||
| 574 | Session_Info(session_name, session_timing, command_timings_, ml_statistics_, task_statistics_) | |
| 575 | } | |
| 64045 | 576 | } |