Issues (1839)

html/inc/host.inc (2 issues)

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
    global $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 processors"), $host->p_ncpus);
123
    if ($host->serialnum) {
124
        row2(tra("Coprocessors"), gpu_desc($host->serialnum));
125
    }
126
    row2(tra("Virtualization"), vbox_desc($host->serialnum));
127
    row2(tra("Operating System"), "$host->os_name <br> $host->os_version");
128
    $v = boinc_version($host->serialnum);
129
    if ($v) {
130
        row2(tra("BOINC version"), $v);
131
    }
132
    $x = $host->m_nbytes/GIGA;
133
    $y = round($x, 2);
134
    row2(tra("Memory"), tra("%1 GB", $y));
135
    if ($host->m_cache > 0) {
136
        $x = $host->m_cache/KILO;
137
        $y = round($x, 2);
138
        row2(tra("Cache"), tra("%1 KB", $y));
139
    }
140
141
    if ($user) {
142
        $x = $host->m_swap/GIGA;
143
        $y = round($x, 2);
144
        row2(tra("Swap space"), tra("%1 GB", $y));
145
        $x = $host->d_total/GIGA;
146
        $y = round($x, 2);
147
        row2(tra("Total disk space"), tra("%1 GB", $y));
148
        $x = $host->d_free/GIGA;
149
        $y = round($x, 2);
150
        row2(tra("Free Disk Space"), tra("%1 GB", $y));
151
    }
152
    $x = $host->p_fpops/1e9;
153
    $y = round($x, 2);
154
    row2(tra("Measured floating point speed"), tra("%1 billion ops/sec", $y));
155
    $x = $host->p_iops/1e9;
156
    $y = round($x, 2);
157
    row2(tra("Measured integer speed"), tra("%1 billion ops/sec", $y));
158
    $x = $host->n_bwup/KILO;
159
    $y = round($x, 2);
160
    if ($y > 0) {
161
        row2(tra("Average upload rate"), tra("%1 KB/sec", $y));
162
    } else {
163
        row2(tra("Average upload rate"), tra("Unknown"));
164
    }
165
    $x = $host->n_bwdown/KILO;
166
    $y = round($x, 2);
167
    if ($y > 0) {
168
        row2(tra("Average download rate"), tra("%1 KB/sec", $y));
169
    } else {
170
        row2(tra("Average download rate"), tra("Unknown"));
171
    }
172
    $x = $host->avg_turnaround/86400;
173
    if (!NO_COMPUTING) {
174
        row2(tra("Average turnaround time"), tra("%1 days", round($x, 2)));
175
        row2(tra("Application details"),
176
            "<a href=host_app_versions.php?hostid=$host->id>".tra("Show")."</a>"
177
        );
178
        $show_results = parse_bool($config, "show_results");
179
        if ($show_results) {
180
            $nresults = host_nresults($host);
181
            if ($nresults) {
182
                $results = "<a href=results.php?hostid=$host->id>$nresults</a>";
183
            } else {
184
                $results = "0";
185
            }
186
            row2(tra("Tasks"), $results);
187
        }
188
    }
189
190
    if ($user) {
191
        row2(tra("Number of times client has contacted server"), $host->rpc_seqno);
192
        row2(tra("Last time contacted server"), sched_log_link($host->rpc_time));
193
        row2(tra("Fraction of time BOINC is running"), number_format(100*$host->on_frac, 2)."%");
194
        if ($host->connected_frac > 0) {
195
            row2(tra("While BOINC is running, fraction of time computer has an Internet connection"), number_format(100*$host->connected_frac, 2)."%");
196
        }
197
        row2(tra("While BOINC is running, fraction of time computing is allowed"), number_format(100*$host->active_frac, 2)."%");
198
        row2(tra("While is BOINC running, fraction of time GPU computing is allowed"), number_format(100*$host->gpu_active_frac, 2)."%");
199
        if ($host->cpu_efficiency) {
200
            row2(tra("Average CPU efficiency"), $host->cpu_efficiency);
201
        }
202
        if (!NO_COMPUTING) {
203
            if ($host->duration_correction_factor) {
204
                row2(tra("Task duration correction factor"), $host->duration_correction_factor);
205
            }
206
        }
207
        row2(tra("Location"), location_form($host));
208
        if ($show_results && $nresults == 0) {
209
            $x = " &middot; <a href=host_delete.php?hostid=$host->id".url_tokens($user->authenticator).">".tra("Delete this computer")."</a> ";
210
        } else {
211
            $x = "";
212
        }
213
        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");
214
    } else {
215
        row2(tra("Number of times client has contacted server"), $host->rpc_seqno);
216
        row2(tra("Last contact"), date_str($host->rpc_time));
217
    }
