[LNT] r343462 - Introduce Latest Runs Report.

Martin Liska via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 1 05:20:54 PDT 2018


Author: marxin
Date: Mon Oct  1 05:20:54 2018
New Revision: 343462

URL: http://llvm.org/viewvc/llvm-project?rev=343462&view=rev
Log:
Introduce Latest Runs Report.

Differential Revision: https://reviews.llvm.org/D51405

Modified:
    lnt/trunk/lnt/server/reporting/dailyreport.py
    lnt/trunk/lnt/server/ui/templates/layout.html
    lnt/trunk/lnt/server/ui/templates/reporting/daily_report.html
    lnt/trunk/lnt/server/ui/views.py
    lnt/trunk/tests/server/ui/V4Pages.py

Modified: lnt/trunk/lnt/server/reporting/dailyreport.py
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/server/reporting/dailyreport.py?rev=343462&r1=343461&r2=343462&view=diff
==============================================================================
--- lnt/trunk/lnt/server/reporting/dailyreport.py (original)
+++ lnt/trunk/lnt/server/reporting/dailyreport.py Mon Oct  1 05:20:54 2018
@@ -1,7 +1,7 @@
 from collections import namedtuple
 from lnt.server.reporting.analysis import REGRESSED, UNCHANGED_FAIL
+from lnt.server.reporting.report import RunResult, RunResults, report_css_styles, pairs, OrderAndHistory
 from lnt.util import multidict
-import colorsys
 import datetime
 import lnt.server.reporting.analysis
 import lnt.server.ui.app
@@ -9,118 +9,6 @@ import re
 import sqlalchemy.sql
 import urllib
 
