1- use std:: sync:: Arc ;
2-
31use crate :: api:: status_new;
42use crate :: job_queue:: build_queue;
53use crate :: load:: SiteCtxt ;
4+ use chrono:: { DateTime , Utc } ;
65use database:: {
76 BenchmarkJob , BenchmarkJobStatus , BenchmarkRequest , BenchmarkRequestStatus ,
87 BenchmarkRequestType , Connection ,
98} ;
109use hashbrown:: HashMap ;
10+ use std:: sync:: Arc ;
11+ use std:: time:: Duration ;
1112
1213pub async fn handle_status_page_new ( ctxt : Arc < SiteCtxt > ) -> anyhow:: Result < status_new:: Response > {
1314 let conn = ctxt. conn ( ) . await ;
1415
1516 let index = conn. load_benchmark_request_index ( ) . await ?;
1617
1718 // The queue contains any in-progress request(s) and then the following requests in queue order
18- // We reverse so that it starts with the request that will be benchmarked the latest
19- let mut queue: Vec < status_new:: BenchmarkRequest > = build_queue ( & * conn, & index)
20- . await ?
19+ let queue = build_queue ( & * conn, & index) . await ?;
20+ let completed = conn. get_last_n_completed_benchmark_requests ( 10 ) . await ?;
21+
22+ // Figure out approximately how long was the most recent master benchmark request
23+ let expected_duration = completed
24+ . iter ( )
25+ . filter ( |req| req. request . is_master ( ) )
26+ . filter_map ( |req| match req. request . status ( ) {
27+ BenchmarkRequestStatus :: Completed { duration, .. } => Some ( duration) ,
28+ _ => None ,
29+ } )
30+ . next ( )
31+ . unwrap_or ( Duration :: from_secs ( 3600 ) ) ;
32+
33+ let in_progress_jobs = conn. get_jobs_of_in_progress_benchmark_requests ( ) . await ?;
34+
35+ // Here we compute the estimated end time for queued requests, and convert the requests to their
36+ // frontend representation.
37+ // We assume that at most a single request is in progress
38+
39+ let now = Utc :: now ( ) ;
40+
41+ // The estimated start time of the current in-progress request
42+ let current_request_start = if let Some ( req) = queue. first ( ) . take_if ( |req| req. is_in_progress ( ) )
43+ {
44+ // Here we need to somehow guess when did the current in-progress request actually start,
45+ // as we do not have that information readily available
46+ let request_jobs = in_progress_jobs
47+ . get ( req. tag ( ) . expect ( "In progress request without a tag" ) )
48+ . map ( |jobs| jobs. as_slice ( ) )
49+ . unwrap_or ( & [ ] ) ;
50+
51+ // Take the earliest start time, if some job has already started
52+ // If there are no started jobs yet, just fall back to the current time (we guess that a
53+ // job will start "any time now")
54+ request_jobs
55+ . iter ( )
56+ . filter_map ( |job| match job. status ( ) {
57+ BenchmarkJobStatus :: Queued => None ,
58+ BenchmarkJobStatus :: InProgress { started_at, .. }
59+ | BenchmarkJobStatus :: Completed { started_at, .. } => Some ( * started_at) ,
60+ } )
61+ . min ( )
62+ . unwrap_or ( now)
63+ } else {
64+ // Assume that the next request (if any) will start at any given moment
65+ now
66+ } ;
67+
68+ // Estimate when the current in-progress request should end
69+ // This ignores the fact that different kinds of requests (e.g. release ones) can have different
70+ // durations, but these are rare and it's not worth the complexity to have multiple estimates
71+ // here.
72+ let current_request_end = current_request_start + expected_duration;
73+
74+ let mut requests: Vec < status_new:: BenchmarkRequest > = queue
2175 . into_iter ( )
22- . map ( |req| request_to_ui ( & req, HashMap :: new ( ) ) )
76+ . enumerate ( )
77+ . map ( |( index, req) | {
78+ let estimated_end = if req. is_in_progress ( ) {
79+ current_request_end
80+ } else {
81+ current_request_end + expected_duration * ( index as u32 )
82+ } ;
83+ request_to_ui ( & req, HashMap :: default ( ) , Some ( estimated_end) )
84+ } )
2385 . collect ( ) ;
24- queue. reverse ( ) ;
25- // And then we add N most recently completed requests to it
26- let completed = conn. get_last_n_completed_benchmark_requests ( 10 ) . await ?;
27- queue. extend (
86+
87+ // We reverse the queued requests so that they start with the request that will be benchmarked the latest
88+ requests. reverse ( ) ;
89+ // And then we add the completed requests
90+ requests. extend (
2891 completed
2992 . into_iter ( )
30- . map ( |req| request_to_ui ( & req. request , req. errors ) ) ,
93+ . map ( |req| request_to_ui ( & req. request , req. errors , None ) ) ,
3194 ) ;
3295
33- let collectors = build_collectors ( conn. as_ref ( ) ) . await ?;
96+ let collectors = build_collectors ( conn. as_ref ( ) , & in_progress_jobs ) . await ?;
3497
3598 Ok ( status_new:: Response {
36- requests : queue ,
99+ requests,
37100 collectors,
38101 } )
39102}
40103
41- async fn build_collectors ( conn : & dyn Connection ) -> anyhow:: Result < Vec < status_new:: Collector > > {
42- let in_progress_jobs = conn. get_jobs_of_in_progress_benchmark_requests ( ) . await ?;
104+ async fn build_collectors (
105+ conn : & dyn Connection ,
106+ in_progress_jobs : & HashMap < String , Vec < BenchmarkJob > > ,
107+ ) -> anyhow:: Result < Vec < status_new:: Collector > > {
43108 let collectors = conn. get_collector_configs ( ) . await ?;
44109 let mut collector_map: HashMap < String , status_new:: Collector > = collectors
45110 . into_iter ( )
@@ -120,11 +185,12 @@ fn job_status_to_priority(status: status_new::BenchmarkJobStatus) -> u32 {
120185fn request_to_ui (
121186 req : & BenchmarkRequest ,
122187 errors : HashMap < String , String > ,
188+ estimated_end : Option < DateTime < Utc > > ,
123189) -> status_new:: BenchmarkRequest {
124190 let ( completed_at, duration_s) = match req. status ( ) {
125- BenchmarkRequestStatus :: WaitingForArtifacts => ( None , None ) ,
126- BenchmarkRequestStatus :: ArtifactsReady => ( None , None ) ,
127- BenchmarkRequestStatus :: InProgress => ( None , None ) ,
191+ BenchmarkRequestStatus :: WaitingForArtifacts => ( estimated_end , None ) ,
192+ BenchmarkRequestStatus :: ArtifactsReady => ( estimated_end , None ) ,
193+ BenchmarkRequestStatus :: InProgress => ( estimated_end , None ) ,
128194 BenchmarkRequestStatus :: Completed {
129195 completed_at,
130196 duration,
@@ -150,6 +216,7 @@ fn request_to_ui(
150216 completed_at,
151217 duration_s,
152218 errors,
219+ end_estimated : estimated_end. is_some ( ) ,
153220 }
154221}
155222
0 commit comments