Issues (1839)

html/inc/host.inc (1 issue)

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") {
267
                return $desc.tra(", CPU has hardware virtualization support and it is enabled");
268
            } elseif ($matches[3]=="1" and $matches[4]=="0") {
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) {
0 ignored issues
show
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...
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