show_host()   F
last analyzed

Complexity

Conditions 24
Paths > 20000

Size

Total Lines 134
Code Lines 110

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 24
eloc 110
c 1
b 0
f 0
nc 67200
nop 3
dl 0
loc 134
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// This file is part of BOINC.
3
// http://boinc.berkeley.edu
4
// Copyright (C) 2008 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
require_once("../inc/credit.inc");
20
require_once("../inc/stats_sites.inc");
21
require_once("../inc/boinc_db.inc");
22
require_once("../inc/user.inc");
23
24
function link_to_results($host) {
25
    if (!$host) return tra("No host");
26
    $config = get_config();
27
    if (!parse_bool($config, "show_results")) return tra("Unavailable");
28
    $nresults = host_nresults($host);
29
    if (!$nresults) return "0";
30
    return "<a href=results.php?hostid=$host->id>$nresults</a>";
31
}
32
33
function sched_log_name($x) {
34
    if ($x == 0) return "NO_SUCH_LOG";
35
    return gmdate('Y-m-d_H/Y-m-d_H:i', $x) . ".txt";
36
}
37
38
function sched_log_link($x) {
39
    if (file_exists("sched_logs")) {
40
        return "<a href=\"../sched_logs/" . sched_log_name($x) . "\">" . time_str($x) . "</a>";
41
    } else {
42
        return time_str($x);
43
    }
44
}
45
46
function location_form($host) {
47
    $none = "selected";
48
    $h=$w=$s=$m="";
49
    if ($host->venue == "home") $h = "selected";
50
    if ($host->venue == "work") $w = "selected";
51
    if ($host->venue == "school") $s = "selected";
52
    $x = "<form action=host_venue_action.php>
53
        <input type=hidden name=hostid value=$host->id>
54
        <select class=\"form-control\" name=venue>
55
        <option value=\"\" $none>---
56
        <option value=home $h>".tra("Home")."
57
        <option value=work $w>".tra("Work")."
58
        <option value=school $s>".tra("School")."
59
        </select>
60
        <p></p>
61
        <input class=\"btn btn-primary btn-sm\" type=submit value=\"".tra("Update location")."\">
62
        </form>
63
    ";
64
    return $x;
65
}
66
67
function cross_project_links($host) {
68
    global $host_sites;
69
    $x = "";
70
    foreach ($host_sites as $h) {
71
        $url = $h[0];
72
        $name = $h[1];
73
        $img = $h[2];
74
        $x .= "<a href=$url".$host->host_cpid."><img class=\"icon\" border=2 src=img/$img alt=\"$name\"></a> ";
75
    }
76
    return $x;
77
}
78
79
// Show full-page description of $host.
80
// If $user is non-null, it's both the owner of the host
81
// and the logged in user (so show some extra fields)
82
//
83
function show_host($host, $user, $ipprivate) {
84
    $config = get_config();
85
    start_table();
86
    row1(tra("Computer information"));
87
    $anonymous = false;
88
    if ($user) {
89
        if ($ipprivate) {
90
            row2(tra("IP address"), "$host->last_ip_addr<br>".tra("(same the last %1 times)", $host->nsame_ip_addr));
91
            if ($host->last_ip_addr != $host->external_ip_addr) {
92
                row2(tra("External IP address"), $host->external_ip_addr);
93
            }
94
        } else {
95
            row2(tra("IP address"), "<a href=show_host_detail.php?hostid=$host->id&ipprivate=1>".tra("Show IP address")."</a>");
96
        }
97
        row2(tra("Domain name"), $host->domain_name);
98
        if ($host->product_name) {
99
            row2(tra("Product name"), $host->product_name);
100
        }
101
        $x = $host->timezone/3600;
102
        if ($x >= 0) $x="+$x";
103
        row2(tra("Local Standard Time"), tra("UTC %1 hours", $x));
104
    } else {
105
        $owner = BoincUser::lookup_id($host->userid);
106
        if ($owner && $owner->show_hosts) {
107
            row2(tra("Owner"), user_links($owner, BADGE_HEIGHT_MEDIUM));
108
        } else {
109
            row2(tra("Owner"), tra("Anonymous"));
110
            $anonymous = true;
111
        }
112
    }
113
    row2(tra("Created"), time_str($host->create_time));
114
    if (!NO_STATS) {
115
        row2(tra("Total credit"), format_credit_large($host->total_credit));
116
        row2(tra("Average credit"), format_credit($host->expavg_credit));
117
        if (!$anonymous) {
118
            row2(tra("Cross project credit"), cross_project_links($host));
119
        }
120
    }
121
    row2(tra("CPU type"), "$host->p_vendor <br> $host->p_model");
122
    row2(tra("Number of cores"), $host->p_ncpus);
123
    $parsed_ser = parse_serialnum($host->serialnum);
124
    row2(tra("Coprocessors"), gpu_desc($parsed_ser));
125
    row2(tra("Virtualization"), vbox_desc($parsed_ser));
126
    row2(tra("Docker"), docker_desc($parsed_ser));
127
    row2(tra("Operating System"), "$host->os_name <br> $host->os_version");
128
    $v = boinc_version($parsed_ser);
129
    row2(tra("BOINC version"), $v);
130
    $x = $host->m_nbytes/GIGA;
131
    $y = round($x, 2);
132
    row2(tra("Memory"), tra("%1 GB", $y));
133
    if ($host->m_cache > 0) {
134
        $x = $host->m_cache/KILO;
135
        $y = round($x, 2);
136
        row2(tra("Cache"), tra("%1 KB", $y));
137
    }
138
139
    if ($user) {
140
        $x = $host->m_swap/GIGA;
141
        $y = round($x, 2);
142
        row2(tra("Swap space"), tra("%1 GB", $y));
143
        $x = $host->d_total/GIGA;
144
        $y = round($x, 2);
145
        row2(tra("Total disk space"), tra("%1 GB", $y));
146
        $x = $host->d_free/GIGA;
147
        $y = round($x, 2);
148
        row2(tra("Free Disk Space"), tra("%1 GB", $y));
149
    }
150
    $x = $host->p_fpops/1e9;
151
    $y = round($x, 2);
152
    row2(tra("Measured floating point speed"), tra("%1 billion ops/sec", $y));
153
    $x = $host->p_iops/1e9;
154
    $y = round($x, 2);
155
    row2(tra("Measured integer speed"), tra("%1 billion ops/sec", $y));
156
    $x = $host->n_bwup/MEGA;
157
    $y = round($x, 2);
158
    if ($y > 0) {
159
        row2(tra("Average upload rate"), tra("%1 MB/sec", $y));
160
    } else {
161
        row2(tra("Average upload rate"), tra("Unknown"));
162
    }
163
    $x = $host->n_bwdown/MEGA;
164
    $y = round($x, 2);
165
    if ($y > 0) {
166
        row2(tra("Average download rate"), tra("%1 MB/sec", $y));
167
    } else {
168
        row2(tra("Average download rate"), tra("Unknown"));
169
    }
170
    $x = $host->avg_turnaround/86400;
171
    if (!NO_COMPUTING) {
172
        row2(tra("Average turnaround time"), tra("%1 days", round($x, 2)));
173
        row2(tra("Application details"),
174
            "<a href=host_app_versions.php?hostid=$host->id>".tra("Show")."</a>"
175
        );
176
        $show_results = parse_bool($config, "show_results");
177
        if ($show_results) {
178
            $nresults = host_nresults($host);
179
            if ($nresults) {
180
                $results = "<a href=results.php?hostid=$host->id>$nresults</a>";
181
            } else {
182
                $results = "0";
183
            }
184
            row2(tra("Tasks"), $results);
185
        }
186
    }
187
188
    if ($user) {
189
        row2(tra("Number of times client has contacted server"), $host->rpc_seqno);
190
        row2(tra("Last time contacted server"), sched_log_link($host->rpc_time));
191
        row2(tra("Fraction of time BOINC is running"), number_format(100*$host->on_frac, 2)."%");
192
        if ($host->connected_frac > 0) {
193
            row2(tra("While BOINC is running, fraction of time computer has an Internet connection"), number_format(100*$host->connected_frac, 2)."%");
194
        }
195
        row2(tra("While BOINC is running, fraction of time computing is allowed"), number_format(100*$host->active_frac, 2)."%");
196
        row2(tra("While is BOINC running, fraction of time GPU computing is allowed"), number_format(100*$host->gpu_active_frac, 2)."%");
197
        if ($host->cpu_efficiency) {
198
            row2(tra("Average CPU efficiency"), $host->cpu_efficiency);
199
        }
200
        if (!NO_COMPUTING) {
201
            if ($host->duration_correction_factor) {
202
                row2(tra("Task duration correction factor"), $host->duration_correction_factor);
203
            }
204
        }
205
        row2(tra("Location"), location_form($host));
206
        if ($show_results && $nresults == 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $show_results does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $nresults does not seem to be defined for all execution paths leading up to this point.
Loading history...
207
            $x = " &middot; <a href=host_delete.php?hostid=$host->id".url_tokens($user->authenticator).">".tra("Delete this computer")."</a> ";
208
        } else {
209
            $x = "";
210
        }
211
        row2(tra("Merge duplicate records of this computer"), "<a class=\"btn btn-primary btn-sm\" href=host_edit_form.php?hostid=$host->id>".tra("Merge")."</a> $x");
212
    } else {
213
        row2(tra("Number of times client has contacted server"), $host->rpc_seqno);
214
        row2(tra("Last contact"), date_str($host->rpc_time));
215
    }
216
    echo "</table>\n";
217
218
}
219
220
// the following is used for list of top hosts
221
//
222
function top_host_table_start($sort_by) {
223
    global $host_sites;
224
    shuffle($host_sites);
225
    start_table('table-striped');
226
    $x = array(
227
        tra("Info"),
228
        tra("Rank"),
229
        tra("Owner"),
230
    );
231
    if (!NO_STATS) {
232
        if ($sort_by == 'total_credit') {
233
            $x[] = "<a href=top_hosts.php?sort_by=expavg_credit>".tra("Avg. credit")."</a>";
234
            $x[] = tra("Total credit");
235
        } else {
236
            $x[] = tra("Recent average credit");
237
            $x[] = "<a href=top_hosts.php?sort_by=total_credit>".tra("Total credit")."</a>";
238
        }
239
    }
240
    $x[] = tra("BOINC version");
241
    $x[] = tra("CPU");
242
    $x[] = tra("GPU");
243
    $x[] = tra("Operating system");
244
    $s = 'style="text-align:right;"';
245
    $a = array("", "", "", $s, $s, "", "", "", "");
246
    row_heading_array($x, $a, "bg-default");
247
}
248
249
function host_nresults($host) {
250
    return BoincResult::count("hostid=$host->id");
251
}
252
253
// host.serialnum is a sequence of terms like
254
// [BOINC|8.1.0]
255
//   or [BOINC|8.1.0|Charity Engine]
256
// [CUDA|NVIDIA GeForce GTX 1650 with Max-Q Design|1|4095MB|53892|300]
257
// (or CAL or INTEL or apple_gpu or opencl_gpu)
258
// [vbox|7.0.14|0|1]
259
// [docker|4.9.3|2]
260
// [dont_use_docker]
261
// [dont_use_wsl]
262
263
// parse it into a list of lists
264
//
265
function parse_serialnum($serialnum) {
266
    $parts = explode('[', $serialnum);
267
    $ret = [];
268
    foreach ($parts as $part) {
269
        if (!$part) continue;
270
        $part = substr($part, 0, -1);
271
        $f = explode('|', $part);
272
        if (!$f) continue;
0 ignored issues
show
Bug Best Practice introduced by
The expression $f of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
273
        $ret[$f[0]] = $f;
274
    }
275
    return $ret;
276
}
277
278
function is_gpu_type($x) {
279
    if ($x == 'CUDA') return true;
280
    if ($x == 'CAL') return true;
281
    if ($x == 'INTEL') return true;
282
    if ($x == 'apple_gpu') return true;
283
    if ($x == 'opencl_gpu') return true;
284
    return false;
285
}
286
287
// return descriptive string for Vbox info.
288
// Prior to BOINC commit 6121ce1, the DB entry looked like e.g. "[vbox|5.0.0]"
289
// where 5.0.0 gave the Virtualbox version number.
290
// After 6121ce1, the entry was "[vbox|5.0.0|1|1]",
291
// where two additional flags give information about
292
// hardware virtualization support.
293
// Older clients may have the old-style serialnum in the DB
294
// despite the server being upgraded.
295
//
296
function vbox_desc($parsed_ser){
297
    if (empty($parsed_ser['vbox'])) return '---';
298
    $f = $parsed_ser['vbox'];
299
    $desc = sprintf('Virtualbox (%s) %s',
300
        $f[1], tra("installed")
301
    );
302
    if (sizeof($f)<=2){
303
        return $desc;
304
    }
305
    if ($f[2]=="1" and $f[3]=="1") {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
306
        return $desc.tra(", CPU has hardware virtualization support and it is enabled");
307
    } elseif ($f[2]=="1" and $f[3]=="0") {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
308
        return $desc.tra(", CPU has hardware virtualization support but it is disabled");
309
    } elseif ($f[2]=="0") {
310
        return $desc.tra(", CPU does not have hardware virtualization support");
311
    }
312
    return $desc;
313
}
314
315
function docker_desc($parsed_ser) {
316
    if (empty($parsed_ser['docker'])) return '---';
317
    $f = $parsed_ser['docker'];
318
    if ($f[2] == '1') {
319
        $x = "Docker version $f[1]";
320
    } else {
321
        $x = "Podman version $f[1]";
322
    }
323
    if (!empty($parsed_ser['dont_use_docker'])) {
324
        $x .= " (don't used Docker)";
325
    }
326
    if (!empty($parsed_ser['dont_use_wsl'])) {
327
        $x .= " (don't used WSL)";
328
    }
329
    return $x;
330
}
331
332
// return a human-readable version of the GPU info
333
//
334
function gpu_desc($parsed_ser, $detail=true) {
335
    $str = "";
336
    foreach ($parsed_ser as $d) {
337
        if (!is_gpu_type($d[0])) continue;
338
        if (count($d) < 4) continue;
339
        if ($str) $str .= "<p>";
340
        if ($d[2]!="" && $d[2]!="1") $str .= "[".$d[2]."] ";
341
        if ($d[0] == "CUDA") {
342
            $str .= "NVIDIA";
343
        } else if ($d[0] == "CAL") {
344
            $str .= "AMD";
345
        } else if ($d[0] == "opencl_gpu") {
346
            $str .= "OpenCL GPU";
347
        } else {
348
            $str .= $d[0];
349
        }
350
        $str .= " ".$d[1];
351
        if ($detail) {
352
            $str .= " (".$d[3].")";
353
            if (array_key_exists(4, $d)) {
354
                if ($d[4] != "" && $d[4] != 0) {
355
                    // if version has no '.', assume it's in 100*maj+min form
356
                    //
357
                    if (strchr($d[4], '.')) {
358
                        $str .= " driver: ".$d[4];
359
                    } else {
360
                        $i = (int)$d[4];
361
                        $maj = (int)($i/100);
362
                        $min = $i%100;
363
                        $str .= sprintf(" driver: %d.%02d", $maj, $min);
364
                    }
365
                }
366
            }
367
            if (array_key_exists(5, $d)) {
368
                if ($d[5] != "" && $d[5] != 0) {
369
                    if (strchr($d[5], '.')) {
370
                        $str .= " OpenCL: ".$d[5];
371
                    } else {
372
                        $i = (int)$d[5];
373
                        $maj = (int)($i/100);
374
                        $min = $i%100;
375
                        $str .= sprintf(" OpenCL: %d.%d", $maj, $min);
376
                    }
377
                }
378
            }
379
        }
380
    }
381
    if (!$str) $str = "---";
382
    return $str;
383
}
384
385
// Given the same string as above, return the BOINC version
386
//
387
function boinc_version($parsed_ser) {
388
    if (empty($parsed_ser['BOINC'])) return '---';
389
    $a = $parsed_ser['BOINC'];
390
    $v = $a[1];
391
    if (array_key_exists(2, $a)) {
392
        $brand = $a[2];
393
        $v .= " ($brand)";
394
    }
395
    return $v;
396
}
397
398
function cpu_desc($host) {
399
    return "$host->p_vendor<br>$host->p_model<br>".tra("(%1 cores)", $host->p_ncpus)."\n";
400
}
401
402
// If private is true, we're showing the host to its owner,
403
// so it's OK to show the domain name etc.
404
// If private is false, show the owner's name only if they've given permission
405
//
406
function show_host_row($host, $i, $private, $show_owner, $any_product_name) {
407
    $anonymous = false;
408
    if (!$private) {
409
        if ($show_owner) {
410
            $user = BoincUser::lookup_id($host->userid);
411
            if ($user && $user->show_hosts) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
412
            } else {
413
                $anonymous = true;
414
            }
415
        }
416
    }
