Issues (1963)

html/user/submit_stats.php (6 issues)

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', 'OS', '# errors');
53
    $n = 0;
54
    foreach ($x as $id=>$count) {
0 ignored issues
show
Expected 1 space before "=>"; 0 found
Loading history...
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
            $host->os_name,
59
            sprintf(
60
                '<a href=submit_stats.php?action=host_list_errors&host_id=%d&batch_id=%d>%d</a>',
61
                $id, $batch->id, $count
62
            )
63
        );
64
        if (++$n == 20) break;
65
    }
66
    text_end();
67
    end_table();
68
    page_tail();
69
}
70
71
function err_code($batch) {
72
    $results = BoincResult::enum_fields(
73
        'exit_status',
74
        sprintf('batch=%d and outcome=%d',
75
            $batch->id,
76
            RESULT_OUTCOME_CLIENT_ERROR
77
        )
78
    );
79
    $x = [];
80
    foreach ($results as $r) {
81
        $id = $r->exit_status;
82
        if (array_key_exists($id, $x)) {
83
            $x[$id] += 1;
84
        } else {
85
            $x[$id] = 1;
86
        }
87
    }
88
    if (!$x) error_page('That batch had no error results');
89
    page_head('Errors by exit code');
90
    text_start();
91
    arsort($x);
92
    start_table();
93
    table_header('Code', '# errors');
94
    $n = 0;
95
    foreach ($x as $id=>$count) {
0 ignored issues
show
Expected 1 space before "=>"; 0 found
Loading history...
Expected 1 space after "=>"; 0 found
Loading history...
96
        table_row(
97
            exit_status_string($id),
98
            sprintf(
99
                '<a href=submit_stats.php?action=code_list&code=%d&batch_id=%d>%d</a>',
100
                $id, $batch->id, $count
101
            )
102
        );
103
        if (++$n == 20) break;
104
    }
105
    text_end();
106
    end_table();
107
    page_tail();
108
}
109
110
// list of error results from a host
111
//
112
function host_list_errors($batch_id, $host_id) {
113
    page_head("Errors for batch $batch_id, host $host_id");
114
    $results = BoincResult::enum(
115
        sprintf('batch=%d and hostid=%d and outcome=%d',
116
            $batch_id, $host_id, RESULT_OUTCOME_CLIENT_ERROR
117
        )
118
    );
119
120
    start_table();
121
    table_header('Job instance', 'Exit status');
122
    foreach ($results as $r) {
123
        table_row(
124
            "<a href=result.php?resultid=$r->id>$r->name</a>",
125
            exit_status_string($r->exit_status)
126
        );
127
    }
128
    end_table();
129
    page_tail();
130
}
131
132
// list of error results with given code
133
//
134
function code_list($batch_id, $code) {
135
    page_head("Errors for batch $batch_id, exit code $code");
136
    $results = BoincResult::enum(
137
        sprintf('batch=%d and exit_status=%d and outcome=%d',
138
            $batch_id, $code, RESULT_OUTCOME_CLIENT_ERROR
139
        )
140
    );
141
142
    text_start();
143
    start_table();
144
    table_header('Job instance', 'Host');
145
    foreach ($results as $r) {
146
        $host = BoincHost::lookup_id($r->hostid);
147
        table_row(
148
            "<a href=result.php?resultid=$r->id>$r->name</a>",
149
            sprintf('<a href=show_host_detail.php?hostid=%d>%d (%s)</a>',
150
                $host->id,
151
                $host->id,
152
                $host->os_name
153
            )
154
        );
155
    }
156
    end_table();
157
    text_end();
158
    page_tail();
159
}
160
161
function graph($data, $xlabel, $ylabel) {
162
    echo "
163
    <script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>
164
    <script type=\"text/javascript\">
165
      google.charts.load('current', {'packages':['corechart']});
166
      google.charts.setOnLoadCallback(drawChart);
167
168
      function drawChart() {
169
        var data = google.visualization.arrayToDataTable([
170
";
171
    echo "['$xlabel','$ylabel'],\n";
172
    foreach ($data as [$x, $y]) {
173
        echo "[$x, $y],\n";
174
    }
175
    echo "
176
        ]);
177
178
        var options = {
179
          title: 'Job runtime (hours)',
180
          legend:  'none'
181
        };
182
183
        var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));