-OrderAndHistory = namedtuple('OrderAndHistory', ['max_order', 'recent_orders'])
-
-
-def _pairs(list):
-    return zip(list[:-1], list[1:])
-
-
-# The hash color palette avoids green and red as these colours are already used
-# in quite a few places to indicate "good" or "bad".
-_hash_color_palette = (
-    colorsys.hsv_to_rgb(h=45. / 360, s=0.3, v=0.9999),  # warm yellow
-    colorsys.hsv_to_rgb(h=210. / 360, s=0.3, v=0.9999),  # blue cyan
-    colorsys.hsv_to_rgb(h=300. / 360, s=0.3, v=0.9999),  # mid magenta
-    colorsys.hsv_to_rgb(h=150. / 360, s=0.3, v=0.9999),  # green cyan
-    colorsys.hsv_to_rgb(h=225. / 360, s=0.3, v=0.9999),  # cool blue
-    colorsys.hsv_to_rgb(h=180. / 360, s=0.3, v=0.9999),  # mid cyan
-)
-
-
-def _clamp(v, minVal, maxVal):
-    return min(max(v, minVal), maxVal)
-
-
-def _toColorString(col):
-    r, g, b = [_clamp(int(v * 255), 0, 255)
-               for v in col]
-    return "#%02x%02x%02x" % (r, g, b)
-
-
-def _get_rgb_colors_for_hashes(hash_strings):
-    hash2color = {}
-    unique_hash_counter = 0
-    for hash_string in hash_strings:
-        if hash_string is not None:
-            if hash_string in hash2color:
-                continue
-            hash2color[hash_string] = _hash_color_palette[unique_hash_counter]
-            unique_hash_counter += 1
-            if unique_hash_counter >= len(_hash_color_palette):
-                break
-    result = []
-    for hash_string in hash_strings:
-        if hash_string is None:
-            result.append(None)
-        else:
-            # If not one of the first N hashes, return rgb value 0,0,0 which is
-            # white.
-            rgb = hash2color.get(hash_string, (0.999, 0.999, 0.999))
-            result.append(_toColorString(rgb))
-    return result
-
-
-# Helper classes to make the sparkline chart construction easier in the jinja
-# template.
-class DayResult:
-    def __init__(self, comparisonResult):
-        self.cr = comparisonResult
-        self.hash = self.cr.cur_hash
-        self.samples = self.cr.samples
-        if self.samples is None:
-            self.samples = []
-
-
-class DayResults:
-    """
-    DayResults contains pre-processed data to easily construct the HTML for
-    a single row in the results table, showing how one test on one board
-    evolved over a number of runs/days.
-    """
-    def __init__(self):
-        self.day_results = []
-        self._complete = False
-        self.min_sample = None
-        self.max_sample = None
-
-    def __getitem__(self, i):
-        return self.day_results[i]
-
-    def __len__(self):
-        return len(self.day_results)
-
-    def append(self, day_result):
-        assert not self._complete
-        self.day_results.append(day_result)
-
-    def complete(self):
-        """
-        complete() needs to be called after all appends to this object, but
-        before the data is used the jinja template.
-        """
-        self._complete = True
-        all_samples = []
-        for dr in self.day_results:
-            if dr is None:
-                continue
-            if dr.cr.samples is not None and not dr.cr.failed:
-                all_samples.extend(dr.cr.samples)
-        if len(all_samples) > 0:
-            self.min_sample = min(all_samples)
-            self.max_sample = max(all_samples)
-        hashes = []
-        for dr in self.day_results:
-            if dr is None:
-                hashes.append(None)
-            else:
-                hashes.append(dr.hash)
-        rgb_colors = _get_rgb_colors_for_hashes(hashes)
-        for i, dr in enumerate(self.day_results):
-            if dr is not None:
-                dr.hash_rgb_color = rgb_colors[i]
-
-
 class DailyReport(object):
     def __init__(self, ts, year, month, day, num_prior_days_to_include=3,
                  day_start_offset_hours=16, for_mail=False,
@@ -212,7 +100,7 @@ class DailyReport(object):
         prior_runs = [session.query(ts.Run).
                       filter(ts.Run.start_time > prior_day).
                       filter(ts.Run.start_time <= day).all()
-                      for day, prior_day in _pairs(self.prior_days)]
+                      for day, prior_day in pairs(self.prior_days)]
 
         if self.filter_machine_re is not None:
             prior_runs = [[run for run in runs
@@ -380,8 +268,8 @@ class DailyReport(object):
                         continue
 
                     # Otherwise, compute the results for all the days.
-                    day_results = DayResults()
-                    day_results.append(DayResult(cr))
+                    day_results = RunResults()
+                    day_results.append(RunResult(cr))
                     for i in range(1, self.num_prior_days_to_include):
                         day_runs = machine_runs.get((machine.id, i), ())
                         if len(day_runs) == 0:
@@ -394,7 +282,7 @@ class DailyReport(object):
                         cr = sri.get_comparison_result(
                             day_runs, prev_runs, test.id, field,
                             self.hash_of_binary_field)
-                        day_results.append(DayResult(cr))
+                        day_results.append(RunResult(cr))
 
                     day_results.complete()
 
@@ -431,23 +319,6 @@ class DailyReport(object):
         env = lnt.server.ui.app.create_jinja_environment()
         template = env.get_template('reporting/daily_report.html')
 
-        # Compute static CSS styles for elements. We use the style directly on
-        # elements instead of via a stylesheet to support major email clients
-        # (like Gmail) which can't deal with embedded style sheets.
-        #
-        # These are derived from the static style.css file we use elsewhere.
-        styles = {
-            "body": ("color:#000000; background-color:#ffffff; "
-                     "font-family: Helvetica, sans-serif; font-size:9pt"),
-            "table": ("font-size:9pt; border-spacing: 0px; "
-                      "border: 1px solid black"),
-            "th": (
-                "background-color:#eee; color:#666666; font-weight: bold; "
-                "cursor: default; text-align:center; font-weight: bold; "
-                "font-family: Verdana; padding:5px; padding-left:8px"),
-            "td": "padding:5px; padding-left:8px",
-        }
-
         return template.render(
-            report=self, styles=styles, analysis=lnt.server.reporting.analysis,
+            report=self, styles=report_css_styles, analysis=lnt.server.reporting.analysis,
             ts_url=ts_url, only_html_body=only_html_body)

Modified: lnt/trunk/lnt/server/ui/templates/layout.html
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/server/ui/templates/layout.html?rev=343462&r1=343461&r2=343462&view=diff
==============================================================================
--- lnt/trunk/lnt/server/ui/templates/layout.html (original)
+++ lnt/trunk/lnt/server/ui/templates/layout.html Mon Oct  1 05:20:54 2018
@@ -161,6 +161,7 @@
                               <li><a href="{{ v4_url_for('.v4_recent_activity') }}">Recent Activity</a></li>
                               <li><a href="{{ v4_url_for('.v4_global_status') }}">Global Status</a></li>
                               <li><a href="{{ v4_url_for('.v4_daily_report_overview') }}">Daily Report</a></li>
+                              <li><a href="{{ v4_url_for('.v4_latest_runs_report') }}">Latest Runs Report</a></li>
                               <li><a href="{{ v4_url_for('.v4_machines') }}">All Machines</a></li>
                                <li class="divider"></li>
                               <li class="disabled"><a href="#">Changes</a></li>

Modified: lnt/trunk/lnt/server/ui/templates/reporting/daily_report.html
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/server/ui/templates/reporting/daily_report.html?rev=343462&r1=343461&r2=343462&view=diff
==============================================================================
--- lnt/trunk/lnt/server/ui/templates/reporting/daily_report.html (original)
+++ lnt/trunk/lnt/server/ui/templates/reporting/daily_report.html Mon Oct  1 05:20:54 2018
@@ -1,4 +1,5 @@
 {% import "utils.html" as utils %}
+{% import "reportutils.html" as reportutils %}
 {% if not only_html_body %}
 <html>
 <head>
@@ -110,39 +111,6 @@
   </tbody>
 </table>
 
-{% macro get_initial_cell_value(day_result) %}
-{%- set cr = day_result.cr -%}
-{%- set test_status = cr.get_test_status() -%}
-
-{%- if (test_status == analysis.REGRESSED or
-       test_status == analysis.UNCHANGED_FAIL) %}
-    <td style="{{ styles.td }}; background-color:#e98080">FAIL</td>
-{%- else %}
-    <td style="{{ styles.td }}; background-color:#d2d2d2"> {#- -#}
-      {{ ("%.4f" % cr.current) if cr.current != none else "N/A" }}</td>
-{%- endif -%}
-
-{% endmacro %}
-
-{% macro get_cell_value(day_result) %}
-{%- set cr = day_result.cr -%}
-{%- set test_status = cr.get_test_status() -%}
-{%- set value_status = cr.get_value_status() -%}
-{%- if (test_status == analysis.REGRESSED or
-       test_status == analysis.UNCHANGED_FAIL) %}
-    <td style="{{ styles.td }}; background-color:#e98080">FAIL</td>
-{%- elif test_status == analysis.IMPROVED %}
-    <td style="{{ styles.td }}; background-color:#8fdf5f">PASS</td>
-{%- else -%}
-{%- if (value_status == analysis.REGRESSED or
-       value_status == analysis.IMPROVED) %}
-    {{ cr.pct_delta|aspctcell(reverse=cr.bigger_is_better)|safe }}
-{%- else %}
-    <td style="{{ styles.td }}">-</td>
-{%- endif -%}
-{%- endif -%}
-{% endmacro %}
-
 {# Generate the table showing the raw sample data. #}
 
 {# If the report is for mail, we put the table header on each test. This is
@@ -164,73 +132,6 @@
   </thead>
 {% endmacro %}
 
-{% macro spark_plot(day_results) %}
-{%- set x_border_size = 5 %}
-{%- set y_border_size = 2 %}
-{%- set height = 18 %}
-{%- set full_height = height + 2*y_border_size %}
-{%- set x_day_spacing = 10 %}
-{%- set sample_fuzzing = 0.5 %}
-{%- set nr_days = day_results|length %}
-{%- set width = x_day_spacing * nr_days + 2*x_border_size %}
-{%- if day_results.max_sample != day_results.min_sample %}
-  {%- set scaling_factor = (1.0*height)
-         / (day_results.max_sample-day_results.min_sample) -%}
-{%- else %}
-  {%- set scaling_factor = 1.0 -%}
-{%- endif %}
-{%- macro spark_y_coord(day_nr, value) -%}
-  {{ (value-day_results.min_sample) * scaling_factor + y_border_size }}
-{%- endmacro -%}
-{%- macro spark_x_coord(day_nr) -%}
-  {{ (nr_days - day_nr) * x_day_spacing + x_border_size }}
-{%- endmacro -%}
-{%- macro spark_hash_background(day_nr, dr) -%}
-  {%- if dr.cr.cur_hash is not none -%}
-    {%- set style = "fill: "+dr.hash_rgb_color+";" -%}
-  {%- else -%}
-    {%- set style = "fill: none;" -%}
-  {%- endif -%}
-    <rect x="{{(nr_days-day_nr-0.5) * x_day_spacing + x_border_size}}" y="0"
-          width="{{x_day_spacing}}" height="{{full_height}}" style="{{style}}"/>
-{%- endmacro -%}
-    <span>
-      <svg width="{{width}}" height="{{full_height}}">
-      <rect width="{{width}}" height="{{full_height}}" fill="#f7f7f7"/>
-{#- Make y-axis go upwards instead of downwards: #}
-      <g transform="translate(0, {{full_height}}) scale(1, -1) ">
-{%- for dr in day_results -%}
-  {%- if dr is not none and not dr.cr.failed -%}
-    {%- set day_nr = loop.index %}
-    {%- set nr_samples_for_day = dr.samples|length %}
-        {{ spark_hash_background(day_nr, dr) }}
-    {%- for sample in dr.samples -%}
-      {# fuzz the x-coordinate slightly so that multiple samples with the same
-         value can be noticed #}
-      {%- set sample_fuzz = (-sample_fuzzing*1.25) +
-                       (2.0*sample_fuzzing/nr_samples_for_day) * loop.index %}
-        <circle cx="{{ spark_x_coord(day_nr)|float + sample_fuzz }}" {# -#}
-                cy="{{ spark_y_coord(day_nr, sample) }}" r="1"
-                stroke-width="1" stroke="black" fill="black" />
-    {%- endfor -%}
-  {%- endif -%}
-{%- endfor %}
-        <polyline points="
-  {%- for dr in day_results -%}
-    {%- if dr is not none -%}
-      {%- set cr = dr.cr -%}
-      {%- set day_nr = loop.index -%}
-      {%- if not cr.failed and cr.current is not none %}
-          {{ spark_x_coord(day_nr) }} {{ spark_y_coord(day_nr, cr.current) }}
-      {%- endif -%}
-    {%- endif -%}
-  {%- endfor -%}
-          " fill="none" stroke="red" stroke-width="1"/>
-        </g>
-      </svg>
-    </span>
-{%- endmacro %}
-
 {% for field,field_results in report.result_table|reverse %}
 {%- if field_results -%}
 <h3>Result Table ({{ field.display_name }})</h3>
@@ -255,14 +156,14 @@
     <td style="{{ styles.td }}">-</td>
 {%-      else -%}
 {%-        if first_result_shown -%}
-    {{ get_cell_value(day_result) }}
+    {{ reportutils.get_cell_value(day_result, analysis, styles) }}
 {%-        else -%}
 {%-        set first_result_shown = true -%}
-    {{ get_initial_cell_value(day_result) }}
+    {{ reportutils.get_initial_cell_value(day_result, analysis, styles) }}
 {%-        endif -%}
 {%-      endif -%}
 {%-    endfor %}
-    <td>{{ spark_plot(day_results) }}</td>
+    <td>{{ reportutils.spark_plot(day_results) }}</td>
   </tr>
 {%-  endfor %}
 {{ "</tbody></table><p>" if report.for_mail }}

Modified: lnt/trunk/lnt/server/ui/views.py
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/server/ui/views.py?rev=343462&r1=343461&r2=343462&view=diff
==============================================================================
--- lnt/trunk/lnt/server/ui/views.py (original)
+++ lnt/trunk/lnt/server/ui/views.py Mon Oct  1 05:20:54 2018
@@ -26,6 +26,7 @@ import lnt.server.db.rules_manager
 import lnt.server.db.search
 import lnt.server.reporting.analysis
 import lnt.server.reporting.dailyreport
+import lnt.server.reporting.latestrunsreport
 import lnt.server.reporting.runs
 import lnt.server.reporting.summaryreport
 import lnt.server.ui.util
@@ -1513,6 +1514,23 @@ def v4_summary_report_ui():
                            config=config, all_machines=all_machines,
                            all_orders=all_orders, **ts_data(ts))
 
+ at v4_route("/latest_runs_report")
+def v4_latest_runs_report():
+    session = request.session
+    ts = request.get_testsuite()
+
+    num_runs_str = request.args.get('num_runs')
+    if num_runs_str is not None:
+        num_runs = int(num_runs_str)
+    else:
+        num_runs = 10
+
+    report = lnt.server.reporting.latestrunsreport.LatestRunsReport(ts, num_runs)
+    report.build(request.session)
+
+    return render_template("v4_latest_runs_report.html", report=report,
+                           analysis=lnt.server.reporting.analysis,
+                           **ts_data(ts))
 
 @db_route("/summary_report")
 def v4_summary_report():

Modified: lnt/trunk/tests/server/ui/V4Pages.py
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/tests/server/ui/V4Pages.py?rev=343462&r1=343461&r2=343462&view=diff
==============================================================================
--- lnt/trunk/tests/server/ui/V4Pages.py (original)
+++ lnt/trunk/tests/server/ui/V4Pages.py Mon Oct  1 05:20:54 2018
@@ -537,6 +537,9 @@ def main():
     assert color2 is None
     assert color1 != color3
 
+    # Check some variations of the latest runs report work.
+    check_html(client, '/v4/nts/latest_runs_report')
+
     check_redirect(client, '/db_default/submitRun',
                    '/db_default/v4/nts/submitRun')
     check_html(client, '/db_default/v4/nts/submitRun')




More information about the llvm-commits mailing list