diff options
author | Michael Wood <michael.g.wood@intel.com> | 2016-05-26 16:12:22 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-06-15 08:35:04 +0100 |
commit | b2a68f55110b39aaf0b0d47bf533251a59a40a41 (patch) | |
tree | 7791ed85141e07f01c228619047740b235ee02dc /bitbake/lib/toaster | |
parent | 32d1e2dd25f288790450db48766cf115854712ba (diff) | |
download | poky-b2a68f55110b39aaf0b0d47bf533251a59a40a41.tar.gz |
bitbake: toaster: port Task tables to ToasterTables widget
Port the Task based tables to ToasterTable. This is the Task, Time, CPU
usage and Disk I/O tables.
(Bitbake rev: bebcef7a4bf08b10e472475435ddc7a524364adb)
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster')
-rw-r--r-- | bitbake/lib/toaster/toastergui/buildtables.py | 227 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/buildinfo-toastertable.html | 4 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/buildtime.html | 4 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/task.html | 2 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/tasks.html | 141 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/urls.py | 23 | ||||
-rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 280 |
7 files changed, 248 insertions, 433 deletions
diff --git a/bitbake/lib/toaster/toastergui/buildtables.py b/bitbake/lib/toaster/toastergui/buildtables.py index dc742b9fe5..51c136f988 100644 --- a/bitbake/lib/toaster/toastergui/buildtables.py +++ b/bitbake/lib/toaster/toastergui/buildtables.py | |||
@@ -19,10 +19,13 @@ | |||
19 | # with this program; if not, write to the Free Software Foundation, Inc., | 19 | # with this program; if not, write to the Free Software Foundation, Inc., |
20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
21 | 21 | ||
22 | from orm.models import Build | 22 | from orm.models import Build, Task |
23 | import toastergui.tables as tables | 23 | from django.db.models import Q |
24 | 24 | ||
25 | import toastergui.tables as tables | ||
25 | from toastergui.widgets import ToasterTable | 26 | from toastergui.widgets import ToasterTable |
27 | from toastergui.tablefilter import TableFilter | ||
28 | from toastergui.tablefilter import TableFilterActionToggle | ||
26 | 29 | ||
27 | 30 | ||
28 | class BuildTablesMixin(ToasterTable): | 31 | class BuildTablesMixin(ToasterTable): |
@@ -279,3 +282,223 @@ class BuiltRecipesTable(BuildTablesMixin): | |||
279 | self.add_column(title="Layer commit", | 282 | self.add_column(title="Layer commit", |
280 | static_data_name="commit", | 283 | static_data_name="commit", |
281 | static_data_template=git_rev_template) | 284 | static_data_template=git_rev_template) |
285 | |||
286 | |||
287 | class BuildTasksTable(BuildTablesMixin): | ||
288 | """ Table to show the tasks that run in this build """ | ||
289 | |||
290 | def __init__(self, *args, **kwargs): | ||
291 | super(BuildTasksTable, self).__init__(*args, **kwargs) | ||
292 | self.title = "Tasks" | ||
293 | self.default_orderby = "order" | ||
294 | |||
295 | # Toggle these columns on off for Time/CPU usage/Disk I/O tables | ||
296 | self.toggle_columns = {} | ||
297 | |||
298 | def setup_queryset(self, *args, **kwargs): | ||
299 | build = Build.objects.get(pk=kwargs['build_id']) | ||
300 | self.static_context_extra['build'] = build | ||
301 | self.queryset = build.task_build.filter(~Q(order=None)) | ||
302 | self.queryset = self.queryset.order_by(self.default_orderby) | ||
303 | |||
304 | def setup_filters(self, *args, **kwargs): | ||
305 | # Execution outcome types filter | ||
306 | executed_outcome = TableFilter(name="execution_outcome", | ||
307 | title="Filter Tasks by 'Executed") | ||
308 | |||
309 | exec_outcome_action_exec = TableFilterActionToggle( | ||
310 | "executed", | ||
311 | "Executed Tasks", | ||
312 | Q(task_executed=True)) | ||
313 | |||
314 | exec_outcome_action_not_exec = TableFilterActionToggle( | ||
315 | "not_executed", | ||
316 | "Not Executed Tasks", | ||
317 | Q(task_executed=False)) | ||
318 | |||
319 | executed_outcome.add_action(exec_outcome_action_exec) | ||
320 | executed_outcome.add_action(exec_outcome_action_not_exec) | ||
321 | |||
322 | # Task outcome types filter | ||
323 | task_outcome = TableFilter(name="task_outcome", | ||
324 | title="Filter Task by 'Outcome'") | ||
325 | |||
326 | for outcome_enum, title in Task.TASK_OUTCOME: | ||
327 | action = TableFilterActionToggle( | ||
328 | title.replace(" ", "_").lower(), | ||
329 | "%s Tasks" % title, | ||
330 | Q(outcome=outcome_enum)) | ||
331 | |||
332 | task_outcome.add_action(action) | ||
333 | |||
334 | # SSTATE outcome types filter | ||
335 | sstate_outcome = TableFilter(name="sstate_outcome", | ||
336 | title="Filter Task by 'Cache attempt'") | ||
337 | |||
338 | for sstate_result_enum, title in Task.SSTATE_RESULT: | ||
339 | action = TableFilterActionToggle( | ||
340 | title.replace(" ", "_").lower(), | ||
341 | "Tasks with '%s' attempts" % title, | ||
342 | Q(sstate_result=sstate_result_enum)) | ||
343 | |||
344 | sstate_outcome.add_action(action) | ||
345 | |||
346 | self.add_filter(sstate_outcome) | ||
347 | self.add_filter(executed_outcome) | ||
348 | self.add_filter(task_outcome) | ||
349 | |||
350 | def setup_columns(self, *args, **kwargs): | ||
351 | self.toggle_columns['order'] = len(self.columns) | ||
352 | |||
353 | recipe_name_tmpl =\ | ||
354 | '<a href="{% url "recipe" extra.build.pk data.recipe.pk %}">'\ | ||
355 | '{{data.recipe.name}}'\ | ||
356 | '</a>' | ||
357 | |||
358 | recipe_version_tmpl =\ | ||
359 | '<a href="{% url "recipe" extra.build.pk data.recipe.pk %}">'\ | ||
360 | '{{data.recipe.version}}'\ | ||
361 | '</a>' | ||
362 | |||
363 | def task_link_tmpl(val): | ||
364 | return ('<a name="task-{{data.order}}"' | ||
365 | 'href="{%% url "task" extra.build.pk data.pk %%}">' | ||
366 | '%s' | ||
367 | '</a>') % str(val) | ||
368 | |||
369 | self.add_column(title="Order", | ||
370 | static_data_name="order", | ||
371 | static_data_template=task_link_tmpl('{{data.order}}'), | ||
372 | orderable=True) | ||
373 | |||
374 | self.add_column(title="Recipe", | ||
375 | static_data_name='recipe__name', | ||
376 | static_data_template=recipe_name_tmpl, | ||
377 | orderable=True) | ||
378 | |||
379 | self.add_column(title="Recipe version", | ||
380 | static_data_name='recipe__version', | ||
381 | static_data_template=recipe_version_tmpl) | ||
382 | |||
383 | self.add_column(title="Task", | ||
384 | static_data_name="task_name", | ||
385 | static_data_template=task_link_tmpl( | ||
386 | "{{data.task_name}}"), | ||
387 | orderable=True) | ||
388 | |||
389 | self.add_column(title="Executed", | ||
390 | static_data_name="task_executed", | ||
391 | static_data_template=task_link_tmpl( | ||
392 | "{{data.get_executed_display}}"), | ||
393 | filter_name='execution_outcome', | ||
394 | orderable=True) | ||
395 | |||
396 | self.static_context_extra['OUTCOME_FAILED'] = Task.OUTCOME_FAILED | ||
397 | outcome_tmpl = task_link_tmpl("{{data.outcome_text}}") | ||
398 | outcome_tmpl = ('%s ' | ||
399 | '{%% if data.outcome = extra.OUTCOME_FAILED %%}' | ||
400 | '<a href="{%% url "build_artifact" extra.build.pk ' | ||
401 | ' "tasklogfile" data.pk %%}">' | ||
402 | ' <i class="icon-download-alt" ' | ||
403 | ' title="Download task log file"></i>' | ||
404 | '</a> {%% endif %%}' | ||
405 | '<i class="icon-question-sign get-help ' | ||
406 | 'hover-help" style="visibility: hidden;" ' | ||
407 | 'title="{{data.get_outcome_help}}"></i>' | ||
408 | ) % outcome_tmpl | ||
409 | |||
410 | self.add_column(title="Outcome", | ||
411 | static_data_name="outcome", | ||
412 | static_data_template=outcome_tmpl, | ||
413 | filter_name="task_outcome", | ||
414 | orderable=True) | ||
415 | |||
416 | self.add_column(title="Cache attempt", | ||
417 | static_data_name="sstate_result", | ||
418 | static_data_template=task_link_tmpl( | ||
419 | "{{data.sstate_text}}"), | ||
420 | filter_name="sstate_outcome", | ||
421 | orderable=True) | ||
422 | |||
423 | self.toggle_columns['elapsed_time'] = len(self.columns) | ||
424 | |||
425 | self.add_column( | ||
426 | title="Time (secs)", | ||
427 | static_data_name="elapsed_time", | ||
428 | static_data_template='{% load projecttags %}{% load humanize %}' | ||
429 | '{{data.elapsed_time|format_none_and_zero|floatformat:2}}', | ||
430 | orderable=True, | ||
431 | hidden=True) | ||
432 | |||
433 | self.toggle_columns['cpu_time_sys'] = len(self.columns) | ||
434 | |||
435 | self.add_column( | ||
436 | title="System CPU time (secs)", | ||
437 | static_data_name="cpu_time_system", | ||
438 | static_data_template='{% load projecttags %}{% load humanize %}' | ||
439 | '{{data.cpu_time_system|format_none_and_zero|floatformat:2}}', | ||
440 | hidden=True, | ||
441 | orderable=True) | ||
442 | |||
443 | self.toggle_columns['cpu_time_user'] = len(self.columns) | ||
444 | |||
445 | self.add_column( | ||
446 | title="User CPU time (secs)", | ||
447 | static_data_name="cpu_time_user", | ||
448 | static_data_template='{% load projecttags %}{% load humanize %}' | ||
449 | '{{data.cpu_time_user|format_none_and_zero|floatformat:2}}', | ||
450 | hidden=True, | ||
451 | orderable=True) | ||
452 | |||
453 | self.toggle_columns['disk_io'] = len(self.columns) | ||
454 | |||
455 | self.add_column( | ||
456 | title="Disk I/O (ms)", | ||
457 | static_data_name="disk_io", | ||
458 | static_data_template='{% load projecttags %}{% load humanize %}' | ||
459 | '{{data.disk_io|format_none_and_zero|filtered_filesizeformat}}', | ||
460 | hidden=True, | ||
461 | orderable=True) | ||
462 | |||
463 | |||
464 | class BuildTimeTable(BuildTasksTable): | ||
465 | """ Same as tasks table but the Time column is default displayed""" | ||
466 | |||
467 | def __init__(self, *args, **kwargs): | ||
468 | super(BuildTimeTable, self).__init__(*args, **kwargs) | ||
469 | self.default_orderby = "-elapsed_time" | ||
470 | |||
471 | def setup_columns(self, *args, **kwargs): | ||
472 | super(BuildTimeTable, self).setup_columns(**kwargs) | ||
473 | |||
474 | self.columns[self.toggle_columns['order']]['hidden'] = True | ||
475 | self.columns[self.toggle_columns['elapsed_time']]['hidden'] = False | ||
476 | |||
477 | |||
478 | class BuildCPUTimeTable(BuildTasksTable): | ||
479 | """ Same as tasks table but the CPU usage columns are default displayed""" | ||
480 | |||
481 | def __init__(self, *args, **kwargs): | ||
482 | super(BuildCPUTimeTable, self).__init__(*args, **kwargs) | ||
483 | self.default_orderby = "-cpu_time_system" | ||
484 | |||
485 | def setup_columns(self, *args, **kwargs): | ||
486 | super(BuildCPUTimeTable, self).setup_columns(**kwargs) | ||
487 | |||
488 | self.columns[self.toggle_columns['order']]['hidden'] = True | ||
489 | self.columns[self.toggle_columns['cpu_time_sys']]['hidden'] = False | ||
490 | self.columns[self.toggle_columns['cpu_time_user']]['hidden'] = False | ||
491 | |||
492 | |||
493 | class BuildIOTable(BuildTasksTable): | ||
494 | """ Same as tasks table but the Disk IO column is default displayed""" | ||
495 | |||
496 | def __init__(self, *args, **kwargs): | ||
497 | super(BuildIOTable, self).__init__(*args, **kwargs) | ||
498 | self.default_orderby = "-disk_io" | ||
499 | |||
500 | def setup_columns(self, *args, **kwargs): | ||
501 | super(BuildIOTable, self).setup_columns(**kwargs) | ||
502 | |||
503 | self.columns[self.toggle_columns['order']]['hidden'] = True | ||
504 | self.columns[self.toggle_columns['disk_io']]['hidden'] = False | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/buildinfo-toastertable.html b/bitbake/lib/toaster/toastergui/templates/buildinfo-toastertable.html index 4ce5c4a8a5..52cc0569f7 100644 --- a/bitbake/lib/toaster/toastergui/templates/buildinfo-toastertable.html +++ b/bitbake/lib/toaster/toastergui/templates/buildinfo-toastertable.html | |||
@@ -12,12 +12,14 @@ | |||
12 | 12 | ||
13 | {% block buildinfomain %} | 13 | {% block buildinfomain %} |
14 | <div class="span10"> | 14 | <div class="span10"> |
15 | {% url 'builtpackagestable' build.id as xhr_table_url %} | 15 | {# xhr_table_url is just the current url so leave it blank #} |
16 | {% with xhr_table_url='' %} | ||
16 | <div class="page-header"> | 17 | <div class="page-header"> |
17 | <h1> | 18 | <h1> |
18 | {{title}} (<span class="table-count-{{table_name}}">0</span>) </h2> | 19 | {{title}} (<span class="table-count-{{table_name}}">0</span>) </h2> |
19 | </h1> | 20 | </h1> |
20 | </div> | 21 | </div> |
21 | {% include "toastertable.html" %} | 22 | {% include "toastertable.html" %} |
23 | {% endwith %} | ||
22 | </div> | 24 | </div> |
23 | {% endblock %} | 25 | {% endblock %} |
diff --git a/bitbake/lib/toaster/toastergui/templates/buildtime.html b/bitbake/lib/toaster/toastergui/templates/buildtime.html deleted file mode 100644 index ea84ae797c..0000000000 --- a/bitbake/lib/toaster/toastergui/templates/buildtime.html +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | {% extends "basebuildpage.html" %} | ||
2 | {% block localbreadcrumb %} | ||
3 | <li>Build Time</li> | ||
4 | {% endblock %} | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/task.html b/bitbake/lib/toaster/toastergui/templates/task.html index 8773351fab..77391b4e35 100644 --- a/bitbake/lib/toaster/toastergui/templates/task.html +++ b/bitbake/lib/toaster/toastergui/templates/task.html | |||
@@ -196,7 +196,7 @@ | |||
196 | <i class="icon-question-sign get-help" title="The running sequence of each task in the build"></i> | 196 | <i class="icon-question-sign get-help" title="The running sequence of each task in the build"></i> |
197 | Task order | 197 | Task order |
198 | </dt> | 198 | </dt> |
199 | <dd><a href="{%url "tasks_task" build.pk task.order %}#{{task.order}}">{{task.order}}</a></dd> | 199 | <dd><a href="{%url "tasks" build.pk %}?page={{task_in_tasks_table_pg}}&limit=25#task-{{task.order}}">{{task.order}}</a></dd> |
200 | {% if task.task_executed %} | 200 | {% if task.task_executed %} |
201 | <dt> | 201 | <dt> |
202 | <i class="icon-question-sign get-help" title="Indicates if this task executes a Python or Shell function(s)"></i> | 202 | <i class="icon-question-sign get-help" title="Indicates if this task executes a Python or Shell function(s)"></i> |
diff --git a/bitbake/lib/toaster/toastergui/templates/tasks.html b/bitbake/lib/toaster/toastergui/templates/tasks.html deleted file mode 100644 index b3b7621e60..0000000000 --- a/bitbake/lib/toaster/toastergui/templates/tasks.html +++ /dev/null | |||
@@ -1,141 +0,0 @@ | |||
1 | {% extends "basebuildpage.html" %} | ||
2 | {% load humanize %} | ||
3 | {% load projecttags %} | ||
4 | |||
5 | {% block title %} {{mainheading}} - {{build.target_set.all|dictsort:"target"|join:", "}} {{build.machine}} - {{build.project.name}} - Toaster{% endblock %} | ||
6 | {% block localbreadcrumb %} | ||
7 | <li>{{mainheading}}</li> | ||
8 | {% endblock %} | ||
9 | |||
10 | {% block nav-tasks %} | ||
11 | {% if 'Tasks' == mainheading %} | ||
12 | <li class="active"><a href="{% url 'tasks' build.pk %}">Tasks</a></li> | ||
13 | {% else %} | ||
14 | <li><a href="{% url 'tasks' build.pk %}">Tasks</a></li> | ||
15 | {% endif %} | ||
16 | {% endblock %} | ||
17 | {% block nav-buildtime %} | ||
18 | {% if 'Time' == mainheading %} | ||
19 | <li class="active"><a href="{% url 'buildtime' build.pk %}">Time</a></li> | ||
20 | {% else %} | ||
21 | <li><a href="{% url 'buildtime' build.pk %}">Time</a></li> | ||
22 | {% endif %} | ||
23 | {% endblock %} | ||
24 | |||
25 | {% block nav-cputime %} | ||
26 | {% if 'CPU time' == mainheading %} | ||
27 | <li class="active"><a href="{% url 'cputime' build.pk %}">CPU time</a></li> | ||
28 | {% else %} | ||
29 | <li><a href="{% url 'cputime' build.pk %}">CPU time</a></li> | ||
30 | {% endif %} | ||
31 | {% endblock %} | ||
32 | |||
33 | {% block nav-diskio %} | ||
34 | {% if 'Disk I/O' == mainheading %} | ||
35 | <li class="active"><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li> | ||
36 | {% else %} | ||
37 | <li><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li> | ||
38 | {% endif %} | ||
39 | {% endblock %} | ||
40 | |||
41 | {% block buildinfomain %} | ||
42 | <div class="col-md-10"> | ||
43 | {% if not request.GET.filter and not request.GET.search and not objects.paginator.count %} | ||
44 | <!-- Empty - no data in database --> | ||
45 | <div class="page-header"> | ||
46 | <h1>{{mainheading}}</h1> | ||
47 | </div> | ||
48 | <div class="alert alert-info lead"> | ||
49 | No data was recorded for this build. | ||
50 | </div> | ||
51 | |||
52 | {% else %} | ||
53 | |||
54 | <div class="page-header"> | ||
55 | <h1> | ||
56 | {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %} | ||
57 | {{objects.paginator.count}} task{{objects.paginator.count|pluralize}} found | ||
58 | {%elif request.GET.filter and objects.paginator.count == 0 or request.GET.search and objects.paginator.count == 0 %} | ||
59 | No tasks found | ||
60 | {%else%} | ||
61 | {{mainheading}} | ||
62 | {%endif%} | ||
63 | </h1> | ||
64 | </div> | ||
65 | |||
66 | {% if objects.paginator.count == 0 %} | ||
67 | <div class="alert"> | ||
68 | <form class="no-results input-append" id="searchform"> | ||
69 | <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="input-append-addon btn" tabindex="-1"><i class="glyphicon glyphicon-remove"></i></a>{% endif %} | ||
70 | <button class="btn" type="submit" value="Search">Search</button> | ||
71 | <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all tasks</button> | ||
72 | </form> | ||
73 | </div> | ||
74 | |||
75 | |||
76 | {% else %} | ||
77 | {% include "basetable_top.html" %} | ||
78 | |||
79 | {% for task in objects %} | ||
80 | <tr {{ task|task_color }} id="{{task.order}}"> | ||
81 | <td class="order"> | ||
82 | <a href="{%url "task" build.pk task.pk%}">{{task.order}}</a> | ||
83 | </td> | ||
84 | <td class="recipe_name" > | ||
85 | <a href="{% url "recipe" build.pk task.recipe.pk %}">{{task.recipe.name}}</a> | ||
86 | </td> | ||
87 | <td class="recipe_version"> | ||
88 | <a href="{% url "recipe" build.pk task.recipe.pk %}">{{task.recipe.version}}</a> | ||
89 | </td> | ||
90 | <td class="task_name"> | ||
91 | <a href="{%url "task" build.pk task.pk%}">{{task.task_name}}</a> {% if task.get_description %}<i class="icon-question-sign get-help hover-help" title="{{task.get_description}}"></i> {% endif %} | ||
92 | </td> | ||
93 | <td class="executed"> | ||
94 | <a href="{%url "task" build.pk task.pk%}">{{task.get_executed_display}}</a> | ||
95 | </td> | ||
96 | <td class="outcome"> | ||
97 | <a href="{%url "task" build.pk task.pk%}">{{task.get_outcome_display}} </a> | ||
98 | {% if task.outcome = task.OUTCOME_FAILED %} | ||
99 | <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}"> | ||
100 | <i class="icon-download-alt" title="Download task log file"></i> | ||
101 | </a> | ||
102 | {% endif %} | ||
103 | <i class="icon-question-sign get-help hover-help" title="{{task.get_outcome_help}}"></i> | ||
104 | </td> | ||
105 | <td class="cache_attempt"> | ||
106 | <a href="{%url "task" build.pk task.pk%}">{{task.get_sstate_result_display|format_none_and_zero}}</a> | ||
107 | </td> | ||
108 | <td class="time_taken"> | ||
109 | {{task.elapsed_time|format_none_and_zero|floatformat:2}} | ||
110 | </td> | ||
111 | <td class="cpu_time_system"> | ||
112 | {{task.cpu_time_system|format_none_and_zero|floatformat:2}} | ||
113 | </td> | ||
114 | <td class="cpu_time_user"> | ||
115 | {{task.cpu_time_user|format_none_and_zero|floatformat:2}} | ||
116 | </td> | ||
117 | <td class="disk_io"> | ||
118 | {{task.disk_io|format_none_and_zero|intcomma}} | ||
119 | </td> | ||
120 | |||
121 | </tr> | ||
122 | {% endfor %} | ||
123 | |||
124 | {% include "basetable_bottom.html" %} | ||
125 | {% endif %} {# objects.paginator.count #} | ||
126 | {% endif %} {# empty #} | ||
127 | </div> | ||
128 | |||
129 | <script type="text/javascript"> | ||
130 | |||
131 | $(document).ready(function() { | ||
132 | // highlight heading on the column for the field used for ordering | ||
133 | if (location.href.search('#') > -1) { | ||
134 | var task_order = location.href.split('#')[1]; | ||
135 | $("#" + task_order).addClass("highlight"); | ||
136 | } | ||
137 | }); | ||
138 | |||
139 | </script> | ||
140 | |||
141 | {% endblock %} | ||
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py index 0636c956b2..c4913f124a 100644 --- a/bitbake/lib/toaster/toastergui/urls.py +++ b/bitbake/lib/toaster/toastergui/urls.py | |||
@@ -35,9 +35,11 @@ urlpatterns = patterns('toastergui.views', | |||
35 | 35 | ||
36 | # build info navigation | 36 | # build info navigation |
37 | url(r'^build/(?P<build_id>\d+)$', 'builddashboard', name="builddashboard"), | 37 | url(r'^build/(?P<build_id>\d+)$', 'builddashboard', name="builddashboard"), |
38 | url(r'^build/(?P<build_id>\d+)/tasks/$', | ||
39 | buildtables.BuildTasksTable.as_view( | ||
40 | template_name="buildinfo-toastertable.html"), | ||
41 | name='tasks'), | ||
38 | 42 | ||
39 | url(r'^build/(?P<build_id>\d+)/tasks/$', 'tasks', name='tasks'), | ||
40 | url(r'^build/(?P<build_id>\d+)/tasks/(?P<task_id>\d+)/$', 'tasks_task', name='tasks_task'), | ||
41 | url(r'^build/(?P<build_id>\d+)/task/(?P<task_id>\d+)$', 'task', name='task'), | 43 | url(r'^build/(?P<build_id>\d+)/task/(?P<task_id>\d+)$', 'task', name='task'), |
42 | 44 | ||
43 | url(r'^build/(?P<build_id>\d+)/recipes/$', | 45 | url(r'^build/(?P<build_id>\d+)/recipes/$', |
@@ -74,9 +76,20 @@ urlpatterns = patterns('toastergui.views', | |||
74 | url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/dirinfo_filepath/_(?P<file_path>(?:/[^/\n]+)*)$', 'dirinfo', name='dirinfo_filepath'), | 76 | url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/dirinfo_filepath/_(?P<file_path>(?:/[^/\n]+)*)$', 'dirinfo', name='dirinfo_filepath'), |
75 | url(r'^build/(?P<build_id>\d+)/configuration$', 'configuration', name='configuration'), | 77 | url(r'^build/(?P<build_id>\d+)/configuration$', 'configuration', name='configuration'), |
76 | url(r'^build/(?P<build_id>\d+)/configvars$', 'configvars', name='configvars'), | 78 | url(r'^build/(?P<build_id>\d+)/configvars$', 'configvars', name='configvars'), |
77 | url(r'^build/(?P<build_id>\d+)/buildtime$', 'buildtime', name='buildtime'), | 79 | url(r'^build/(?P<build_id>\d+)/buildtime$', |
78 | url(r'^build/(?P<build_id>\d+)/cputime$', 'cputime', name='cputime'), | 80 | buildtables.BuildTimeTable.as_view( |
79 | url(r'^build/(?P<build_id>\d+)/diskio$', 'diskio', name='diskio'), | 81 | template_name="buildinfo-toastertable.html"), |
82 | name='buildtime'), | ||
83 | |||
84 | url(r'^build/(?P<build_id>\d+)/cputime$', | ||
85 | buildtables.BuildCPUTimeTable.as_view( | ||
86 | template_name="buildinfo-toastertable.html"), | ||
87 | name='cputime'), | ||
88 | |||
89 | url(r'^build/(?P<build_id>\d+)/diskio$', | ||
90 | buildtables.BuildIOTable.as_view( | ||
91 | template_name="buildinfo-toastertable.html"), | ||
92 | name='diskio'), | ||
80 | 93 | ||
81 | # image information dir | 94 | # image information dir |
82 | url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/packagefile/(?P<packagefile_id>\d+)$', | 95 | url(r'^build/(?P<build_id>\d+)/target/(?P<target_id>\d+)/packagefile/(?P<packagefile_id>\d+)$', |
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 3a25d5ea1e..35ab63a22e 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
@@ -596,6 +596,7 @@ def task( request, build_id, task_id ): | |||
596 | 'log_body' : log_body, | 596 | 'log_body' : log_body, |
597 | 'showing_matches' : False, | 597 | 'showing_matches' : False, |
598 | 'uri_list' : uri_list, | 598 | 'uri_list' : uri_list, |
599 | 'task_in_tasks_table_pg': int(task_object.order / 25) + 1 | ||
599 | } | 600 | } |
600 | if request.GET.get( 'show_matches', "" ): | 601 | if request.GET.get( 'show_matches', "" ): |
601 | context[ 'showing_matches' ] = True | 602 | context[ 'showing_matches' ] = True |
@@ -995,285 +996,6 @@ def _find_task_provider(task_object): | |||
995 | return trc | 996 | return trc |
996 | return None | 997 | return None |
997 | 998 | ||
998 | def tasks_common(request, build_id, variant, task_anchor): | ||
999 | # This class is shared between these pages | ||
1000 | # | ||
1001 | # Column tasks buildtime diskio cpuusage | ||
1002 | # --------- ------ ---------- ------- --------- | ||
1003 | # Cache def | ||
1004 | # CPU min - | ||
1005 | # Disk min - | ||
1006 | # Executed def def def def | ||
1007 | # Log | ||
1008 | # Order def + | ||
1009 | # Outcome def def def def | ||
1010 | # Recipe min min min min | ||
1011 | # Version | ||
1012 | # Task min min min min | ||
1013 | # Time min - | ||
1014 | # | ||
1015 | # 'min':on always, 'def':on by default, else hidden | ||
1016 | # '+' default column sort up, '-' default column sort down | ||
1017 | |||
1018 | anchor = request.GET.get('anchor', '') | ||
1019 | if not anchor: | ||
1020 | anchor=task_anchor | ||
1021 | |||
1022 | # default ordering depends on variant | ||
1023 | default_orderby = None | ||
1024 | filter_search_display = 'tasks' | ||
1025 | |||
1026 | if 'buildtime' == variant: | ||
1027 | default_orderby = 'elapsed_time:-' | ||
1028 | title_variant = 'Time' | ||
1029 | object_search_display = 'time data' | ||
1030 | elif 'diskio' == variant: | ||
1031 | default_orderby = 'disk_io:-' | ||
1032 | title_variant = 'Disk I/O' | ||
1033 | object_search_display = 'disk I/O data' | ||
1034 | elif 'cputime' == variant: | ||
1035 | default_orderby = 'cpu_time_system:-' | ||
1036 | title_variant='CPU time' | ||
1037 | object_search_display = 'CPU time data' | ||
1038 | else: | ||
1039 | default_orderby = 'order:+' | ||
1040 | title_variant = 'Tasks' | ||
1041 | object_search_display = 'tasks' | ||
1042 | |||
1043 | (pagesize, orderby) = _get_parameters_values(request, 25, default_orderby) | ||
1044 | |||
1045 | mandatory_parameters = {'count': pagesize, 'page' : 1, 'orderby': orderby} | ||
1046 | |||
1047 | template = 'tasks.html' | ||
1048 | retval = _verify_parameters( request.GET, mandatory_parameters ) | ||
1049 | if retval: | ||
1050 | if task_anchor: | ||
1051 | mandatory_parameters['anchor']=task_anchor | ||
1052 | return _redirect_parameters( variant, request.GET, mandatory_parameters, build_id = build_id) | ||
1053 | (filter_string, search_term, ordering_string) = _search_tuple(request, Task) | ||
1054 | queryset_all = Task.objects.filter(build=build_id).exclude(order__isnull=True).exclude(outcome=Task.OUTCOME_NA) | ||
1055 | queryset_all = queryset_all.select_related("recipe", "build") | ||
1056 | |||
1057 | queryset_with_search = _get_queryset(Task, queryset_all, None , search_term, ordering_string, 'order') | ||
1058 | |||
1059 | if ordering_string.startswith('outcome'): | ||
1060 | queryset = _get_queryset(Task, queryset_all, filter_string, search_term, 'order:+', 'order') | ||
1061 | queryset = sorted(queryset, key=lambda ur: (ur.outcome_text), reverse=ordering_string.endswith('-')) | ||
1062 | elif ordering_string.startswith('sstate_result'): | ||
1063 | queryset = _get_queryset(Task, queryset_all, filter_string, search_term, 'order:+', 'order') | ||
1064 | queryset = sorted(queryset, key=lambda ur: (ur.sstate_text), reverse=ordering_string.endswith('-')) | ||
1065 | else: | ||
1066 | queryset = _get_queryset(Task, queryset_all, filter_string, search_term, ordering_string, 'order') | ||
1067 | |||
1068 | |||
1069 | # compute the anchor's page | ||
1070 | if anchor: | ||
1071 | request.GET = request.GET.copy() | ||
1072 | del request.GET['anchor'] | ||
1073 | i=0 | ||
1074 | a=int(anchor) | ||
1075 | count_per_page=int(pagesize) | ||
1076 | for task_object in queryset.iterator(): | ||
1077 | if a == task_object.order: | ||
1078 | new_page= (i / count_per_page ) + 1 | ||
1079 | request.GET.__setitem__('page', new_page) | ||
1080 | mandatory_parameters['page']=new_page | ||
1081 | return _redirect_parameters( variant, request.GET, mandatory_parameters, build_id = build_id) | ||
1082 | i += 1 | ||
1083 | |||
1084 | task_objects = _build_page_range(Paginator(queryset, pagesize),request.GET.get('page', 1)) | ||
1085 | |||
1086 | # define (and modify by variants) the 'tablecols' members | ||
1087 | tc_order={ | ||
1088 | 'name':'Order', | ||
1089 | 'qhelp':'The running sequence of each task in the build', | ||
1090 | 'clclass': 'order', 'hidden' : 1, | ||
1091 | 'orderkey' : 'order', | ||
1092 | 'orderfield':_get_toggle_order(request, "order"), | ||
1093 | 'ordericon':_get_toggle_order_icon(request, "order")} | ||
1094 | if 'tasks' == variant: | ||
1095 | tc_order['hidden']='0' | ||
1096 | del tc_order['clclass'] | ||
1097 | |||
1098 | tc_recipe={ | ||
1099 | 'name':'Recipe', | ||
1100 | 'qhelp':'The name of the recipe to which each task applies', | ||
1101 | 'orderkey' : 'recipe__name', | ||
1102 | 'orderfield': _get_toggle_order(request, "recipe__name"), | ||
1103 | 'ordericon':_get_toggle_order_icon(request, "recipe__name"), | ||
1104 | } | ||
1105 | tc_recipe_version={ | ||
1106 | 'name':'Recipe version', | ||
1107 | 'qhelp':'The version of the recipe to which each task applies', | ||
1108 | 'clclass': 'recipe_version', 'hidden' : 1, | ||
1109 | } | ||
1110 | tc_task={ | ||
1111 | 'name':'Task', | ||
1112 | 'qhelp':'The name of the task', | ||
1113 | 'orderfield': _get_toggle_order(request, "task_name"), | ||
1114 | 'ordericon':_get_toggle_order_icon(request, "task_name"), | ||
1115 | 'orderkey' : 'task_name', | ||
1116 | } | ||
1117 | tc_executed={ | ||
1118 | 'name':'Executed', | ||
1119 | 'qhelp':"This value tells you if a task had to run (executed) in order to generate the task output, or if the output was provided by another task and therefore the task didn't need to run (not executed)", | ||
1120 | 'clclass': 'executed', 'hidden' : 0, | ||
1121 | 'orderfield': _get_toggle_order(request, "task_executed"), | ||
1122 | 'ordericon':_get_toggle_order_icon(request, "task_executed"), | ||
1123 | 'orderkey' : 'task_executed', | ||
1124 | 'filter' : { | ||
1125 | 'class' : 'executed', | ||
1126 | 'label': 'Show:', | ||
1127 | 'options' : [ | ||
1128 | ('Executed Tasks', 'task_executed:1', queryset_with_search.filter(task_executed=1).count()), | ||
1129 | ('Not Executed Tasks', 'task_executed:0', queryset_with_search.filter(task_executed=0).count()), | ||
1130 | ] | ||
1131 | } | ||
1132 | |||
1133 | } | ||
1134 | tc_outcome={ | ||
1135 | 'name':'Outcome', | ||
1136 | 'qhelp':"This column tells you if 'executed' tasks succeeded or failed. The column also tells you why 'not executed' tasks did not need to run", | ||
1137 | 'clclass': 'outcome', 'hidden' : 0, | ||
1138 | 'orderfield': _get_toggle_order(request, "outcome"), | ||
1139 | 'ordericon':_get_toggle_order_icon(request, "outcome"), | ||
1140 | 'orderkey' : 'outcome', | ||
1141 | 'filter' : { | ||
1142 | 'class' : 'outcome', | ||
1143 | 'label': 'Show:', | ||
1144 | 'options' : [ | ||
1145 | ('Succeeded Tasks', 'outcome:%d'%Task.OUTCOME_SUCCESS, queryset_with_search.filter(outcome=Task.OUTCOME_SUCCESS).count(), "'Succeeded' tasks are those that ran and completed during the build" ), | ||
1146 | ('Failed Tasks', 'outcome:%d'%Task.OUTCOME_FAILED, queryset_with_search.filter(outcome=Task.OUTCOME_FAILED).count(), "'Failed' tasks are those that ran but did not complete during the build"), | ||
1147 | ('Cached Tasks', 'outcome:%d'%Task.OUTCOME_CACHED, queryset_with_search.filter(outcome=Task.OUTCOME_CACHED).count(), 'Cached tasks restore output from the <code>sstate-cache</code> directory or mirrors'), | ||
1148 | ('Prebuilt Tasks', 'outcome:%d'%Task.OUTCOME_PREBUILT, queryset_with_search.filter(outcome=Task.OUTCOME_PREBUILT).count(),'Prebuilt tasks didn\'t need to run because their output was reused from a previous build'), | ||
1149 | ('Covered Tasks', 'outcome:%d'%Task.OUTCOME_COVERED, queryset_with_search.filter(outcome=Task.OUTCOME_COVERED).count(), 'Covered tasks didn\'t need to run because their output is provided by another task in this build'), | ||
1150 | ('Empty Tasks', 'outcome:%d'%Task.OUTCOME_EMPTY, queryset_with_search.filter(outcome=Task.OUTCOME_EMPTY).count(), 'Empty tasks have no executable content'), | ||
1151 | ] | ||
1152 | } | ||
1153 | |||
1154 | } | ||
1155 | |||
1156 | tc_cache={ | ||
1157 | 'name':'Cache attempt', | ||
1158 | 'qhelp':'This column tells you if a task tried to restore output from the <code>sstate-cache</code> directory or mirrors, and reports the result: Succeeded, Failed or File not in cache', | ||
1159 | 'clclass': 'cache_attempt', 'hidden' : 0, | ||
1160 | 'orderfield': _get_toggle_order(request, "sstate_result"), | ||
1161 | 'ordericon':_get_toggle_order_icon(request, "sstate_result"), | ||
1162 | 'orderkey' : 'sstate_result', | ||
1163 | 'filter' : { | ||
1164 | 'class' : 'cache_attempt', | ||
1165 | 'label': 'Show:', | ||
1166 | 'options' : [ | ||
1167 | ('Tasks with cache attempts', 'sstate_result__gt:%d'%Task.SSTATE_NA, queryset_with_search.filter(sstate_result__gt=Task.SSTATE_NA).count(), 'Show all tasks that tried to restore ouput from the <code>sstate-cache</code> directory or mirrors'), | ||
1168 | ("Tasks with 'File not in cache' attempts", 'sstate_result:%d'%Task.SSTATE_MISS, queryset_with_search.filter(sstate_result=Task.SSTATE_MISS).count(), 'Show tasks that tried to restore output, but did not find it in the <code>sstate-cache</code> directory or mirrors'), | ||
1169 | ("Tasks with 'Failed' cache attempts", 'sstate_result:%d'%Task.SSTATE_FAILED, queryset_with_search.filter(sstate_result=Task.SSTATE_FAILED).count(), 'Show tasks that found the required output in the <code>sstate-cache</code> directory or mirrors, but could not restore it'), | ||
1170 | ("Tasks with 'Succeeded' cache attempts", 'sstate_result:%d'%Task.SSTATE_RESTORED, queryset_with_search.filter(sstate_result=Task.SSTATE_RESTORED).count(), 'Show tasks that successfully restored the required output from the <code>sstate-cache</code> directory or mirrors'), | ||
1171 | ] | ||
1172 | } | ||
1173 | |||
1174 | } | ||
1175 | #if 'tasks' == variant: tc_cache['hidden']='0'; | ||
1176 | tc_time={ | ||
1177 | 'name':'Time (secs)', | ||
1178 | 'qhelp':'How long it took the task to finish in seconds', | ||
1179 | 'orderfield': _get_toggle_order(request, "elapsed_time", True), | ||
1180 | 'ordericon':_get_toggle_order_icon(request, "elapsed_time"), | ||
1181 | 'orderkey' : 'elapsed_time', | ||
1182 | 'clclass': 'time_taken', 'hidden' : 1, | ||
1183 | } | ||
1184 | if 'buildtime' == variant: | ||
1185 | tc_time['hidden']='0' | ||
1186 | del tc_time['clclass'] | ||
1187 | tc_cache['hidden']='1' | ||
1188 | |||
1189 | tc_cpu_time_system={ | ||
1190 | 'name':'System CPU time (secs)', | ||
1191 | 'qhelp':'Total amount of time spent executing in kernel mode, in ' + | ||
1192 | 'seconds. Note that this time can be greater than the task ' + | ||
1193 | 'time due to parallel execution.', | ||
1194 | 'orderfield': _get_toggle_order(request, "cpu_time_system", True), | ||
1195 | 'ordericon':_get_toggle_order_icon(request, "cpu_time_system"), | ||
1196 | 'orderkey' : 'cpu_time_system', | ||
1197 | 'clclass': 'cpu_time_system', 'hidden' : 1, | ||
1198 | } | ||
1199 | |||
1200 | tc_cpu_time_user={ | ||
1201 | 'name':'User CPU time (secs)', | ||
1202 | 'qhelp':'Total amount of time spent executing in user mode, in seconds. ' + | ||
1203 | 'Note that this time can be greater than the task time due to ' + | ||
1204 | 'parallel execution.', | ||
1205 | 'orderfield': _get_toggle_order(request, "cpu_time_user", True), | ||
1206 | 'ordericon':_get_toggle_order_icon(request, "cpu_time_user"), | ||
1207 | 'orderkey' : 'cpu_time_user', | ||
1208 | 'clclass': 'cpu_time_user', 'hidden' : 1, | ||
1209 | } | ||
1210 | |||
1211 | if 'cputime' == variant: | ||
1212 | tc_cpu_time_system['hidden']='0' | ||
1213 | tc_cpu_time_user['hidden']='0' | ||
1214 | del tc_cpu_time_system['clclass'] | ||
1215 | del tc_cpu_time_user['clclass'] | ||
1216 | tc_cache['hidden']='1' | ||
1217 | |||
1218 | tc_diskio={ | ||
1219 | 'name':'Disk I/O (bytes)', | ||
1220 | 'qhelp':'Number of bytes written to and read from the disk during the task', | ||
1221 | 'orderfield': _get_toggle_order(request, "disk_io", True), | ||
1222 | 'ordericon':_get_toggle_order_icon(request, "disk_io"), | ||
1223 | 'orderkey' : 'disk_io', | ||
1224 | 'clclass': 'disk_io', 'hidden' : 1, | ||
1225 | } | ||
1226 | if 'diskio' == variant: | ||
1227 | tc_diskio['hidden']='0' | ||
1228 | del tc_diskio['clclass'] | ||
1229 | tc_cache['hidden']='1' | ||
1230 | |||
1231 | build = Build.objects.get(pk=build_id) | ||
1232 | |||
1233 | context = { 'objectname': variant, | ||
1234 | 'object_search_display': object_search_display, | ||
1235 | 'filter_search_display': filter_search_display, | ||
1236 | 'mainheading': title_variant, | ||
1237 | 'build': build, | ||
1238 | 'project': build.project, | ||
1239 | 'objects': task_objects, | ||
1240 | 'default_orderby' : default_orderby, | ||
1241 | 'search_term': search_term, | ||
1242 | 'total_count': queryset_with_search.count(), | ||
1243 | 'tablecols':[ | ||
1244 | tc_order, | ||
1245 | tc_recipe, | ||
1246 | tc_recipe_version, | ||
1247 | tc_task, | ||
1248 | tc_executed, | ||
1249 | tc_outcome, | ||
1250 | tc_cache, | ||
1251 | tc_time, | ||
1252 | tc_cpu_time_system, | ||
1253 | tc_cpu_time_user, | ||
1254 | tc_diskio, | ||
1255 | ]} | ||
1256 | |||
1257 | |||
1258 | response = render(request, template, context) | ||
1259 | _set_parameters_values(pagesize, orderby, request) | ||
1260 | return response | ||
1261 | |||
1262 | def tasks(request, build_id): | ||
1263 | return tasks_common(request, build_id, 'tasks', '') | ||
1264 | |||
1265 | def tasks_task(request, build_id, task_id): | ||
1266 | return tasks_common(request, build_id, 'tasks', task_id) | ||
1267 | |||
1268 | def buildtime(request, build_id): | ||
1269 | return tasks_common(request, build_id, 'buildtime', '') | ||
1270 | |||
1271 | def diskio(request, build_id): | ||
1272 | return tasks_common(request, build_id, 'diskio', '') | ||
1273 | |||
1274 | def cputime(request, build_id): | ||
1275 | return tasks_common(request, build_id, 'cputime', '') | ||
1276 | |||
1277 | def configuration(request, build_id): | 999 | def configuration(request, build_id): |
1278 | template = 'configuration.html' | 1000 | template = 'configuration.html' |
1279 | 1001 | ||