@@ -451,11 +451,18 @@ def gettimelinedata(request):
451451 if not executables :
452452 timeline_list ['error' ] = "No executables selected"
453453 return HttpResponse (json .dumps (timeline_list ))
454- environment = None
455- try :
456- environment = get_object_or_404 (Environment , id = data .get ('env' ))
457- except ValueError :
458- Http404 ()
454+
455+ environments = []
456+ for env_id in data .get ('env' , '' ).split (',' )[:2 ]:
457+ if not env_id :
458+ continue
459+ try :
460+ environments .append (get_object_or_404 (Environment , id = int (env_id )))
461+ except (ValueError , Http404 ):
462+ pass
463+ if not environments :
464+ timeline_list ['error' ] = "No environment selected"
465+ return HttpResponse (json .dumps (timeline_list ))
459466
460467 number_of_revs , benchmarks = get_num_revs_and_benchmarks (data )
461468
@@ -471,13 +478,13 @@ def gettimelinedata(request):
471478 next_benchmarks = int (next_benchmarks )
472479
473480 resp = StreamingHttpResponse (stream_timeline (baseline_exe , baseline_rev , benchmarks , data ,
474- environment , executables , number_of_revs ,
481+ environments , executables , number_of_revs ,
475482 next_benchmarks ),
476483 content_type = 'application/json' )
477484 return resp
478485
479486
480- def stream_timeline (baseline_exe , baseline_rev , benchmarks , data , environment , executables ,
487+ def stream_timeline (baseline_exe , baseline_rev , benchmarks , data , environments , executables ,
481488 number_of_revs , next_benchmarks ):
482489 yield '{"timelines": ['
483490 num_results = {"results" : 0 }
@@ -493,7 +500,7 @@ def stream_timeline(baseline_exe, baseline_rev, benchmarks, data, environment, e
493500 num_benchmark += 1
494501
495502 if not next_benchmarks or num_benchmark > next_benchmarks :
496- result = get_timeline_for_benchmark (baseline_exe , baseline_rev , bench , environment ,
503+ result = get_timeline_for_benchmark (baseline_exe , baseline_rev , bench , environments ,
497504 executables , number_of_revs , num_results )
498505 if result != "" :
499506 transmitted_benchmarks += 1
@@ -516,7 +523,7 @@ def stream_timeline(baseline_exe, baseline_rev, benchmarks, data, environment, e
516523 yield ']' + not_first + next_page + ', "error":"None"}\n '
517524
518525
519- def get_timeline_for_benchmark (baseline_exe , baseline_rev , bench , environment , executables ,
526+ def get_timeline_for_benchmark (baseline_exe , baseline_rev , bench , environments , executables ,
520527 number_of_revs , num_results ):
521528 lessisbetter = bench .lessisbetter and ' (less is better)' or ' (more is better)'
522529 timeline = {
@@ -528,74 +535,67 @@ def get_timeline_for_benchmark(baseline_exe, baseline_rev, bench, environment, e
528535 'lessisbetter' : lessisbetter ,
529536 'branches' : {},
530537 'baseline' : "None" ,
538+ 'environments' : [{'id' : env .id , 'name' : env .name } for env in environments ],
531539 }
532540 append = False
533541 for branch in Branch .objects .filter (
534542 project__track = True , name = F ('project__default_branch' )):
535- # For now, we'll only work with default branches
536- for executable in executables :
537- if executable .project != branch .project :
538- continue
539-
540- resultquery = Result .objects .filter (
541- benchmark = bench
542- ).filter (
543- environment = environment
544- ).filter (
545- executable = executable
546- ).filter (
547- revision__branch = branch
548- ).select_related (
549- "revision"
550- ).order_by ('-revision__date' )[:number_of_revs ]
551- if not len (resultquery ):
552- continue
553- timeline ['branches' ].setdefault (branch .name , {})
554-
555- results = []
556- for res in resultquery :
557- if bench .data_type == 'M' :
558- q1 , q3 , val_max , val_min = get_stats_with_defaults (res )
559- results .append (
560- [
543+ for environment in environments :
544+ for executable in executables :
545+ if executable .project != branch .project :
546+ continue
547+
548+ resultquery = Result .objects .filter (
549+ benchmark = bench ,
550+ environment = environment ,
551+ executable = executable ,
552+ revision__branch = branch ,
553+ ).select_related (
554+ "revision"
555+ ).order_by ('-revision__date' )[:number_of_revs ]
556+ if not len (resultquery ):
557+ continue
558+ timeline ['branches' ].setdefault (branch .name , {})
559+
560+ results = []
561+ for res in resultquery :
562+ if bench .data_type == 'M' :
563+ q1 , q3 , val_max , val_min = get_stats_with_defaults (res )
564+ results .append ([
561565 res .revision .date .strftime ('%Y/%m/%d %H:%M:%S %z' ),
562566 res .value , val_max , q3 , q1 , val_min ,
563567 res .revision .get_short_commitid (), res .revision .tag , branch .name ,
564568 res .suite_version ,
565- ]
566- )
567- else :
568- std_dev = ""
569- if res .std_dev is not None :
570- std_dev = res .std_dev
571- results .append (
572- [
569+ ])
570+ else :
571+ std_dev = ""
572+ if res .std_dev is not None :
573+ std_dev = res .std_dev
574+ results .append ([
573575 res .revision .date .strftime ('%Y/%m/%d %H:%M:%S %z' ),
574576 res .value , std_dev ,
575577 res .revision .get_short_commitid (), res .revision .tag , branch .name ,
576578 res .suite_version ,
577- ]
578- )
579- timeline ['branches' ][branch .name ][executable .id ] = results
580- append = True
579+ ])
580+ # Key is "exe_id:env_id" so multiple environments render as separate series
581+ timeline ['branches' ][branch .name ][f" { executable .id } : { environment . id } " ] = results
582+ append = True
581583 if baseline_rev is not None and append :
582584 try :
583585 baselinevalue = Result .objects .get (
584586 executable = baseline_exe ,
585587 benchmark = bench ,
586588 revision = baseline_rev ,
587- environment = environment
589+ environment = environments [ 0 ],
588590 ).value
589591 except Result .DoesNotExist :
590592 timeline ['baseline' ] = "None"
591593 else :
592- # determine start and end revision (x axis)
593- # from longest data series
594594 results = []
595595 for branch in timeline ['branches' ]:
596- for exe in timeline ['branches' ][branch ]:
597- if len (timeline ['branches' ][branch ][exe ]) > len (results ):
598- results = timeline ['branches' ][branch ][exe ]
596+ for key in timeline ['branches' ][branch ]:
597+ if len (timeline ['branches' ][branch ][key ]) > len (results ):
598+ results = timeline ['branches' ][branch ][key ]
599599 end = results [0 ][0 ]
600600 start = results [len (results ) - 1 ][0 ]
601601 timeline ['baseline' ] = [
@@ -625,6 +625,10 @@ def timeline(request):
625625 if not enviros :
626626 return no_environment_error (request )
627627 defaultenviro = get_default_environment (enviros , data )
628+ if 'env' in data :
629+ defaultenvironments = get_default_environment (enviros , data , multi = True )[:2 ]
630+ else :
631+ defaultenvironments = defaultenviro # already respects DEF_ENVIRONMENT
628632
629633 # Default Project
630634 defaultproject = Project .objects .filter (track = True )
@@ -643,6 +647,15 @@ def timeline(request):
643647 except Executable .DoesNotExist :
644648 pass
645649
650+ if not checkedexecutables :
651+ if hasattr (settings , 'DEF_EXECUTABLES' ) and settings .DEF_EXECUTABLES :
652+ for def_exe in settings .DEF_EXECUTABLES :
653+ try :
654+ proj = Project .objects .get (name = def_exe ['project' ])
655+ checkedexecutables .append (
656+ Executable .objects .get (name = def_exe ['name' ], project = proj ))
657+ except (Project .DoesNotExist , Executable .DoesNotExist ):
658+ pass
646659 if not checkedexecutables :
647660 checkedexecutables = Executable .objects .filter (project__track = True )
648661
@@ -671,12 +684,17 @@ def timeline(request):
671684 except ValueError :
672685 pass
673686
674- lastrevisions = [10 , 50 , 200 , 1000 ]
687+ lastrevisions = [10 , 15 , 50 , 200 ]
675688 defaultlast = settings .DEF_TIMELINE_LIMIT
676- if 'revs' in data :
677- if int (data ['revs' ]) not in lastrevisions :
678- lastrevisions .append (data ['revs' ])
679- defaultlast = data ['revs' ]
689+ if 'revs' in data and data ['revs' ]:
690+ try :
691+ revs_int = int (data ['revs' ])
692+ except ValueError :
693+ revs_int = None
694+ if revs_int is not None :
695+ if revs_int not in lastrevisions :
696+ lastrevisions .append (revs_int )
697+ defaultlast = revs_int
680698
681699 benchmarks = Benchmark .objects .all ()
682700
@@ -733,6 +751,7 @@ def timeline(request):
733751 'baseline' : baseline ,
734752 'defaultbenchmark' : defaultbenchmark ,
735753 'defaultenvironment' : defaultenviro ,
754+ 'defaultenvironments' : defaultenvironments ,
736755 'lastrevisions' : lastrevisions ,
737756 'defaultlast' : defaultlast ,
738757 'executables' : executables ,
0 commit comments