|
8 | 8 | from django.conf import settings |
9 | 9 | from django.core.urlresolvers import reverse |
10 | 10 | from 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 |
13 | 13 | from django.db.models import F |
14 | 14 | from django.shortcuts import get_object_or_404, render_to_response |
15 | 15 | from django.views.decorators.http import require_GET, require_POST |
@@ -257,115 +257,173 @@ def gettimelinedata(request): |
257 | 257 | except ValueError: |
258 | 258 | Http404() |
259 | 259 |
|
260 | | - benchmarks = [] |
261 | | - number_of_revs = int(data.get('revs', 10)) |
| 260 | + number_of_revs, benchmarks = get_num_revs_and_benchmarks(data) |
262 | 261 |
|
| 262 | + baseline_rev = None |
| 263 | + baseline_exe = None |
| 264 | + if data.get('base') not in (None, 'none', 'undefined'): |
| 265 | + exe_id, rev_id = data['base'].split("+") |
| 266 | + baseline_rev = Revision.objects.get(id=rev_id) |
| 267 | + baseline_exe = Executable.objects.get(id=exe_id) |
| 268 | + |
| 269 | + next_benchmarks = data.get('nextBenchmarks', False) |
| 270 | + if next_benchmarks is not False: |
| 271 | + next_benchmarks = int(next_benchmarks) |
| 272 | + |
| 273 | + resp = StreamingHttpResponse(stream_timeline(baseline_exe, baseline_rev, benchmarks, data, |
| 274 | + environment, executables, number_of_revs, |
| 275 | + next_benchmarks), |
| 276 | + content_type='application/json') |
| 277 | + return resp |
| 278 | + |
| 279 | + |
| 280 | +def stream_timeline(baseline_exe, baseline_rev, benchmarks, data, environment, executables, |
| 281 | + number_of_revs, next_benchmarks): |
| 282 | + yield '{"timelines": [' |
| 283 | + num_results = {"results": 0} |
| 284 | + num_benchmark = 0 |
| 285 | + transmitted_benchmarks = 0 |
| 286 | + timeline_grid_paging = get_setting('TIMELINE_GRID_PAGING', 10) |
| 287 | + |
| 288 | + for bench in benchmarks: |
| 289 | + if transmitted_benchmarks + 1 > timeline_grid_paging: |
| 290 | + # don't send more results than configured |
| 291 | + break |
| 292 | + |
| 293 | + num_benchmark += 1 |
| 294 | + |
| 295 | + if not next_benchmarks or num_benchmark > next_benchmarks: |
| 296 | + result = get_timeline_for_benchmark(baseline_exe, baseline_rev, bench, environment, |
| 297 | + executables, number_of_revs, num_results) |
| 298 | + if result != "": |
| 299 | + transmitted_benchmarks += 1 |
| 300 | + yield result |
| 301 | + |
| 302 | + if not next_benchmarks or (next_benchmarks < len(benchmarks) |
| 303 | + and transmitted_benchmarks > 0): |
| 304 | + next_page = ', "nextBenchmarks": ' + str(num_benchmark) |
| 305 | + else: |
| 306 | + next_page = ', "nextBenchmarks": false' |
| 307 | + |
| 308 | + if next_benchmarks: |
| 309 | + not_first = ', "first": false' |
| 310 | + else: |
| 311 | + not_first = ', "first": true' |
| 312 | + |
| 313 | + if num_results['results'] == 0 and data['ben'] != 'show_none' and not next_benchmarks: |
| 314 | + yield ']' + not_first + next_page + ', "error":"No data found for the selected options"}\n' |
| 315 | + else: |
| 316 | + yield ']' + not_first + next_page + ', "error":"None"}\n' |
| 317 | + |
| 318 | + |
| 319 | +def get_timeline_for_benchmark(baseline_exe, baseline_rev, bench, environment, executables, |
| 320 | + number_of_revs, num_results): |
| 321 | + lessisbetter = bench.lessisbetter and ' (less is better)' or ' (more is better)' |
| 322 | + timeline = { |
| 323 | + 'benchmark': bench.name, |
| 324 | + 'benchmark_id': bench.id, |
| 325 | + 'benchmark_description': bench.description, |
| 326 | + 'data_type': bench.data_type, |
| 327 | + 'units': bench.units, |
| 328 | + 'lessisbetter': lessisbetter, |
| 329 | + 'branches': {}, |
| 330 | + 'baseline': "None", |
| 331 | + } |
| 332 | + append = False |
| 333 | + for branch in Branch.objects.filter( |
| 334 | + project__track=True, name=F('project__default_branch')): |
| 335 | + # For now, we'll only work with default branches |
| 336 | + for executable in executables: |
| 337 | + if executable.project != branch.project: |
| 338 | + continue |
| 339 | + |
| 340 | + resultquery = Result.objects.filter( |
| 341 | + benchmark=bench |
| 342 | + ).filter( |
| 343 | + environment=environment |
| 344 | + ).filter( |
| 345 | + executable=executable |
| 346 | + ).filter( |
| 347 | + revision__branch=branch |
| 348 | + ).select_related( |
| 349 | + "revision" |
| 350 | + ).order_by('-revision__date')[:number_of_revs] |
| 351 | + if not len(resultquery): |
| 352 | + continue |
| 353 | + timeline['branches'].setdefault(branch.name, {}) |
| 354 | + |
| 355 | + results = [] |
| 356 | + for res in resultquery: |
| 357 | + if bench.data_type == 'M': |
| 358 | + q1, q3, val_max, val_min = get_stats_with_defaults(res) |
| 359 | + results.append( |
| 360 | + [ |
| 361 | + res.revision.date.strftime('%Y/%m/%d %H:%M:%S %z'), |
| 362 | + res.value, val_max, q3, q1, val_min, |
| 363 | + res.revision.get_short_commitid(), res.revision.tag, branch.name |
| 364 | + ] |
| 365 | + ) |
| 366 | + else: |
| 367 | + std_dev = "" |
| 368 | + if res.std_dev is not None: |
| 369 | + std_dev = res.std_dev |
| 370 | + results.append( |
| 371 | + [ |
| 372 | + res.revision.date.strftime('%Y/%m/%d %H:%M:%S %z'), |
| 373 | + res.value, std_dev, |
| 374 | + res.revision.get_short_commitid(), res.revision.tag, branch.name |
| 375 | + ] |
| 376 | + ) |
| 377 | + timeline['branches'][branch.name][executable.id] = results |
| 378 | + append = True |
| 379 | + if baseline_rev is not None and append: |
| 380 | + try: |
| 381 | + baselinevalue = Result.objects.get( |
| 382 | + executable=baseline_exe, |
| 383 | + benchmark=bench, |
| 384 | + revision=baseline_rev, |
| 385 | + environment=environment |
| 386 | + ).value |
| 387 | + except Result.DoesNotExist: |
| 388 | + timeline['baseline'] = "None" |
| 389 | + else: |
| 390 | + # determine start and end revision (x axis) |
| 391 | + # from longest data series |
| 392 | + results = [] |
| 393 | + for branch in timeline['branches']: |
| 394 | + for exe in timeline['branches'][branch]: |
| 395 | + if len(timeline['branches'][branch][exe]) > len(results): |
| 396 | + results = timeline['branches'][branch][exe] |
| 397 | + end = results[0][0] |
| 398 | + start = results[len(results) - 1][0] |
| 399 | + timeline['baseline'] = [ |
| 400 | + [str(start), baselinevalue], |
| 401 | + [str(end), baselinevalue] |
| 402 | + ] |
| 403 | + if append: |
| 404 | + old_num_results = num_results['results'] |
| 405 | + json_str = json.dumps(timeline) |
| 406 | + num_results['results'] = old_num_results + len(timeline) |
| 407 | + |
| 408 | + if old_num_results > 0: |
| 409 | + return "," + json_str |
| 410 | + else: |
| 411 | + return json_str |
| 412 | + else: |
| 413 | + return "" |
| 414 | + |
| 415 | + |
| 416 | +def get_num_revs_and_benchmarks(data): |
263 | 417 | if data['ben'] == 'grid': |
264 | 418 | benchmarks = Benchmark.objects.all().order_by('name') |
265 | 419 | number_of_revs = 15 |
266 | 420 | elif data['ben'] == 'show_none': |
267 | 421 | benchmarks = [] |
| 422 | + number_of_revs = int(data.get('revs', 10)) |
268 | 423 | else: |
269 | 424 | benchmarks = [get_object_or_404(Benchmark, name=data['ben'])] |
270 | | - |
271 | | - baselinerev = None |
272 | | - baselineexe = None |
273 | | - if data.get('base') not in (None, 'none', 'undefined'): |
274 | | - exeid, revid = data['base'].split("+") |
275 | | - baselinerev = Revision.objects.get(id=revid) |
276 | | - baselineexe = Executable.objects.get(id=exeid) |
277 | | - for bench in benchmarks: |
278 | | - lessisbetter = bench.lessisbetter and ' (less is better)' or ' (more is better)' |
279 | | - timeline = { |
280 | | - 'benchmark': bench.name, |
281 | | - 'benchmark_id': bench.id, |
282 | | - 'benchmark_description': bench.description, |
283 | | - 'data_type': bench.data_type, |
284 | | - 'units': bench.units, |
285 | | - 'lessisbetter': lessisbetter, |
286 | | - 'branches': {}, |
287 | | - 'baseline': "None", |
288 | | - } |
289 | | - append = False |
290 | | - for branch in Branch.objects.filter( |
291 | | - project__track=True, name=F('project__default_branch')): |
292 | | - # For now, we'll only work with default branches |
293 | | - for executable in executables: |
294 | | - if executable.project != branch.project: |
295 | | - continue |
296 | | - |
297 | | - resultquery = Result.objects.filter( |
298 | | - benchmark=bench |
299 | | - ).filter( |
300 | | - environment=environment |
301 | | - ).filter( |
302 | | - executable=executable |
303 | | - ).filter( |
304 | | - revision__branch=branch |
305 | | - ).select_related( |
306 | | - "revision" |
307 | | - ).order_by('-revision__date')[:number_of_revs] |
308 | | - if not len(resultquery): |
309 | | - continue |
310 | | - timeline['branches'].setdefault(branch.name, {}) |
311 | | - |
312 | | - results = [] |
313 | | - for res in resultquery: |
314 | | - if bench.data_type == 'M': |
315 | | - q1, q3, val_max, val_min = get_stats_with_defaults(res) |
316 | | - results.append( |
317 | | - [ |
318 | | - res.revision.date.strftime('%Y/%m/%d %H:%M:%S %z'), |
319 | | - res.value, val_max, q3, q1, val_min, |
320 | | - res.revision.get_short_commitid(), res.revision.tag, branch.name |
321 | | - ] |
322 | | - ) |
323 | | - else: |
324 | | - std_dev = "" |
325 | | - if res.std_dev is not None: |
326 | | - std_dev = res.std_dev |
327 | | - results.append( |
328 | | - [ |
329 | | - res.revision.date.strftime('%Y/%m/%d %H:%M:%S %z'), |
330 | | - res.value, std_dev, |
331 | | - res.revision.get_short_commitid(), res.revision.tag, branch.name |
332 | | - ] |
333 | | - ) |
334 | | - timeline['branches'][branch.name][executable.id] = results |
335 | | - append = True |
336 | | - |
337 | | - if baselinerev is not None and append: |
338 | | - try: |
339 | | - baselinevalue = Result.objects.get( |
340 | | - executable=baselineexe, |
341 | | - benchmark=bench, |
342 | | - revision=baselinerev, |
343 | | - environment=environment |
344 | | - ).value |
345 | | - except Result.DoesNotExist: |
346 | | - timeline['baseline'] = "None" |
347 | | - else: |
348 | | - # determine start and end revision (x axis) |
349 | | - # from longest data series |
350 | | - results = [] |
351 | | - for branch in timeline['branches']: |
352 | | - for exe in timeline['branches'][branch]: |
353 | | - if len(timeline['branches'][branch][exe]) > len(results): |
354 | | - results = timeline['branches'][branch][exe] |
355 | | - end = results[0][0] |
356 | | - start = results[len(results) - 1][0] |
357 | | - timeline['baseline'] = [ |
358 | | - [str(start), baselinevalue], |
359 | | - [str(end), baselinevalue] |
360 | | - ] |
361 | | - |
362 | | - if append: |
363 | | - timeline_list['timelines'].append(timeline) |
364 | | - |
365 | | - if not len(timeline_list['timelines']) and data['ben'] != 'show_none': |
366 | | - response = 'No data found for the selected options' |
367 | | - timeline_list['error'] = response |
368 | | - return HttpResponse(json.dumps(timeline_list)) |
| 425 | + number_of_revs = int(data.get('revs', 10)) |
| 426 | + return number_of_revs, benchmarks |
369 | 427 |
|
370 | 428 |
|
371 | 429 | def get_stats_with_defaults(res): |
|
0 commit comments