417
    echo "<tr><td>ID: $host->id
418
        <br><a href=show_host_detail.php?hostid=$host->id>".tra("Details")."</a>
419
    ";
420
    if (!NO_COMPUTING) {
421
        echo "
422
        | <a href=results.php?hostid=$host->id>".tra("Tasks")."</a>
423
        ";
424
    }
425
    if (!NO_STATS) {
426
        if (!$anonymous) {
427
            echo "
428
                <br><nobr><small>".tra("Cross-project stats:")."</small></nobr><br>".cross_project_links($host);
429
        }
430
    }
431
    echo "
432
        </td>
433
    ";
434
    if ($private) {
435
        echo "<td>$host->domain_name</td>\n";
436
        if ($any_product_name) {
437
            echo "<td>$host->product_name</td>\n";
438
        }
439
        echo "<td>$host->venue</td>\n";
440
    } else {
441
        echo "<td>$i</td>\n";
442
        if ($show_owner) {
443
            if ($anonymous) {
444
                echo "<td>".tra("Anonymous")."</td>\n";
445
            } else {
446
                echo "<td>", user_links($user, BADGE_HEIGHT_MEDIUM), "</td>\n";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $user does not seem to be defined for all execution paths leading up to this point.
Loading history...
447
            }
448
        }
449
    }
