Skip to content

Commit

Permalink
Show expected time for directories in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
xrchz committed Nov 16, 2017
1 parent 202649e commit aee3bf1
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 25 deletions.
4 changes: 0 additions & 4 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
TODO: Show expected time required for a directory in progress
Can be calculated as the average time for this directory in other
stopped/running jobs

TODO: Add interface to stop jobs. Rethink job categorisation.
Should the job page have a link for cancelling that job?
If so, how would workers know to do so? Polling?
Expand Down
48 changes: 48 additions & 0 deletions apiLib.sml
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,54 @@ fun read_job_type inp =
else "master"
end

fun read_secs timing =
let
val secs_millisecs = String.tokens (equal #".") timing
val whole_secs = List.nth(secs_millisecs,0)
in
if List.all Char.isDigit (String.explode whole_secs)
then Option.valOf(Int.fromString whole_secs)
else (* TODO: only for supporting legacy %E format
could just update the files and remove this *)
let val ls = String.tokens (equal #":") whole_secs
in
Option.valOf(Int.fromString(List.nth(ls,0))) * 60 * 60 +
Option.valOf(Int.fromString(List.nth(ls,1))) * 60 +
Option.valOf(Int.fromString(List.nth(ls,2)))
handle Subscript =>
Option.valOf(Int.fromString(List.nth(ls,0))) * 60 +
Option.valOf(Int.fromString(List.nth(ls,1)))
end
end

fun read_total_time dir inp =
let
fun loop () =
case TextIO.inputLine inp of NONE => NONE
| SOME line =>
let
val (_,rest) = extract_word line
val prefix = " Resuming "
val resuming = Substring.isPrefix prefix rest
val prefix = " Finished "
val finished = Substring.isPrefix prefix rest
val rest = Substring.triml (String.size prefix) rest
val (dir',rest) = Substring.splitl (not o Char.isSpace) rest
val dirs_match = Substring.isPrefix dir dir' andalso
String.size dir = Substring.size dir'
val rest = Substring.dropl Char.isSpace rest
val (timing,_) = Substring.splitl (not o Char.isSpace) rest
in
if dirs_match then
if finished then
SOME (read_secs (Substring.string timing))
handle Option => loop () | Subscript => loop ()
else if resuming then NONE
else loop ()
else loop ()
end
in loop () end

val max_dir_length = 50

datatype status = Pending | Success | Failure | Aborted
Expand Down
44 changes: 26 additions & 18 deletions serverLib.sml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ type job = {
val machine_date = Date.fmt "%Y-%m-%dT%H:%M:%SZ"
val pretty_date = Date.fmt "%b %d %H:%M:%S"
val pretty_date_moment = "MMM DD HH:mm:ss"
fun machine_secs s = String.concat["PT",Int.toString s,"S"]

fun print_claimed out (worker,date) =
let
Expand Down Expand Up @@ -250,6 +251,19 @@ fun read_job_snapshot q id : bare_snapshot =
val () = TextIO.closeIn inp
in bs end

fun timings_of_dir dir files =
let
fun foldthis (f,(t,fs)) =
let
val inp = TextIO.openIn f handle IO.Io _ => cgi_die 500 ["cannot open ",f]
in
(case read_total_time dir inp of NONE => (t,fs) | SOME s => (t+s,f::fs))
before TextIO.closeIn inp
end handle e => cgi_die 500 ["unexpected error on ",f,"\n",exnMessage e]
in
List.foldl foldthis (0,[]) files
end

fun get_head_sha ({bcml,...}:bare_snapshot) =
case bcml of Bbr sha => sha | Bpr {head_sha,...} => head_sha

Expand Down Expand Up @@ -577,6 +591,8 @@ structure HTML = struct
"ls[i].innerHTML = ' [' + moment(ls[i].getAttribute('datetime')).fromNow() + ']';}",
"else if (ls[i].getAttribute('class') == 'since') {",
"ls[i].innerHTML = '[elapsed: ' + moment(ls[i].getAttribute('datetime')).fromNow(true) + ']';}",
"else if (ls[i].getAttribute('class') == 'duration') {",
"ls[i].innerHTML = '[average: ' + moment.duration(ls[i].getAttribute('datetime')).humanize() + ']';}",
"else if (all) {",
"ls[i].innerHTML = moment(ls[i].getAttribute('datetime')).format('",
pretty_date_moment,"');}}}"]
Expand All @@ -595,6 +611,7 @@ structure HTML = struct
val pre = elt "pre"
fun time d = element "time" [("datetime",machine_date d)] [pretty_date d]
fun time_ago d = element "time" [("datetime",machine_date d),("class","ago")] [" [",pretty_date d,"]"]
fun duration s = element "time" [("datetime",machine_secs s),("class","duration")] [Int.toString s,"s"]
fun a href body = element "a" [("href",href)] [body]
fun span attrs strs = element "span" attrs strs
fun status_attrs Success = [("class","success")]
Expand Down Expand Up @@ -652,22 +669,7 @@ in
fun format_rusage s =
let
val timing = String.tokens Char.isSpace s
val secs_millisecs = String.tokens (equal #".") (List.nth(timing,0))
val whole_secs = List.nth(secs_millisecs,0)
val ts =
if List.all Char.isDigit (String.explode whole_secs)
then Option.valOf(Int.fromString whole_secs)
else (* TODO: only for supporting legacy %E format
could just update the files and remove this *)
let val ls = String.tokens (equal #":") whole_secs
in
Option.valOf(Int.fromString(List.nth(ls,0))) * 60 * 60 +
Option.valOf(Int.fromString(List.nth(ls,1))) * 60 +
Option.valOf(Int.fromString(List.nth(ls,2)))
handle Subscript =>
Option.valOf(Int.fromString(List.nth(ls,0))) * 60 +
Option.valOf(Int.fromString(List.nth(ls,1)))
end
val ts = read_secs (List.nth(timing,0))
val tm = Int.quot(ts,60) val ss = Int.rem(ts,60)
val hh = Int.quot(tm,60) val mm = Int.rem(tm,60)
val tK = Option.valOf(Int.fromString(List.nth(timing,1)))
Expand Down Expand Up @@ -769,7 +771,7 @@ in
val prefix = " Finished "
val rest = extract_prefix_trimr prefix s
val (dir,rest) = extract_word rest
val (space,rest) = Substring.splitl Char.isSpace (Substring.full rest)
val (space,rest) = Substring.splitl Char.isSpace rest
in
String.concat[
prefix,
Expand All @@ -784,9 +786,15 @@ in
val dir = extract_prefix_trimr prefix dir_part
(* val pad = CharVector.tabulate(max_dir_length - String.size dir,(fn _ => #" ")) *)
val (l,r) = Substring.splitAt (Substring.full time_part,6)
val files =
List.map (fn id => OS.Path.concat("running",Int.toString id)) (running()) @
List.map (fn id => OS.Path.concat("stopped",Int.toString id)) (stopped())
val (t,fs) = timings_of_dir dir files
val average = if List.null fs then [] else [" ",duration(Int.quot(t,List.length fs))]
val line = String.concat [
time_part, prefix, dir, " ",
Substring.string l, "class='since' ", Substring.string r, "\n" ]
Substring.string l, "class='since' ", Substring.string r,
String.concat average, "\n" ]
in
line :: rest
end handle Option => acc | Subscript => acc end
Expand Down
5 changes: 2 additions & 3 deletions utilLib.sml
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ structure utilLib = struct
(Substring.triml (String.size prefix) line))
end

fun extract_word s =
let val (s1,s2) = Substring.splitl (not o Char.isSpace) (Substring.full s)
in (s1, Substring.string s2) end
val extract_word =
Substring.splitl (not o Char.isSpace) o Substring.full

local
open Unix
Expand Down

0 comments on commit aee3bf1

Please sign in to comment.