218
    echo "</table>\n";
219
220
}
221
222
// the following is used for list of top hosts
223
//
224
function top_host_table_start($sort_by) {
225
    global $host_sites;
226
    shuffle($host_sites);
227
    start_table('table-striped');
228
    $x = array(
229
        tra("Info"),
230
        tra("Rank"),
231
        tra("Owner"),
232
    );
233
    if (!NO_STATS) {
234
        if ($sort_by == 'total_credit') {
235
            $x[] = "<a href=top_hosts.php?sort_by=expavg_credit>".tra("Avg. credit")."</a>";
236
            $x[] = tra("Total credit");
237
        } else {
238
            $x[] = tra("Recent average credit");
239
            $x[] = "<a href=top_hosts.php?sort_by=total_credit>".tra("Total credit")."</a>";
240
        }
241
    }
242
    $x[] = tra("BOINC version");
243
    $x[] = tra("CPU");
244
    $x[] = tra("GPU");
245
    $x[] = tra("Operating system");
246
    $s = 'style="text-align:right;"';
247
    $a = array("", "", "", $s, $s, "", "", "", "");
248
    row_heading_array($x, $a, "bg-default");
249
}
250
251
function host_nresults($host) {
252
    return BoincResult::count("hostid=$host->id");
253
}
254
255
256
// Parse the Virtualbox version information from inside the serialnum field.
257
// Prior to BOINC commit 6121ce1, the DB entry looked like e.g. "[vbox|5.0.0]"
258
// where 5.0.0 gave the Virtualbox version number. After 6121ce1, the entry was
259
// "[vbox|5.0.0|1|1]", where now two additional flags give information about
260
// hardware virtualization support. Older clients may have the old-style
261
// serialnum in the DB despite the server being upgraded.
262
function vbox_desc($x){
263
    if (preg_match("/\[vbox\|(.*?)(\|([01])\|([01]))?\]/",$x,$matches)){
264
        $desc = "Virtualbox (".$matches[1].") ".tra("installed");
265
        if (sizeof($matches)>2){
266
            if ($matches[3]=="1" and $matches[4]=="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...
267
                return $desc.tra(", CPU has hardware virtualization support and it is enabled");
268
            } elseif ($matches[3]=="1" and $matches[4]=="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...
269
                return $desc.tra(", CPU has hardware virtualization support but it is disabled");
270
            } elseif ($matches[3]=="0") {
271
                return $desc.tra(", CPU does not have hardware virtualization support");
272
            }
273
        } else {
274
            return $desc;
275
        }
276
    } else {
277
        return tra("None");
278
    }
279
}
280
281
// Given string of the form [BOINC|vers][type|model|count|RAM|driver-vers][vbox|vers],
282
// return a human-readable version of the GPU info
283
//
284
function gpu_desc($x, $detail=true) {
285
    $descs = explode("]", $x);
286
    array_pop($descs);
287
    $str = "";
288
    foreach ($descs as $desc) {
289
        $desc = trim($desc, "[");
290
        $d = explode("|", $desc);
291
        //print_r($d);
292
        if ($d[0] == "BOINC") continue;
293
        if ($d[0] == "vbox") continue;
294
        if (count($d) < 5) continue;
295
        if ($str) $str .= "<p>";
296
        if ($d[2]!="" && $d[2]!="1") $str .= "[".$d[2]."] ";
297
        if ($d[0] == "CUDA") {
298
            $str .= "NVIDIA";
299
        } else if ($d[0] == "CAL") {
300
            $str .= "AMD";
301
        } else if ($d[0] == "opencl_gpu") {
302
            $str .= "OpenCL GPU";
303
        } else {
304
            $str .= $d[0];
305
        }
306
        $str .= " ".$d[1];
307
        if ($detail) {
308
            $str .= " (".$d[3].")";
309
            if (array_key_exists(4, $d)) {
310
                if ($d[4] != "" && $d[4] != 0) {
311
                    // if version has no '.', assume it's in 100*maj+min form
312
                    //
313
                    if (strchr($d[4], '.')) {
314
                        $str .= " driver: ".$d[4];
315
                    } else {
316
                        $i = (int)$d[4];
317
                        $maj = (int)($i/100);
318
                        $min = $i%100;
319
                        $str .= sprintf(" driver: %d.%02d", $maj, $min);
320
                    }
321
                }
322
            }
323
            if (array_key_exists(5, $d)) {
324
                if ($d[5] != "" && $d[5] != 0) {
325
                    if (strchr($d[5], '.')) {
326
                        $str .= " OpenCL: ".$d[5];
327
                    } else {
328
                        $i = (int)$d[5];
329
                        $maj = (int)($i/100);
330
                        $min = $i%100;
331
                        $str .= sprintf(" OpenCL: %d.%d", $maj, $min);
332
                    }
333
                }
334
            }
335
        }
336
    }
337
    if (!$str) $str = "---";
338
    return $str;
339
}
340
341
// Given the same string as above, return the BOINC version
342
//
343
function boinc_version($x) {
344
    $y = strstr($x, 'BOINC');
345
    if (!$y) return '';
346
    $z = explode("]", $y, 2);
347
    $a = explode('|', $z[0]);
348
    $v = $a[1];
349
    if (array_key_exists(2, $a)) {
350
        $brand = $a[2];
351
        $v .= " ($brand)";
352
    }
353
    return $v;
354
}
355
356
function cpu_desc($host) {
357
    return "$host->p_vendor<br>$host->p_model<br>".tra("(%1 processors)", $host->p_ncpus)."\n";
358
}
359
360
// If private is true, we're showing the host to its owner,
361
// so it's OK to show the domain name etc.
362
// If private is false, show the owner's name only if they've given permission
363
//
364
function show_host_row($host, $i, $private, $show_owner, $any_product_name) {
365
    $anonymous = false;
366
    if (!$private) {
367
        if ($show_owner) {
368
            $user = BoincUser::lookup_id($host->userid);
369
            if ($user && $user->show_hosts) {
370
            } else {
371
                $anonymous = true;
372
            }
373
        }
374
    }
375
    echo "<tr><td>ID: $host->id
376
        <br><a href=show_host_detail.php?hostid=$host->id>".tra("Details")."</a>
377
    ";
378
    if (!NO_COMPUTING) {
379
        echo "
380
        | <a href=results.php?hostid=$host->id>".tra("Tasks")."</a>
381
        ";
382
    }
383
    if (!NO_STATS) {
384
        if (!$anonymous) {
385
            echo "
386
                <br><nobr><small>".tra("Cross-project stats:")."</small></nobr><br>".cross_project_links($host);
387
        }
388
    }
389
    echo "
390
        </td>
391
    ";
392
    if ($private) {
393
        echo "<td>$host->domain_name</td>\n";
394
        if ($any_product_name) {
395
            echo "<td>$host->product_name</td>\n";
396
        }
397
        echo "<td>$host->venue</td>\n";
398
    } else {
399
        echo "<td>$i</td>\n";
400
        if ($show_owner) {
401
            if ($anonymous) {
402
                echo "<td>".tra("Anonymous")."</td>\n";
403
            } else {
404
                echo "<td>", user_links($user, BADGE_HEIGHT_MEDIUM), "</td>\n";
405
            }
406
        }
407
    }
408
    if ($show_owner) {
409
        // This is used in the "top computers" display
410
        //
411
        if (!NO_STATS) {
412
            printf("
413
                <td align=right>%s</td>
414
                <td align=right>%s</td>",
415
                format_credit($host->expavg_credit),
416
                format_credit_large($host->total_credit)
417
            );
418
        }
419
        printf("
420
            <td>%s</td>
421
            <td>%s</td>
422
            <td>%s</td>
423
            <td>%s <br> %s</td>",
424
            boinc_version($host->serialnum),
425
            cpu_desc($host),
426
            gpu_desc($host->serialnum),
427
            $host->os_name, $host->os_version
428
        );
429
    } else {
430
        // This is used to show the computers of a given user
431
        //
432
        if (!NO_STATS) {
433
            printf("
434
                <td align=right>%s</td>
435
                <td align=right>%s</td>",
436
                format_credit($host->expavg_credit),
437
                format_credit_large($host->total_credit)
438
            );
439
        }
440
        printf("
441
            <td>%s</td>
442
            <td>%s</td>
443
            <td>%s</td>
444
            <td>%s<br><small>%s</small></td>
445
            <td>%s</td>
446
            ",
447
            boinc_version($host->serialnum),
448
            cpu_desc($host),
449
            gpu_desc($host->serialnum),
450
            $host->os_name, $host->os_version,
451
            sched_log_link($host->rpc_time)
452
        );
453
    }
454
455
    echo "</tr>\n";
456
}
457
458
// Logic for deciding whether two host records might actually
459
// be the same machine, based on CPU info
460
//
461
// p_vendor is typically either AuthenticAMD or GenuineIntel.
462
// Over time we've changed the contents of p_model.
463
// Some examples:
464
// Intel(R) Core(TM)2 Duo CPU  E7300  @ 2.66GHz [Family 6 Model 23 Stepping 6]
465
// AMD Athlon(tm) II X2 250 Processor [Family 16 Model 6 Stepping 3]
466
// Intel(R) Xeon(R) CPU X5650 @ 2.67GHz [x86 Family 6 Model 44 Stepping 2]
467
// Intel(R) Core(TM) i5-2500K CPU @ 3.30GHz [Intel64 Family 6 Model 42 Stepping 7]
468
//
469
// in the last 2 cases, let's call x86 and Intel64 the "architecture"
470
//
471
// so, here's the policy:
472
//
473
// if p_ncpus different, return false
474
// if p_vendor different, return false
475
// if both have family/model/stepping info
476
//    if info disagrees, return false
477
//    if both have GHz info, and they disagree, return false
478
//    if both have architecture, and they disagree, return false
479
//    return true
480
// if p_model different, return false
481
// return true
482
//
483
484
// parse p_model to produce the following structure:
485
// x->speed     "3.00GHz" etc. or null
486
// x->arch      "x86" etc. or null
487
// x->info      "Family 6 Model 23 Stepping 6" etc. or null
488
//
489
function parse_model($model) {
490
    $y = explode(" ", $model);
491
    $x = new StdClass;
492
    $x->speed = null;
493
    $x->arch = null;
494
    $x->info = null;
495
    foreach ($y as $z) {
496
        if (strstr($z, "GHz")) $x->speed = $z;
497
        if (strstr($z, "MHz")) $x->speed = $z;
498
    }
499
    $pos1 = strpos($model, '[');
500
    if ($pos1 === false) return $x;
501
    $pos2 = strpos($model, ']');
502
    if ($pos2 === false) return $x;
503
    $a = substr($model, $pos1+1, $pos2-$pos1-1);
504
    $y = explode(" ", $a);
505
    if (count($y) == 0) return $x;
506
    if ($y[0] == "Family") {
507
        $x->info = $a;
508
    } else {
509
        $x->arch = $y[0];
510
        $x->info = substr($a, strlen($y[0])+1);
511
    }
512
    return $x;
513
}
514
515
function cpus_compatible($host1, $host2) {
516
    if ($host1->p_ncpus != $host2->p_ncpus) return false;
517
    if ($host1->p_vendor != $host2->p_vendor) return false;
518
    $x1 = parse_model($host1->p_model);
519
    $x2 = parse_model($host2->p_model);
520
    if ($x1->info && $x2->info) {
521
        if ($x1->info != $x2->info) return false;
522
        if ($x1->speed && $x2->speed) {
523
            if ($x1->speed != $x2->speed) return false;
524
        }
525
        if ($x1->arch && $x2->arch) {
526
            if ($x1->arch != $x2->arch) return false;
527
        }
528
        return true;
529
    }
530
    if ($host1->p_model != $host2->p_model) return false;
531
    return true;
532
}
533
534
// does one host strictly precede the other?
535
//
536
function times_disjoint($host1, $host2) {
537
    if ($host1->rpc_time < $host2->create_time) return true;
538
    if ($host2->rpc_time < $host1->create_time) return true;
539
    return false;
540
}
541
542
function os_compatible($host1, $host2) {
543
    if (strstr($host1->os_name, "Windows") && strstr($host2->os_name, "Windows")) return true;
544
    if (strstr($host1->os_name, "Linux") && strstr($host2->os_name, "Linux")) return true;
545
    if (strstr($host1->os_name, "Darwin") && strstr($host2->os_name, "Darwin")) return true;
546
    if (strstr($host1->os_name, "SunOS") && strstr($host2->os_name, "SunOS")) return true;
547
    if ($host1->os_name == $host2->os_name) return true;
548
    return false;
549
}
550
551
// Return true if it's possible that the two host records
552
// correspond to the same host
553
// NOTE: the cheat-proofing comes from checking
554
// that their time intervals are disjoint.
555
// So the CPU/OS checks don't have to be very strict.
556
//
557
function hosts_compatible($host1, $host2, $show_detail) {
558
    // A host is "new" if it has no credit and no results.
559
    // Skip disjoint-time check if one host or other is new
560
    //
561
    $new1 = !$host1->total_credit && !host_nresults($host1);
562
    $new2 = !$host2->total_credit && !host_nresults($host2);
563
    if (!$new1 && !$new2) {
564
        if (!times_disjoint($host1, $host2)) {
565
            if ($show_detail) {
566
                $c1 = date_str($host1->create_time);
567
                $r1 = date_str($host1->rpc_time);
568
                $c2 = date_str($host2->create_time);
569
                $r2 = date_str($host2->rpc_time);
570
                echo "<br>".tra("Host %1 has overlapping lifetime:", $host2->id)." ($c1 - $r1), ($c2 - $r2)";
571
            }
572
            return false;
573
        }
574
    }
575
    if (!os_compatible($host1, $host2)) {
576
        if ($show_detail) {
577
            echo "<br>".tra("Host %1 has an incompatible OS:", $host2->id)." ($host1->os_name, $host2->os_name)\n";
578
        }
579
        return false;
580
    }
581
    if (!cpus_compatible($host1, $host2)) {
582
        if ($show_detail) {
583
            echo "<br>".tra("Host %1 has an incompatible CPU:", $host2->id)." ($host1->p_vendor $host1->p_model, $host2->p_vendor $host2->p_model)\n";
584
        }
585
        return false;
586
    }
587
    return true;
588
}
589
590
// recompute host's average credit by scanning results.
591
// Could be expensive if lots of results!
592
//
593
function host_update_credit($hostid) {
594
    $total = 0;
595
    $avg = 0;
596
    $avg_time = 0;
597
598
    $results = BoincResult::enum("hostid=$hostid order by received_time");
599
    foreach($results as $result) {
600
        if ($result->granted_credit <= 0) continue;
601
        $total += $result->granted_credit;
602
603
        update_average(
604
            $result->received_time,
605
            $result->sent_time,
606
            $result->granted_credit,
607
            $avg,
608
            $avg_time
609
        );
610
611
        //echo "<br>$avg\n";
612
    }
613
614
    // do a final decay
615
    //
616
    $now = time();
617
    update_average(now, 0, 0, $avg, $avg_time);
618
619
    $host = new BoincHost();
620
    $host->id = hostid;
621
    $host->update("total_credit=$total, expavg_credit=$avg, expavg_time=$now");
622
}
623
624
// decay a host's average credit
625
//
626
function host_decay_credit($host) {
627
    $avg = $host->expavg_credit;
628
    $avg_time = $host->expavg_time;
629
    $now = time();
630
    update_average($now, 0, 0, $avg, $avg_time);
631
    $host->update("expavg_credit=$avg, expavg_time=$now");
632
}
633
634
// if the host hasn't received new credit for ndays,
635
// decay its average and return true
636
//
637
function host_inactive_ndays($host, $ndays) {
638
    $diff = time() - $host->expavg_time;
639
    if ($diff > $ndays*86400) {
640
        host_decay_credit($host);
641
        return true;
642
    }
643
    return false;
644
}
645
646
// invariant: old_host.create_time < new_host.create_time
647
//
648
function merge_hosts($old_host, $new_host) {
649
    if ($old_host->id == $new_host->id) {
650
        return tra("same host");
651
    }
652
    if (!hosts_compatible($old_host, $new_host, false)) {
653
        return tra("Can't merge host %1 into %2 - they're incompatible", $old_host->id, $new_host->id);
654
    }
655
656
    echo "<br>".tra("Merging host %1 into host %2", $old_host->id, $new_host->id)."\n";
657
658
    // decay the average credit of both hosts
659
    //
660
    $now = time();
661
    update_average($now, 0, 0, $old_host->expavg_credit, $old_host->expavg_time);
662
    update_average($now, 0, 0, $new_host->expavg_credit, $new_host->expavg_time);
663
664
    // update the database:
665
    // - add credit from old to new host
666
    // - change results to refer to new host
667
    // - put old host in "zombie" state (userid=0, rpc_seqno=new host ID)
668
    //
669
    $total_credit = $old_host->total_credit + $new_host->total_credit;
670
    $recent_credit = $old_host->expavg_credit + $new_host->expavg_credit;
671
    $result = $new_host->update("total_credit=$total_credit, expavg_credit=$recent_credit, expavg_time=$now");
672
    if (!$result) {
673
        return tra("Couldn't update credit of new computer");
674
    }
675
    $result = BoincResult::update_aux("hostid=$new_host->id where hostid=$old_host->id");
676
    if (!$result) {
677
        return tra("Couldn't update results");
678
    }
679
680
    $result = $old_host->update("total_credit=0, expavg_credit=0, userid=0, rpc_seqno=$new_host->id");
681
    if (!$result) {
682
        return tra("Couldn't retire old computer");
683
    }
684
    echo "<br>".tra("Retired old computer %1", $old_host->id)."\n";
685
    return 0;
686
}
687
688
//////////////// helper functions for hosts_user.php ////////////////
689
690
function link_url($sort, $rev, $show_all) {
691
    global $userid;
692
    $x = $userid ? "&userid=$userid":"";
693
    return "hosts_user.php?sort=$sort&rev=$rev&show_all=$show_all$x";
694
}
695
696
function link_url_rev($actual_sort, $sort, $rev, $show_all) {
697
    if ($actual_sort == $sort) {
698
        $rev = 1 - $rev;
699
    }
700
    return link_url($sort, $rev, $show_all);
701
}
702
703
function more_or_less($sort, $rev, $show_all) {
704
    echo "<p>";
705
    if ($show_all) {
706
        $url = link_url($sort, $rev, 0);
707
        echo tra("Show:")." ".tra("All computers")." &middot; <a href=$url>".tra("Only computers active in past 30 days")."</a>";
708
    } else {
709
        $url = link_url($sort, $rev, 1);
710
        echo tra("Show:")." <a href=$url>".tra("All computers")."</a> &middot; ".tra("Only computers active in past 30 days");
711
    }
712
    echo "<p>";
713
}
714
715
function user_host_table_start(
716
    $private, $sort, $rev, $show_all, $any_product_name
717
) {
718
    start_table('table-striped');
719
    $x = array();
720
    $a = array();
721
722
    $url = link_url_rev($sort, "id", $rev, $show_all);
723
    $x[] = "<a href=$url>".tra("Computer ID")."</a>";
724
    $a[] = '';
725
726
    if ($private) {
727
        $url = link_url_rev($sort, "name", $rev, $show_all);
728
        $x[] = "<a href=$url>".tra("Name")."</a>";
729
        $a[] = null;
730
        $url = link_url_rev($sort, "venue", $rev, $show_all);
731
        if ($any_product_name) {
732
            $x[] = tra("Model");
733
            $a[] = null;
734
        }
735
        $x[] = "<a href=$url>".tra("Location")."</a>";
736
        $a[] = null;
737
    } else {
738
        $x[] = tra("Rank");
739
        $a[] = null;
740
    }
741
    if (!NO_STATS) {
742
        $url = link_url_rev($sort, "expavg_credit", $rev, $show_all);
743
        $x[] = "<a href=$url>".tra("Avg. credit")."</a>";
744
        $a[] = ALIGN_RIGHT;
745
        $url = link_url_rev($sort, "total_credit", $rev, $show_all);
746
        $x[] = "<a href=$url>".tra("Total credit")."</a>";
747
        $a[] = ALIGN_RIGHT;
748
    }
749
    $x[] = tra("BOINC<br>version");
750
    $a[] = null;
751
    $url = link_url_rev($sort, "cpu", $rev, $show_all);
752
    $x[] = "<a href=$url>".tra("CPU")."</a>";
753
    $a[] = null;
754
    $x[] = tra("GPU");
755
    $a[] = null;
756
    $url = link_url_rev($sort, "os", $rev, $show_all);
757
    $x[] = "<a href=$url>".tra("Operating System")."</a>";
758
    $a[] = null;
759
    $url = link_url_rev($sort, "rpc_time", $rev, $show_all);
760
    $x[] = "<a href=$url>".tra("Last contact")."</a>";
761
    $a[] = null;
762
    row_heading_array($x, $a, "bg-default");
763
}
764
765
function show_user_hosts($userid, $private, $show_all, $sort, $rev) {
766
    $desc = false;  // whether the sort order's default is decreasing
767
    switch ($sort) {
768
    case "total_credit": $sort_clause = "total_credit"; $desc = true; break;
769
    case "expavg_credit": $sort_clause = "expavg_credit"; $desc = true; break;
770
    case "name": $sort_clause = "domain_name"; break;
771
    case "id": $sort_clause = "id"; break;
772
    case "cpu": $sort_clause = "p_vendor"; break;
773
    case "gpu": $sort_clause = "serialnum"; break;
774
    case "os": $sort_clause = "os_name"; break;
775
    case "venue": $sort_clause = "venue"; break;
776
    default:
777
        // default value -- sort by RPC time
778
        $sort = "rpc_time";
779
        $sort_clause = "rpc_time";
780
        $desc = true;
781
    }
782
783
    if ($rev != $desc) {
784
        $sort_clause .= " desc";
785
    }
786
    more_or_less($sort, $rev, $show_all);
787
788
    $now = time();
789
    $old_hosts=0;
790
    $i = 1;
791
    $hosts = BoincHost::enum("userid=$userid order by $sort_clause");
792
    $any_product_name = false;
793
    foreach ($hosts as $host) {
794
        if ($host->product_name) {
795
            $any_product_name = true;
796
            break;
797
        }
798
    }
799
    user_host_table_start($private, $sort, $rev, $show_all, $any_product_name);
800
    foreach ($hosts as $host) {
801
        $is_old=false;
802
        if (($now - $host->rpc_time) > 30*86400) {
803
            $is_old=true;
804
            $old_hosts++;
805
        }
806
        if (!$show_all && $is_old) continue;
807
        show_host_row($host, $i, $private, false, $any_product_name);
808
        $i++;
809
    }
810
    end_table();
811
812
    if ($old_hosts>0) {
813
        more_or_less($sort, $rev, $show_all);
814
    }
815
816
    if ($private) {
817
        echo "
818
            <a href=merge_by_name.php>".tra("Merge computers by name")."</a>
819
        ";
820
    }
821
}
822
823
// remove user-specific info from a user's hosts
824
//
825
function anonymize_hosts($user) {
826
    $hosts = BoincHost::enum("userid=$user->id");
827
    foreach ($hosts as $h) {
828
        $h->update("domain_name='deleted', last_ip_addr=''");
829
    }
830
}
831
832
$cvs_version_tracker[]="\$Id$";  //Generated automatically - do not edit
833
834
?>
835