450
    $parsed_ser = parse_serialnum($host->serialnum);
451
    if ($show_owner) {
452
        // This is used in the "top computers" display
453
        //
454
        if (!NO_STATS) {
455
            printf("
456
                <td align=right>%s</td>
457
                <td align=right>%s</td>",
458
                format_credit($host->expavg_credit),
459
                format_credit_large($host->total_credit)
460
            );
461
        }
462
        printf("
463
            <td>%s</td>
464
            <td>%s</td>
465
            <td>%s</td>
466
            <td>%s <br> %s</td>",
467
            boinc_version($parsed_ser),
468
            cpu_desc($host),
469
            gpu_desc($parsed_ser),
470
            $host->os_name, $host->os_version
471
        );
472
    } else {
473
        // This is used to show the computers of a given user
474
        //
475
        if (!NO_STATS) {
476
            printf("
477
                <td align=right>%s</td>
478
                <td align=right>%s</td>",
479
                format_credit($host->expavg_credit),
480
                format_credit_large($host->total_credit)
481
            );
482
        }
483
        printf("
484
            <td>%s</td>
485
            <td>%s</td>
486
            <td>%s</td>
487
            <td>%s<br><small>%s</small></td>
488
            <td>%s</td>
489
            ",
490
            boinc_version($parsed_ser),
491
            cpu_desc($host),
492
            gpu_desc($parsed_ser),
493
            $host->os_name, $host->os_version,
494
            sched_log_link($host->rpc_time)
495
        );
496
    }
