Completed
Push — master ( 713211...3caa84 )
by Vitalii
53s queued 21s
created

flops_graph()   B

Complexity

Conditions 8
Paths 60

Size

Total Lines 39
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 8
eloc 28
c 1
b 0
f 1
nc 60
nop 1
dl 0
loc 39
rs 8.4444
1
<?php
2
// This file is part of BOINC.
3
// https://boinc.berkeley.edu
4
// Copyright (C) 2025 University of California
5
//
6
// BOINC is free software; you can redistribute it and/or modify it
7
// under the terms of the GNU Lesser General Public License
8
// as published by the Free Software Foundation,
9
// either version 3 of the License, or (at your option) any later version.
10
//
11
// BOINC is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
// See the GNU Lesser General Public License for more details.
15
//
16
// You should have received a copy of the GNU Lesser General Public License
17
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18
19
// show various stats of batches:
20
// err_host
21
//      list of hosts with the most errors
22
// err_code
23
//      list of exit codes with most errors
24
// flops_graph
25
//      histogram of average CPU hours
26
27
require_once('../inc/util.inc');
28
require_once('../inc/result.inc');
29
30
function err_host($batch) {
31
    $results = BoincResult::enum_fields(
32
        'hostid',
33
        sprintf('batch=%d and outcome=%d',
34
            $batch->id,
35
            RESULT_OUTCOME_CLIENT_ERROR
36
        )
37
    );
38
    $x = [];
39
    foreach ($results as $r) {
40
        $id = $r->hostid;
41
        if (array_key_exists($id, $x)) {
42
            $x[$id] += 1;
43
        } else {
44
            $x[$id] = 1;
45
        }
46
    }
47
    if (!$x) error_page('That batch had no error results');
48
    page_head('Errors by host');
49
    text_start();
50
    arsort($x);
51
    start_table();
52
    table_header('Host', '# errors');
53
    $n = 0;
54
    foreach ($x as $id=>$count) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "=>"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after "=>"; 0 found
Loading history...
55
        $host = BoincHost::lookup_id($id);
56
        table_row(
57
            "<a href=show_host_detail.php?hostid=$id>$host->domain_name</a>",
58
            sprintf(
59
                '<a href=submit_stats.php?action=host_list&host_id=%d&batch_id=%d>%d</a>',
60
                $id, $batch->id, $count
61
            )
62
        );
63
        if (++$n == 20) break;
64
    }
65
    text_end();
66
    end_table();
67
    page_tail();
68
}
69
70
function err_code($batch) {
71
    $results = BoincResult::enum_fields(
72
        'exit_status',
73
        sprintf('batch=%d and outcome=%d',
74
            $batch->id,
75
            RESULT_OUTCOME_CLIENT_ERROR
76
        )
77
    );
78
    $x = [];
79
    foreach ($results as $r) {
80
        $id = $r->exit_status;
81
        if (array_key_exists($id, $x)) {
82
            $x[$id] += 1;
83
        } else {
84
            $x[$id] = 1;
85
        }
86
    }
87
    if (!$x) error_page('That batch had no error results');
88
    page_head('Errors by exit code');
89
    text_start();
90
    arsort($x);
91
    start_table();
92
    table_header('Code', '# errors');
93
    $n = 0;
94
    foreach ($x as $id=>$count) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "=>"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after "=>"; 0 found
Loading history...
95
        table_row(
96
            exit_status_string($id),
97
            sprintf(
98
                '<a href=submit_stats.php?action=code_list&code=%d&batch_id=%d>%d</a>',
99
                $id, $batch->id, $count
100
            )
101
        );
102
        if (++$n == 20) break;
103
    }
104
    text_end();
105
    end_table();
106
    page_tail();
