# HG changeset patch # User wenzelm # Date 1596824389 -7200 # Node ID 3546dd4ade74c14ebb286209878851f9f4114036 # Parent b9ded33bd58ce869f8cfd76b9ec324fb0a81ebdd ML statistics via external process: allows monitoring RTS while ML program sleeps; diff -r b9ded33bd58c -r 3546dd4ade74 src/Pure/Concurrent/future.ML --- a/src/Pure/Concurrent/future.ML Fri Aug 07 15:13:50 2020 +0200 +++ b/src/Pure/Concurrent/future.ML Fri Aug 07 20:19:49 2020 +0200 @@ -17,7 +17,6 @@ val task_of: 'a future -> task val peek: 'a future -> 'a Exn.result option val is_finished: 'a future -> bool - val ML_statistics: bool Unsynchronized.ref val interruptible_task: ('a -> 'b) -> 'a -> 'b val cancel_group: group -> unit val cancel: 'a future -> unit @@ -168,31 +167,25 @@ fold (fn (_, state_ref) => fn i => if ! state_ref = state then i + 1 else i) (! workers) 0; - -(* status *) - -val ML_statistics = Unsynchronized.ref false; +(* ML statistics *) -fun report_status () = (*requires SYNCHRONIZED*) - if ! ML_statistics then - let - val {ready, pending, running, passive, urgent} = Task_Queue.status (! queue); - val workers_total = length (! workers); - val workers_active = count_workers Working; - val workers_waiting = count_workers Waiting; - val _ = - ML_Statistics.set - {tasks_ready = ready, - tasks_pending = pending, - tasks_running = running, - tasks_passive = passive, - tasks_urgent = urgent, - workers_total = workers_total, - workers_active = workers_active, - workers_waiting = workers_waiting}; - val stats = ML_Statistics.get (); - in Output.try_protocol_message (Markup.ML_statistics :: stats) [] end - else (); +fun ML_statistics () = (*requires SYNCHRONIZED*) + let + val {ready, pending, running, passive, urgent} = Task_Queue.status (! queue); + val workers_total = length (! workers); + val workers_active = count_workers Working; + val workers_waiting = count_workers Waiting; + in + ML_Statistics.set + {tasks_ready = ready, + tasks_pending = pending, + tasks_running = running, + tasks_passive = passive, + tasks_urgent = urgent, + workers_total = workers_total, + workers_active = workers_active, + workers_waiting = workers_waiting} + end; (* cancellation primitives *) @@ -286,7 +279,7 @@ (* scheduler *) fun scheduler_end () = (*requires SYNCHRONIZED*) - (report_status (); scheduler := NONE); + (ML_statistics (); scheduler := NONE); fun scheduler_next () = (*requires SYNCHRONIZED*) let @@ -300,8 +293,8 @@ val _ = if tick then Unsynchronized.change status_ticks (fn i => i + 1) else (); val _ = - if tick andalso ! status_ticks mod (if ! Multithreading.trace >= 1 then 2 else 10) = 0 - then report_status () else (); + if tick andalso ! status_ticks mod (if ! Multithreading.trace >= 1 then 2 else 5) = 0 + then ML_statistics () else (); val _ = if not tick orelse forall (Thread.isActive o #1) (! workers) then () diff -r b9ded33bd58c -r 3546dd4ade74 src/Pure/ML/ml_process.scala --- a/src/Pure/ML/ml_process.scala Fri Aug 07 15:13:50 2020 +0200 +++ b/src/Pure/ML/ml_process.scala Fri Aug 07 20:19:49 2020 +0200 @@ -124,7 +124,7 @@ val ml_options2 = if (!Platform.is_windows || ml_options.exists(_.containsSlice("codepage"))) ml_options1 else ml_options1 ::: List("--codepage", "utf8") - ml_options2 + ml_options2 ::: List("--exportstats") } // bash diff -r b9ded33bd58c -r 3546dd4ade74 src/Pure/ML/ml_statistics.scala --- a/src/Pure/ML/ml_statistics.scala Fri Aug 07 15:13:50 2020 +0200 +++ b/src/Pure/ML/ml_statistics.scala Fri Aug 07 20:19:49 2020 +0200 @@ -50,6 +50,45 @@ } + /* protocol handler */ + + class Protocol_Handler extends Session.Protocol_Handler + { + private var session: Session = null + private var monitoring: Future[Unit] = Future.value(()) + + override def init(init_session: Session): Unit = synchronized + { + session = init_session + } + + override def exit(): Unit = synchronized + { + session = null + monitoring.cancel + } + + private def consume(props: Properties.T): Unit = synchronized + { + if (session != null && session.session_options.bool("ML_statistics")) { + session.runtime_statistics.post(Session.Runtime_Statistics(props)) + } + } + + private def ml_pid(msg: Prover.Protocol_Output): Boolean = synchronized + { + msg.properties match { + case Markup.ML_Pid(pid) => + monitoring = Future.thread("ML_statistics") { monitor(pid, consume = consume) } + true + case _ => false + } + } + + val functions = List(Markup.ML_Pid.name -> ml_pid) + } + + /* memory fields (mega bytes) */ def mem_print(x: Long): Option[String] = diff -r b9ded33bd58c -r 3546dd4ade74 src/Pure/PIDE/markup.ML --- a/src/Pure/PIDE/markup.ML Fri Aug 07 15:13:50 2020 +0200 +++ b/src/Pure/PIDE/markup.ML Fri Aug 07 20:19:49 2020 +0200 @@ -209,6 +209,7 @@ val dialogN: string val dialog: serial -> string -> T val jedit_actionN: string val functionN: string + val ml_pid: int -> Properties.T val commands_accepted: Properties.T val assign_update: Properties.T val removed_versions: Properties.T @@ -672,6 +673,8 @@ val functionN = "function" +fun ml_pid pid = [(functionN, "ML_pid"), (idN, Value.print_int pid)]; + val commands_accepted = [(functionN, "commands_accepted")]; val assign_update = [(functionN, "assign_update")]; diff -r b9ded33bd58c -r 3546dd4ade74 src/Pure/PIDE/markup.scala --- a/src/Pure/PIDE/markup.scala Fri Aug 07 15:13:50 2020 +0200 +++ b/src/Pure/PIDE/markup.scala Fri Aug 07 20:19:49 2020 +0200 @@ -569,13 +569,22 @@ class Name_Function(name: String) extends Function(name) { - def unapply(props: Properties.T): Option[(String)] = + def unapply(props: Properties.T): Option[String] = props match { case List(PROPERTY, (NAME, a)) => Some(a) case _ => None } } + object ML_Pid extends Function("ML_pid") + { + def unapply(props: Properties.T): Option[Long] = + props match { + case List(PROPERTY, (ID, Value.Long(pid))) => Some(pid) + case _ => None + } + } + val command_timing_properties: Set[String] = Set(FILE, OFFSET, NAME, Elapsed.name) object Command_Timing extends Properties_Function("command_timing") diff -r b9ded33bd58c -r 3546dd4ade74 src/Pure/System/isabelle_process.ML --- a/src/Pure/System/isabelle_process.ML Fri Aug 07 15:13:50 2020 +0200 +++ b/src/Pure/System/isabelle_process.ML Fri Aug 07 20:19:49 2020 +0200 @@ -113,6 +113,8 @@ Output.physical_stderr "Recovered from Isabelle process crash -- see also Isabelle_Process.crashes\n"); +val _ = Session.protocol_handler "isabelle.ML_Statistics$Protocol_Handler"; + in fun init_protocol modes = Thread_Attributes.uninterruptible (fn _ => fn (address, password) => @@ -199,6 +201,7 @@ fun protocol () = (Session.init_protocol_handlers (); + Output.protocol_message (Markup.ml_pid (ML_PID.get ())) []; message Markup.initN [] [XML.Text (Session.welcome ())]; protocol_loop ()); @@ -227,7 +230,6 @@ fun init_options () = (ML_Print_Depth.set_print_depth (Options.default_int "ML_print_depth"); - Future.ML_statistics := Options.default_bool "ML_statistics"; Multithreading.trace := Options.default_int "threads_trace"; Multithreading.max_threads_update (Options.default_int "threads"); Multithreading.parallel_proofs := Options.default_int "parallel_proofs";