184
185
        chart.draw(data, options);
186
      }
187
    </script>
188
    ";
189
    echo "
190
    <div id=\"curve_chart\" style=\"width: 900px; height: 500px\"></div>
191
    ";
192
}
193
194
function flops_graph($batch) {
195
    page_head("Batch $batch->id job runtimes");
196
    echo "
197
    <p>
198
    Runtimes of completed jobs, normalized to an average (4.3 GFLOPS) computer.
199
    <p>
200
    ";
201
    $results = BoincResult::enum_fields(
202
        'flops_estimate*elapsed_time as flops',
203
        sprintf('batch=%d and outcome=%d',
204
            $batch->id, RESULT_OUTCOME_SUCCESS
205
        )
206
    );
207
    $x = [];
208
    $min = 1e99;
209
    $max = 0;
210
    foreach ($results as $r) {
211
        $f = $r->flops / (4.3e9 *3600);
212
        if ($f > $max) $max = $f;
213
        if ($f < $min) $min = $f;
214
        $x[] = $f;
215
    }
216
    $n = 800;
217
    $count = [];
218
    for ($i=0; $i<$n; $i++) {
219
        $count[$i] = 0;
220
    }
221
    $range = $max - $min;
222
    foreach ($x as $f) {
223
        $d = intval($n*($f-$min)/$range);
224
        if ($d >= $n) $d = $n-1;
225
        $count[$d] += 1;
226
    }
227
    $data = [];
228
    for ($i=0; $i<$n; $i++) {
229
        $data[] = [$min+($i*$range)/$n, $count[$i]];
230
    }
231
    graph($data, 'hours', 'count');
232
    page_tail();
233
}
234
235
// show hosts that did jobs for this batch
236
function show_hosts($batch) {
237
    $results = BoincResult::enum_fields(
238
        'hostid',
239
        sprintf('batch=%d and outcome=%d',
240
            $batch->id,
241
            RESULT_OUTCOME_SUCCESS
242
        )
243
    );
244
    $x = [];
245
    foreach ($results as $r) {
246
        $id = $r->hostid;
247
        if (array_key_exists($id, $x)) {
248
            $x[$id] += 1;
249
        } else {
250
            $x[$id] = 1;
251
        }
252
    }
253
    arsort($x);
254
    page_head("Batch $batch->id: completed jobs grouped by host");
255
    text_start();
256
    start_table();
257
    table_header('Host', 'OS', '# jobs');
258
    foreach ($x as $id => $count) {
259
        $host = BoincHost::lookup_id($id);
260
        table_row(
261
            "<a href=show_host_detail.php?hostid=$id>$id</a>",
262
            $host->os_name,
263
            $count
264
        );
265
    }
266
    end_table();
267
    text_end();
268
    page_tail();
269
}
270
271
$batch = BoincBatch::lookup_id(get_int('batch_id'));
272
if (!$batch) error_page('no batch');
273
switch(get_str('action')) {
274
case 'err_host':
275
    err_host($batch);
276
    break;
277
case 'err_code':
278
    err_code($batch);
279
    break;
280
case 'host_list_errors':
281
    host_list_errors($batch->id, get_int('host_id'));
282
    break;
283
case 'code_list':
284
    code_list($batch->id, get_int('code'));
285
    break;
286
case 'flops_graph':
287
    flops_graph($batch);
288
    break;
289
case 'show_hosts':
290
    show_hosts($batch);
291
    break;
292
default:
0 ignored issues
show
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
DEFAULT case must have a breaking statement
Loading history...
293
    error_page('bad action');
294
}
295
296
?>
297