107
}
108
109
// list of error results from a host
110
//
111
function host_list($batch_id, $host_id) {
112
    page_head("Errors for batch $batch_id, host $host_id");
113
    $results = BoincResult::enum(
114
        sprintf('batch=%d and hostid=%d and outcome=%d',
115
            $batch_id, $host_id, RESULT_OUTCOME_CLIENT_ERROR
116
        )
117
    );
118
119
    start_table();
120
    table_header('Job instance', 'Exit status');
121
    foreach ($results as $r) {
122
        table_row(
123
            "<a href=result.php?resultid=$r->id>$r->name</a>",
124
            exit_status_string($r->exit_status)
125
        );
126
    }
127
    end_table();
128
    page_tail();
129
}
130
131
// list of error results with given code
132
//
133
function code_list($batch_id, $code) {
134
    page_head("Errors for batch $batch_id, exit code $code");
135
    $results = BoincResult::enum(
136
        sprintf('batch=%d and exit_status=%d and outcome=%d',
137
            $batch_id, $code, RESULT_OUTCOME_CLIENT_ERROR
138
        )
139
    );
140
141
    start_table();
142
    table_header('Job instance');
143
    foreach ($results as $r) {
144
        table_row(
145
            "<a href=result.php?resultid=$r->id>$r->name</a>"
146
        );
147
    }
148
    end_table();
149
    page_tail();
150
}
151
152
function graph($data, $xlabel, $ylabel) {
153
    echo "
154
    <script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>
155
    <script type=\"text/javascript\">
156
      google.charts.load('current', {'packages':['corechart']});
157
      google.charts.setOnLoadCallback(drawChart);
158
159
      function drawChart() {
160
        var data = google.visualization.arrayToDataTable([
161
";
162
    echo "['$xlabel','$ylabel'],\n";
163
    foreach ($data as [$x, $y]) {
164
        echo "[$x, $y],\n";
165
    }
166
    echo "
167
        ]);
168
169
        var options = {
170
          title: 'Job runtime (hours)',
171
          legend:  'none'
172
        };
173
174
        var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));
175
176
        chart.draw(data, options);
177
      }
178
    </script>
179
    ";
180
    echo "
181
    <div id=\"curve_chart\" style=\"width: 900px; height: 500px\"></div>
182
    ";
183
}
184
185
function flops_graph($batch) {
186
    page_head("Batch $batch->id job runtimes");
187
    echo "
188
    <p>
189
    Runtimes of completed jobs, normalized to an average (4.3 GFLOPS) computer.
190
    <p>
191
    ";
192
    $results = BoincResult::enum_fields(
193
        'flops_estimate*elapsed_time as flops',
194
        sprintf('batch=%d and outcome=%d',
195
            $batch->id, RESULT_OUTCOME_SUCCESS
196
        )
197
    );
198
    $x = [];
199
    $min = 1e99;
200
    $max = 0;
201
    foreach ($results as $r) {
202
        $f = $r->flops / (4.3e9 *3600);
203
        if ($f > $max) $max = $f;
204
        if ($f < $min) $min = $f;
205
        $x[] = $f;
206
    }
207
    $n = 800;
208
    $count = [];
209
    for ($i=0; $i<$n; $i++) {
210
        $count[$i] = 0;
211
    }
212
    $range = $max - $min;
213
    foreach ($x as $f) {
214
        $d = intval($n*($f-$min)/$range);
215
        if ($d >= $n) $d = $n-1;
216
        $count[$d] += 1;
217
    }
218
    $data = [];
219
    for ($i=0; $i<$n; $i++) {
220
        $data[] = [$min+($i*$range)/$n, $count[$i]];
221
    }
222
    graph($data, 'hours', 'count');
223
    page_tail();
224
}
225
226
$batch = BoincBatch::lookup_id(get_int('batch_id'));
227
if (!$batch) error_page('no batch');
228
switch(get_str('action')) {
229
case 'err_host':
230
    err_host($batch);
231
    break;
232
case 'err_code':
233
    err_code($batch);
234
    break;
235
case 'host_list':
236
    host_list($batch->id, get_int('host_id'));
237
    break;
238
case 'code_list':
239
    code_list($batch->id, get_int('code'));
240
    break;
241
case 'flops_graph':
242
    flops_graph($batch);
243
    break;
244
default:
0 ignored issues
show
Coding Style introduced by
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
Coding Style introduced by
DEFAULT case must have a breaking statement
Loading history...
245
    error_page('bad action');
246
}
247
248
?>
249