Completed
Push — master ( 3fce85...f171bb )
by Vitalii
01:05 queued 17s
created

gpu_desc()   B

Complexity

Conditions 7
Paths 18

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

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