88from django .conf import settings
99from django .core .urlresolvers import reverse
1010from django .core .exceptions import ValidationError , ObjectDoesNotExist
11- from django .http import HttpResponse , Http404 , HttpResponseBadRequest ,\
12- HttpResponseNotFound
11+ from django .http import HttpResponse , Http404 , HttpResponseBadRequest , \
12+ HttpResponseNotFound , StreamingHttpResponse
1313from django .db .models import F
1414from django .shortcuts import get_object_or_404 , render_to_response
1515from django .views .decorators .http import require_GET , require_POST
2020 Executable , Benchmark , Branch )
2121from .views_data import (get_default_environment , getbaselineexecutables ,
2222 getdefaultexecutable , getcomparisonexes ,
23- get_benchmark_results )
23+ get_benchmark_results , get_num_revs_and_benchmarks ,
24+ get_stats_with_defaults )
2425from .results import save_result , create_report_if_enough_data
2526from . import commits
2627from .validators import validate_results_request
@@ -224,6 +225,12 @@ def comparison(request):
224225 'selecteddirection' : selecteddirection
225226 })
226227
228+ def get_setting (name , default = None ):
229+ if hasattr (settings , name ):
230+ return getattr (settings , name )
231+ else :
232+ return default
233+
227234
228235@require_GET
229236def gettimelinedata (request ):
@@ -251,126 +258,160 @@ def gettimelinedata(request):
251258 except ValueError :
252259 Http404 ()
253260
254- benchmarks = []
255- number_of_revs = int (data .get ('revs' , 10 ))
256-
257- if data ['ben' ] == 'grid' :
258- benchmarks = Benchmark .objects .all ().order_by ('name' )
259- number_of_revs = 15
260- elif data ['ben' ] == 'show_none' :
261- benchmarks = []
262- else :
263- benchmarks = [get_object_or_404 (Benchmark , name = data ['ben' ])]
261+ number_of_revs , benchmarks = get_num_revs_and_benchmarks (data )
264262
265- baselinerev = None
266- baselineexe = None
263+ baseline_rev = None
264+ baseline_exe = None
267265 if data .get ('base' ) not in (None , 'none' , 'undefined' ):
268- exeid , revid = data ['base' ].split ("+" )
269- baselinerev = Revision .objects .get (id = revid )
270- baselineexe = Executable .objects .get (id = exeid )
266+ exe_id , rev_id = data ['base' ].split ("+" )
267+ baseline_rev = Revision .objects .get (id = rev_id )
268+ baseline_exe = Executable .objects .get (id = exe_id )
269+
270+ next_benchmarks = data .get ('nextBenchmarks' , False )
271+ if next_benchmarks is not False :
272+ next_benchmarks = int (next_benchmarks )
273+
274+ resp = StreamingHttpResponse (stream_timeline (baseline_exe , baseline_rev , benchmarks , data ,
275+ environment , executables , number_of_revs ,
276+ next_benchmarks ),
277+ content_type = 'application/json' )
278+ return resp
279+
280+
281+ def stream_timeline (baseline_exe , baseline_rev , benchmarks , data , environment , executables ,
282+ number_of_revs , next_benchmarks ):
283+ yield '{"timelines": ['
284+ num_results = {"results" : 0 }
285+ num_benchmark = 0
286+ transmitted_benchmarks = 0
287+ timeline_grid_paging = get_setting ('TIMELINE_GRID_PAGING' , 10 )
288+
271289 for bench in benchmarks :
272- lessisbetter = bench .lessisbetter and ' (less is better)' or ' (more is better)'
273- timeline = {
274- 'benchmark' : bench .name ,
275- 'benchmark_id' : bench .id ,
276- 'benchmark_description' : bench .description ,
277- 'data_type' : bench .data_type ,
278- 'units' : bench .units ,
279- 'lessisbetter' : lessisbetter ,
280- 'branches' : {},
281- 'baseline' : "None" ,
282- }
283- append = False
284- for branch in Branch .objects .filter (
285- project__track = True , name = F ('project__default_branch' )):
286- # For now, we'll only work with default branches
287- for executable in executables :
288- if executable .project != branch .project :
289- continue
290-
291- resultquery = Result .objects .filter (
292- benchmark = bench
293- ).filter (
294- environment = environment
295- ).filter (
296- executable = executable
297- ).filter (
298- revision__branch = branch
299- ).select_related (
300- "revision"
301- ).order_by ('-revision__date' )[:number_of_revs ]
302- if not len (resultquery ):
303- continue
304- timeline ['branches' ].setdefault (branch .name , {})
305-
306- results = []
307- for res in resultquery :
308- if bench .data_type == 'M' :
309- val_min = ""
310- if res .val_min is not None :
311- val_min = res .val_min
312- val_max = ""
313- if res .val_max is not None :
314- val_max = res .val_max
315- q1 = ""
316- if res .q1 is not None :
317- q1 = res .q1
318- q3 = ""
319- if res .q3 is not None :
320- q3 = res .q3
321- results .append (
322- [
323- res .revision .date .strftime ('%Y/%m/%d %H:%M:%S %z' ),
324- res .value , val_max , q3 , q1 , val_min ,
325- res .revision .get_short_commitid (), res .revision .tag , branch .name
326- ]
327- )
328- else :
329- std_dev = ""
330- if res .std_dev is not None :
331- std_dev = res .std_dev
332- results .append (
333- [
334- res .revision .date .strftime ('%Y/%m/%d %H:%M:%S %z' ),
335- res .value , std_dev ,
336- res .revision .get_short_commitid (), res .revision .tag , branch .name
337- ]
338- )
339- timeline ['branches' ][branch .name ][executable .id ] = results
340- append = True
341-
342- if baselinerev is not None and append :
343- try :
344- baselinevalue = Result .objects .get (
345- executable = baselineexe ,
346- benchmark = bench ,
347- revision = baselinerev ,
348- environment = environment
349- ).value
350- except Result .DoesNotExist :
351- timeline ['baseline' ] = "None"
352- else :
353- # determine start and end revision (x axis)
354- # from longest data series
355- results = []
356- for branch in timeline ['branches' ]:
357- for exe in timeline ['branches' ][branch ]:
358- if len (timeline ['branches' ][branch ][exe ]) > len (results ):
359- results = timeline ['branches' ][branch ][exe ]
360- end = results [0 ][0 ]
361- start = results [len (results ) - 1 ][0 ]
362- timeline ['baseline' ] = [
363- [str (start ), baselinevalue ],
364- [str (end ), baselinevalue ]
365- ]
366-
367- if append :
368- timeline_list ['timelines' ].append (timeline )
369-
370- if not len (timeline_list ['timelines' ]) and data ['ben' ] != 'show_none' :
371- response = 'No data found for the selected options'
372- timeline_list ['error' ] = response
373- return HttpResponse (json .dumps (timeline_list ))
290+ if transmitted_benchmarks + 1 > timeline_grid_paging :
291+ # don't send more results than configured
292+ break
293+
294+ num_benchmark += 1
295+
296+ if not next_benchmarks or num_benchmark > next_benchmarks :
297+ result = get_timeline_for_benchmark (baseline_exe , baseline_rev , bench , environment ,
298+ executables , number_of_revs , num_results )
299+ if result != "" :
300+ transmitted_benchmarks += 1
301+ yield result
302+
303+ if not next_benchmarks or (next_benchmarks < len (benchmarks )
304+ and transmitted_benchmarks > 0 ):
305+ next_page = ', "nextBenchmarks": ' + str (num_benchmark )
306+ else :
307+ next_page = ', "nextBenchmarks": false'
308+
309+ if next_benchmarks :
310+ not_first = ', "first": false'
311+ else :
312+ not_first = ', "first": true'
313+
314+ if num_results ['results' ] == 0 and data ['ben' ] != 'show_none' and not next_benchmarks :
315+ yield ']' + not_first + next_page + ', "error":"No data found for the selected options"}\n '
316+ else :
317+ yield ']' + not_first + next_page + ', "error":"None"}\n '
318+
319+
320+ def get_timeline_for_benchmark (baseline_exe , baseline_rev , bench , environment , executables ,
321+ number_of_revs , num_results ):
322+ lessisbetter = bench .lessisbetter and ' (less is better)' or ' (more is better)'
323+ timeline = {
324+ 'benchmark' : bench .name ,
325+ 'benchmark_id' : bench .id ,
326+ 'benchmark_description' : bench .description ,
327+ 'data_type' : bench .data_type ,
328+ 'units' : bench .units ,
329+ 'lessisbetter' : lessisbetter ,
330+ 'branches' : {},
331+ 'baseline' : "None" ,
332+ }
333+ append = False
334+ for branch in Branch .objects .filter (
335+ project__track = True , name = F ('project__default_branch' )):
336+ # For now, we'll only work with default branches
337+ for executable in executables :
338+ if executable .project != branch .project :
339+ continue
340+
341+ resultquery = Result .objects .filter (
342+ benchmark = bench
343+ ).filter (
344+ environment = environment
345+ ).filter (
346+ executable = executable
347+ ).filter (
348+ revision__branch = branch
349+ ).select_related (
350+ "revision"
351+ ).order_by ('-revision__date' )[:number_of_revs ]
352+ if not len (resultquery ):
353+ continue
354+ timeline ['branches' ].setdefault (branch .name , {})
355+
356+ results = []
357+ for res in resultquery :
358+ if bench .data_type == 'M' :
359+ q1 , q3 , val_max , val_min = get_stats_with_defaults (res )
360+ results .append (
361+ [
362+ res .revision .date .strftime ('%Y/%m/%d %H:%M:%S %z' ),
363+ res .value , val_max , q3 , q1 , val_min ,
364+ res .revision .get_short_commitid (), res .revision .tag , branch .name
365+ ]
366+ )
367+ else :
368+ std_dev = ""
369+ if res .std_dev is not None :
370+ std_dev = res .std_dev
371+ results .append (
372+ [
373+ res .revision .date .strftime ('%Y/%m/%d %H:%M:%S %z' ),
374+ res .value , std_dev ,
375+ res .revision .get_short_commitid (), res .revision .tag , branch .name
376+ ]
377+ )
378+ timeline ['branches' ][branch .name ][executable .id ] = results
379+ append = True
380+ if baseline_rev is not None and append :
381+ try :
382+ baselinevalue = Result .objects .get (
383+ executable = baseline_exe ,
384+ benchmark = bench ,
385+ revision = baseline_rev ,
386+ environment = environment
387+ ).value
388+ except Result .DoesNotExist :
389+ timeline ['baseline' ] = "None"
390+ else :
391+ # determine start and end revision (x axis)
392+ # from longest data series
393+ results = []
394+ for branch in timeline ['branches' ]:
395+ for exe in timeline ['branches' ][branch ]:
396+ if len (timeline ['branches' ][branch ][exe ]) > len (results ):
397+ results = timeline ['branches' ][branch ][exe ]
398+ end = results [0 ][0 ]
399+ start = results [len (results ) - 1 ][0 ]
400+ timeline ['baseline' ] = [
401+ [str (start ), baselinevalue ],
402+ [str (end ), baselinevalue ]
403+ ]
404+ if append :
405+ old_num_results = num_results ['results' ]
406+ json_str = json .dumps (timeline )
407+ num_results ['results' ] = old_num_results + len (timeline )
408+
409+ if old_num_results > 0 :
410+ return "," + json_str
411+ else :
412+ return json_str
413+ else :
414+ return ""
374415
375416
376417@require_GET
@@ -437,7 +478,7 @@ def timeline(request):
437478 defaultlast = data ['revs' ]
438479
439480 benchmarks = Benchmark .objects .all ()
440- grid_limit = 30
481+
441482 defaultbenchmark = "grid"
442483 if not len (benchmarks ):
443484 return no_data_found (request )
@@ -452,7 +493,7 @@ def timeline(request):
452493 name = settings .DEF_BENCHMARK )
453494 except Benchmark .DoesNotExist :
454495 pass
455- elif len (benchmarks ) >= grid_limit :
496+ elif len (benchmarks ) >= get_setting ( 'TIMELINE_GRID_LIMIT' , 30 ) :
456497 defaultbenchmark = 'show_none'
457498
458499 if 'ben' in data and data ['ben' ] != defaultbenchmark :
0 commit comments