497
498
    echo "</tr>\n";
499
}
500
501
// Logic for deciding whether two host records might actually
502
// be the same machine, based on CPU info
503
//
504
// p_vendor is typically either AuthenticAMD or GenuineIntel.
505
// Over time we've changed the contents of p_model.
506
// Some examples:
507
// Intel(R) Core(TM)2 Duo CPU  E7300  @ 2.66GHz [Family 6 Model 23 Stepping 6]
508
// AMD Athlon(tm) II X2 250 Processor [Family 16 Model 6 Stepping 3]
509
// Intel(R) Xeon(R) CPU X5650 @ 2.67GHz [x86 Family 6 Model 44 Stepping 2]
510
// Intel(R) Core(TM) i5-2500K CPU @ 3.30GHz [Intel64 Family 6 Model 42 Stepping 7]
511
//
512
// in the last 2 cases, let's call x86 and Intel64 the "architecture"
513
//
514
// so, here's the policy:
515
//
516
// if p_ncpus different, return false
517
// if p_vendor different, return false
518
// if both have family/model/stepping info
519
//    if info disagrees, return false
520
//    if both have GHz info, and they disagree, return false
521
//    if both have architecture, and they disagree, return false
522
//    return true
523
// if p_model different, return false
524
// return true
525
//
526
527
// parse p_model to produce the following structure:
528
// x->speed     "3.00GHz" etc. or null
529
// x->arch      "x86" etc. or null
530
// x->info      "Family 6 Model 23 Stepping 6" etc. or null
531
//
532
function parse_model($model) {
533
    $y = explode(" ", $model);
534
    $x = new StdClass;
535
    $x->speed = null;
536
    $x->arch = null;
537
    $x->info = null;
538
    foreach ($y as $z) {
539
        if (strstr($z, "GHz")) $x->speed = $z;
540
        if (strstr($z, "MHz")) $x->speed = $z;
541
    }
542
    $pos1 = strpos($model, '[');
543
    if ($pos1 === false) return $x;
544
    $pos2 = strpos($model, ']');
545
    if ($pos2 === false) return $x;
546
    $a = substr($model, $pos1+1, $pos2-$pos1-1);
547
    $y = explode(" ", $a);
548
    if (count($y) == 0) return $x;
549
    if ($y[0] == "Family") {
550
        $x->info = $a;
551
    } else {
552
        $x->arch = $y[0];
553
        $x->info = substr($a, strlen($y[0])+1);
554
    }
555
    return $x;
556
}
557
558
function cpus_compatible($host1, $host2) {
559
    if ($host1->p_ncpus != $host2->p_ncpus) return false;
560
    if ($host1->p_vendor != $host2->p_vendor) return false;
561
    $x1 = parse_model($host1->p_model);
562
    $x2 = parse_model($host2->p_model);
563
    if ($x1->info && $x2->info) {
564
        if ($x1->info != $x2->info) return false;
565
        if ($x1->speed && $x2->speed) {
566
            if ($x1->speed != $x2->speed) return false;
567
        }
568
        if ($x1->arch && $x2->arch) {
569
            if ($x1->arch != $x2->arch) return false;
570
        }
571
        return true;
572
    }
573
    if ($host1->p_model != $host2->p_model) return false;
574
    return true;
575
}
576
577
// does one host strictly precede the other?
578
//
579
function times_disjoint($host1, $host2) {
580
    if ($host1->rpc_time < $host2->create_time) return true;
581
    if ($host2->rpc_time < $host1->create_time) return true;
582
    return false;
583
}
584
585
function os_compatible($host1, $host2) {
586
    if (strstr($host1->os_name, "Windows") && strstr($host2->os_name, "Windows")) return true;
587
    if (strstr($host1->os_name, "Linux") && strstr($host2->os_name, "Linux")) return true;
588
    if (strstr($host1->os_name, "Darwin") && strstr($host2->os_name, "Darwin")) return true;
589
    if (strstr($host1->os_name, "SunOS") && strstr($host2->os_name, "SunOS")) return true;
590
    if ($host1->os_name == $host2->os_name) return true;
591
    return false;
592
}
593
594
// Return true if it's possible that the two host records
595
// correspond to the same host
596
// NOTE: the cheat-proofing comes from checking
597
// that their time intervals are disjoint.
598
// So the CPU/OS checks don't have to be very strict.
599
//
600
function hosts_compatible($host1, $host2, $show_detail) {
601
    // A host is "new" if it has no credit and no results.
602
    // Skip disjoint-time check if one host or other is new
603
    //
604
    $new1 = !$host1->total_credit && !host_nresults($host1);
605
    $new2 = !$host2->total_credit && !host_nresults($host2);
606
    if (!$new1 && !$new2) {
607
        if (!times_disjoint($host1, $host2)) {
608
            if ($show_detail) {
609
                $c1 = date_str($host1->create_time);
610
                $r1 = date_str($host1->rpc_time);
611
                $c2 = date_str($host2->create_time);
612
                $r2 = date_str($host2->rpc_time);
613
                echo "<br>".tra("Host %1 has overlapping lifetime:", $host2->id)." ($c1 - $r1), ($c2 - $r2)";
614
            }
615
            return false;
616
        }
617
    }
618
    if (!os_compatible($host1, $host2)) {
619
        if ($show_detail) {
620
            echo "<br>".tra("Host %1 has an incompatible OS:", $host2->id)." ($host1->os_name, $host2->os_name)\n";
621
        }
622
        return false;
623
    }
624
    if (!cpus_compatible($host1, $host2)) {
625
        if ($show_detail) {
626
            echo "<br>".tra("Host %1 has an incompatible CPU:", $host2->id)." ($host1->p_vendor $host1->p_model, $host2->p_vendor $host2->p_model)\n";
627
        }
628
        return false;
629
    }
630
    return true;
631
}
632
633
// recompute host's average credit by scanning results.
634
// Could be expensive if lots of results!
635
//
636
function host_update_credit($hostid) {
637
    $total = 0;
638
    $avg = 0;
639
    $avg_time = 0;
640
641
    $results = BoincResult::enum("hostid=$hostid order by received_time");
642
    foreach($results as $result) {
643
        if ($result->granted_credit <= 0) continue;
644
        $total += $result->granted_credit;
645
646
        update_average(
647
            $result->received_time,
648
            $result->sent_time,
649
            $result->granted_credit,
650
            $avg,
651
            $avg_time
652
        );
653
654
        //echo "<br>$avg\n";
655
    }
656
657
    // do a final decay
658
    //
659
    $now = time();
660
    update_average(now, 0, 0, $avg, $avg_time);
661
662
    $host = new BoincHost();
663
    $host->id = hostid;
664
    $host->update("total_credit=$total, expavg_credit=$avg, expavg_time=$now");
665
}
666
667
// decay a host's average credit
668
//
669
function host_decay_credit($host) {
670
    $avg = $host->expavg_credit;
671
    $avg_time = $host->expavg_time;
672
    $now = time();
673
    update_average($now, 0, 0, $avg, $avg_time);
674
    $host->update("expavg_credit=$avg, expavg_time=$now");
675
}
676
677
// if the host hasn't received new credit for ndays,
678
// decay its average and return true
679
//
680
function host_inactive_ndays($host, $ndays) {
681
    $diff = time() - $host->expavg_time;
682
    if ($diff > $ndays*86400) {
683
        host_decay_credit($host);
684
        return true;
685
    }
686
    return false;
687
}
688
689
// invariant: old_host.create_time < new_host.create_time
690
//
691
function merge_hosts($old_host, $new_host) {
692
    if ($old_host->id == $new_host->id) {
693
        return tra("same host");
694
    }
695
    if (!hosts_compatible($old_host, $new_host, false)) {
696
        return tra("Can't merge host %1 into %2 - they're incompatible", $old_host->id, $new_host->id);
697
    }
698
699
    echo "<br>".tra("Merging host %1 into host %2", $old_host->id, $new_host->id)."\n";
700
701
    // decay the average credit of both hosts
702
    //
703
    $now = time();
704
    update_average($now, 0, 0, $old_host->expavg_credit, $old_host->expavg_time);
705
    update_average($now, 0, 0, $new_host->expavg_credit, $new_host->expavg_time);
706
707
    // update the database:
708
    // - add credit from old to new host
709
    // - change results to refer to new host
710
    // - put old host in "zombie" state (userid=0, rpc_seqno=new host ID)
711
    //
712
    $total_credit = $old_host->total_credit + $new_host->total_credit;
713
    $recent_credit = $old_host->expavg_credit + $new_host->expavg_credit;
714
    $result = $new_host->update("total_credit=$total_credit, expavg_credit=$recent_credit, expavg_time=$now");
715
    if (!$result) {
716
        return tra("Couldn't update credit of new computer");
717
    }
718
    $result = BoincResult::update_aux("hostid=$new_host->id where hostid=$old_host->id");
719
    if (!$result) {
720
        return tra("Couldn't update results");
721
    }
722
723
    $result = $old_host->update("total_credit=0, expavg_credit=0, userid=0, rpc_seqno=$new_host->id");
724
    if (!$result) {
725
        return tra("Couldn't retire old computer");
726
    }
727
    echo "<br>".tra("Retired old computer %1", $old_host->id)."\n";
728
    return 0;
729
}
730
731
//////////////// helper functions for hosts_user.php ////////////////
732
733
function link_url($sort, $rev, $show_all) {
734
    global $userid;
735
    $x = $userid ? "&userid=$userid":"";
736
    return "hosts_user.php?sort=$sort&rev=$rev&show_all=$show_all$x";
737
}
738
739
function link_url_rev($actual_sort, $sort, $rev, $show_all) {
740
    if ($actual_sort == $sort) {
741
        $rev = 1 - $rev;
742
    }
743
    return link_url($sort, $rev, $show_all);
744
}
745
746
function more_or_less($sort, $rev, $show_all) {
747
    echo "<p>";
748
    if ($show_all) {
749
        $url = link_url($sort, $rev, 0);
750
        echo tra("Show:")." ".tra("All computers")." &middot; <a href=$url>".tra("Only computers active in past 30 days")."</a>";
751
    } else {
752
        $url = link_url($sort, $rev, 1);
753
        echo tra("Show:")." <a href=$url>".tra("All computers")."</a> &middot; ".tra("Only computers active in past 30 days");
754
    }
755
    echo "<p>";
756
}
757
758
function user_host_table_start(
759
    $private, $sort, $rev, $show_all, $any_product_name
0 ignored issues
show
Coding Style introduced by
Multi-line function declarations must define one parameter per line
Loading history...
760
) {
761
    start_table('table-striped');
762
    $x = array();
763
    $a = array();
764
765
    $url = link_url_rev($sort, "id", $rev, $show_all);
766
    $x[] = "<a href=$url>".tra("Computer ID")."</a>";
767
    $a[] = '';
768
769
    if ($private) {
770
        $url = link_url_rev($sort, "name", $rev, $show_all);
771
        $x[] = "<a href=$url>".tra("Name")."</a>";
772
        $a[] = null;
773
        $url = link_url_rev($sort, "venue", $rev, $show_all);
774
        if ($any_product_name) {
775
            $x[] = tra("Model");
776
            $a[] = null;
777
        }
778
        $x[] = "<a href=$url>".tra("Location")."</a>";
779
        $a[] = null;
780
    } else {
781
        $x[] = tra("Rank");
782
        $a[] = null;
783
    }
784
    if (!NO_STATS) {
785
        $url = link_url_rev($sort, "expavg_credit", $rev, $show_all);
786
        $x[] = "<a href=$url>".tra("Avg. credit")."</a>";
787
        $a[] = ALIGN_RIGHT;
788
        $url = link_url_rev($sort, "total_credit", $rev, $show_all);
789
        $x[] = "<a href=$url>".tra("Total credit")."</a>";
790
        $a[] = ALIGN_RIGHT;
791
    }
792
    $x[] = tra("BOINC<br>version");
793
    $a[] = null;
794
    $url = link_url_rev($sort, "cpu", $rev, $show_all);
795
    $x[] = "<a href=$url>".tra("CPU")."</a>";
796
    $a[] = null;
797
    $x[] = tra("GPU");
798
    $a[] = null;
799
    $url = link_url_rev($sort, "os", $rev, $show_all);
800
    $x[] = "<a href=$url>".tra("Operating System")."</a>";
801
    $a[] = null;
802
    $url = link_url_rev($sort, "rpc_time", $rev, $show_all);
803
    $x[] = "<a href=$url>".tra("Last contact")."</a>";
804
    $a[] = null;
805
    row_heading_array($x, $a, "bg-default");
806
}
807
808
function show_user_hosts($userid, $private, $show_all, $sort, $rev) {
809
    $desc = false;  // whether the sort order's default is decreasing
810
    switch ($sort) {
811
    case "total_credit": $sort_clause = "total_credit"; $desc = true; break;
812
    case "expavg_credit": $sort_clause = "expavg_credit"; $desc = true; break;
813
    case "name": $sort_clause = "domain_name"; break;
814
    case "id": $sort_clause = "id"; break;
815
    case "cpu": $sort_clause = "p_vendor"; break;
816
    case "gpu": $sort_clause = "serialnum"; break;
817
    case "os": $sort_clause = "os_name"; break;
818
    case "venue": $sort_clause = "venue"; break;
819
    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...
820
        // default value -- sort by RPC time
821
        $sort = "rpc_time";
822
        $sort_clause = "rpc_time";
823
        $desc = true;
824
    }
825
826
    if ($rev != $desc) {
827
        $sort_clause .= " desc";
828
    }
829
    more_or_less($sort, $rev, $show_all);
830
831
    $now = time();
832
    $old_hosts=0;
833
    $i = 1;
834
    $hosts = BoincHost::enum("userid=$userid order by $sort_clause");
835
    $any_product_name = false;
836
    foreach ($hosts as $host) {
837
        if ($host->product_name) {
838
            $any_product_name = true;
839
            break;
840
        }
841
    }
842
    user_host_table_start($private, $sort, $rev, $show_all, $any_product_name);
843
    foreach ($hosts as $host) {
844
        $is_old=false;
845
        if (($now - $host->rpc_time) > 30*86400) {
846
            $is_old=true;
847
            $old_hosts++;
848
        }
849
        if (!$show_all && $is_old) continue;
850
        show_host_row($host, $i, $private, false, $any_product_name);
851
        $i++;
852
    }
853
    end_table();
854
855
    if ($old_hosts>0) {
856
        more_or_less($sort, $rev, $show_all);
857
    }
858
859
    if ($private) {
860
        echo "
861
            <a href=merge_by_name.php>".tra("Merge computers by name")."</a>
862
        ";
863
    }
864
}
865
866
// remove user-specific info from a user's hosts
867
//
868
function anonymize_hosts($user) {
869
    $hosts = BoincHost::enum("userid=$user->id");
870
    foreach ($hosts as $h) {
871
        $h->update("domain_name='deleted', last_ip_addr=''");
872
    }
873
}
874
875
876
?>
877