.
require_once("../inc/credit.inc");
require_once("../inc/stats_sites.inc");
require_once("../inc/boinc_db.inc");
require_once("../inc/user.inc");
function link_to_results($host) {
if (!$host) return tra("No host");
$config = get_config();
if (!parse_bool($config, "show_results")) return tra("Unavailable");
$nresults = host_nresults($host);
if (!$nresults) return "0";
return "id>$nresults";
}
function sched_log_name($x) {
if ($x == 0) return "NO_SUCH_LOG";
return gmdate('Y-m-d_H/Y-m-d_H:i', $x) . ".txt";
}
function sched_log_link($x) {
if (file_exists("sched_logs")) {
return "" . time_str($x) . "";
} else {
return time_str($x);
}
}
function location_form($host) {
$none = "selected";
$h=$w=$s=$m="";
if ($host->venue == "home") $h = "selected";
if ($host->venue == "work") $w = "selected";
if ($host->venue == "school") $s = "selected";
$x = "
";
return $x;
}
function cross_project_links($host) {
global $host_sites;
$x = "";
foreach ($host_sites as $h) {
$url = $h[0];
$name = $h[1];
$img = $h[2];
$x .= "host_cpid."> ";
}
return $x;
}
// Show full-page description of $host.
// If $user is non-null, it's both the owner of the host
// and the logged in user (so show some extra fields)
//
function show_host($host, $user, $ipprivate) {
global $config;
start_table();
row1(tra("Computer information"));
$anonymous = false;
if ($user) {
if ($ipprivate) {
row2(tra("IP address"), "$host->last_ip_addr
".tra("(same the last %1 times)", $host->nsame_ip_addr));
if ($host->last_ip_addr != $host->external_ip_addr) {
row2(tra("External IP address"), $host->external_ip_addr);
}
} else {
row2(tra("IP address"), "id&ipprivate=1>".tra("Show IP address")."");
}
row2(tra("Domain name"), $host->domain_name);
if ($host->product_name) {
row2(tra("Product name"), $host->product_name);
}
$x = $host->timezone/3600;
if ($x >= 0) $x="+$x";
row2(tra("Local Standard Time"), tra("UTC %1 hours", $x));
} else {
$owner = BoincUser::lookup_id($host->userid);
if ($owner && $owner->show_hosts) {
row2(tra("Owner"), user_links($owner, BADGE_HEIGHT_MEDIUM));
} else {
row2(tra("Owner"), tra("Anonymous"));
$anonymous = true;
}
}
row2(tra("Created"), time_str($host->create_time));
if (!NO_STATS) {
row2(tra("Total credit"), format_credit_large($host->total_credit));
row2(tra("Average credit"), format_credit($host->expavg_credit));
if (!$anonymous) {
row2(tra("Cross project credit"), cross_project_links($host));
}
}
row2(tra("CPU type"), "$host->p_vendor
$host->p_model");
row2(tra("Number of processors"), $host->p_ncpus);
if ($host->serialnum) {
row2(tra("Coprocessors"), gpu_desc($host->serialnum));
}
row2(tra("Virtualization"), vbox_desc($host->serialnum));
row2(tra("Operating System"), "$host->os_name
$host->os_version");
$v = boinc_version($host->serialnum);
if ($v) {
row2(tra("BOINC version"), $v);
}
$x = $host->m_nbytes/GIGA;
$y = round($x, 2);
row2(tra("Memory"), tra("%1 GB", $y));
if ($host->m_cache > 0) {
$x = $host->m_cache/KILO;
$y = round($x, 2);
row2(tra("Cache"), tra("%1 KB", $y));
}
if ($user) {
$x = $host->m_swap/GIGA;
$y = round($x, 2);
row2(tra("Swap space"), tra("%1 GB", $y));
$x = $host->d_total/GIGA;
$y = round($x, 2);
row2(tra("Total disk space"), tra("%1 GB", $y));
$x = $host->d_free/GIGA;
$y = round($x, 2);
row2(tra("Free Disk Space"), tra("%1 GB", $y));
}
$x = $host->p_fpops/1e9;
$y = round($x, 2);
row2(tra("Measured floating point speed"), tra("%1 billion ops/sec", $y));
$x = $host->p_iops/1e9;
$y = round($x, 2);
row2(tra("Measured integer speed"), tra("%1 billion ops/sec", $y));
$x = $host->n_bwup/KILO;
$y = round($x, 2);
if ($y > 0) {
row2(tra("Average upload rate"), tra("%1 KB/sec", $y));
} else {
row2(tra("Average upload rate"), tra("Unknown"));
}
$x = $host->n_bwdown/KILO;
$y = round($x, 2);
if ($y > 0) {
row2(tra("Average download rate"), tra("%1 KB/sec", $y));
} else {
row2(tra("Average download rate"), tra("Unknown"));
}
$x = $host->avg_turnaround/86400;
if (!NO_COMPUTING) {
row2(tra("Average turnaround time"), tra("%1 days", round($x, 2)));
row2(tra("Application details"),
"id>".tra("Show").""
);
$show_results = parse_bool($config, "show_results");
if ($show_results) {
$nresults = host_nresults($host);
if ($nresults) {
$results = "id>$nresults";
} else {
$results = "0";
}
row2(tra("Tasks"), $results);
}
}
if ($user) {
row2(tra("Number of times client has contacted server"), $host->rpc_seqno);
row2(tra("Last time contacted server"), sched_log_link($host->rpc_time));
row2(tra("Fraction of time BOINC is running"), number_format(100*$host->on_frac, 2)."%");
if ($host->connected_frac > 0) {
row2(tra("While BOINC is running, fraction of time computer has an Internet connection"), number_format(100*$host->connected_frac, 2)."%");
}
row2(tra("While BOINC is running, fraction of time computing is allowed"), number_format(100*$host->active_frac, 2)."%");
row2(tra("While is BOINC running, fraction of time GPU computing is allowed"), number_format(100*$host->gpu_active_frac, 2)."%");
if ($host->cpu_efficiency) {
row2(tra("Average CPU efficiency"), $host->cpu_efficiency);
}
if (!NO_COMPUTING) {
if ($host->duration_correction_factor) {
row2(tra("Task duration correction factor"), $host->duration_correction_factor);
}
}
row2(tra("Location"), location_form($host));
if ($show_results && $nresults == 0) {
$x = " · id".url_tokens($user->authenticator).">".tra("Delete this computer")." ";
} else {
$x = "";
}
row2(tra("Merge duplicate records of this computer"), "id>".tra("Merge")." $x");
} else {
row2(tra("Number of times client has contacted server"), $host->rpc_seqno);
row2(tra("Last contact"), date_str($host->rpc_time));
}
echo "\n";
}
// the following is used for list of top hosts
//
function top_host_table_start($sort_by) {
global $host_sites;
shuffle($host_sites);
start_table('table-striped');
$x = array(
tra("Info"),
tra("Rank"),
tra("Owner"),
);
if (!NO_STATS) {
if ($sort_by == 'total_credit') {
$x[] = "".tra("Avg. credit")."";
$x[] = tra("Total credit");
} else {
$x[] = tra("Recent average credit");
$x[] = "".tra("Total credit")."";
}
}
$x[] = tra("BOINC version");
$x[] = tra("CPU");
$x[] = tra("GPU");
$x[] = tra("Operating system");
$s = 'style="text-align:right;"';
$a = array("", "", "", $s, $s, "", "", "", "");
row_heading_array($x, $a, "bg-default");
}
function host_nresults($host) {
return BoincResult::count("hostid=$host->id");
}
// Parse the Virtualbox version information from inside the serialnum field.
// Prior to BOINC commit 6121ce1, the DB entry looked like e.g. "[vbox|5.0.0]"
// where 5.0.0 gave the Virtualbox version number. After 6121ce1, the entry was
// "[vbox|5.0.0|1|1]", where now two additional flags give information about
// hardware virtualization support. Older clients may have the old-style
// serialnum in the DB despite the server being upgraded.
function vbox_desc($x){
if (preg_match("/\[vbox\|(.*?)(\|([01])\|([01]))?\]/",$x,$matches)){
$desc = "Virtualbox (".$matches[1].") ".tra("installed");
if (sizeof($matches)>2){
if ($matches[3]=="1" and $matches[4]=="1") {
return $desc.tra(", CPU has hardware virtualization support and it is enabled");
} elseif ($matches[3]=="1" and $matches[4]=="0") {
return $desc.tra(", CPU has hardware virtualization support but it is disabled");
} elseif ($matches[3]=="0") {
return $desc.tra(", CPU does not have hardware virtualization support");
}
} else {
return $desc;
}
} else {
return tra("None");
}
}
// Given string of the form [BOINC|vers][type|model|count|RAM|driver-vers][vbox|vers],
// return a human-readable version of the GPU info
//
function gpu_desc($x, $detail=true) {
$descs = explode("]", $x);
array_pop($descs);
$str = "";
foreach ($descs as $desc) {
$desc = trim($desc, "[");
$d = explode("|", $desc);
//print_r($d);
if ($d[0] == "BOINC") continue;
if ($d[0] == "vbox") continue;
if ($str) $str .= "";
if ($d[2]!="" && $d[2]!="1") $str .= "[".$d[2]."] ";
if ($d[0] == "CUDA") {
$str .= "NVIDIA";
} else if ($d[0] == "CAL") {
$str .= "AMD";
} else if ($d[0] == "opencl_gpu") {
$str .= "OpenCL GPU";
} else {
$str .= $d[0];
}
$str .= " ".$d[1];
if ($detail) {
$str .= " (".$d[3].")";
if (array_key_exists(4, $d)) {
if ($d[4] != "" && $d[4] != 0) {
// if version has no '.', assume it's in 100*maj+min form
//
if (strchr($d[4], '.')) {
$str .= " driver: ".$d[4];
} else {
$i = (int)$d[4];
$maj = (int)($i/100);
$min = $i%100;
$str .= sprintf(" driver: %d.%02d", $maj, $min);
}
}
}
if (array_key_exists(5, $d)) {
if ($d[5] != "" && $d[5] != 0) {
if (strchr($d[5], '.')) {
$str .= " OpenCL: ".$d[5];
} else {
$i = (int)$d[5];
$maj = (int)($i/100);
$min = $i%100;
$str .= sprintf(" OpenCL: %d.%d", $maj, $min);
}
}
}
}
}
if (!$str) $str = "---";
return $str;
}
// Given the same string as above, return the BOINC version
//
function boinc_version($x) {
$y = strstr($x, 'BOINC');
if (!$y) return '';
$z = explode("]", $y, 2);
$a = explode('|', $z[0]);
$v = $a[1];
if (array_key_exists(2, $a)) {
$brand = $a[2];
$v .= " ($brand)";
}
return $v;
}
function cpu_desc($host) {
return "$host->p_vendor
$host->p_model
".tra("(%1 processors)", $host->p_ncpus)."\n";
}
// If private is true, we're showing the host to its owner,
// so it's OK to show the domain name etc.
// If private is false, show the owner's name only if they've given permission
//
function show_host_row($host, $i, $private, $show_owner, $any_product_name) {
$anonymous = false;
if (!$private) {
if ($show_owner) {
$user = BoincUser::lookup_id($host->userid);
if ($user && $user->show_hosts) {
} else {
$anonymous = true;
}
}
}
echo "
ID: $host->id
id>".tra("Details")."
";
if (!NO_COMPUTING) {
echo "
| id>".tra("Tasks")."
";
}
if (!NO_STATS) {
if (!$anonymous) {
echo "
".tra("Cross-project stats:")." ".cross_project_links($host);
}
}
echo "
|
";
if ($private) {
echo "$host->domain_name | \n";
if ($any_product_name) {
echo "$host->product_name | \n";
}
echo "$host->venue | \n";
} else {
echo "$i | \n";
if ($show_owner) {
if ($anonymous) {
echo "".tra("Anonymous")." | \n";
} else {
echo "", user_links($user, BADGE_HEIGHT_MEDIUM), " | \n";
}
}
}
if ($show_owner) {
// This is used in the "top computers" display
//
if (!NO_STATS) {
printf("
%s |
%s | ",
format_credit($host->expavg_credit),
format_credit_large($host->total_credit)
);
}
printf("
%s |
%s |
%s |
%s %s | ",
boinc_version($host->serialnum),
cpu_desc($host),
gpu_desc($host->serialnum),
$host->os_name, $host->os_version
);
} else {
// This is used to show the computers of a given user
//
if (!NO_STATS) {
printf("
%s |
%s | ",
format_credit($host->expavg_credit),
format_credit_large($host->total_credit)
);
}
printf("
%s |
%s |
%s |
%s %s |
%s |
",
boinc_version($host->serialnum),
cpu_desc($host),
gpu_desc($host->serialnum),
$host->os_name, $host->os_version,
sched_log_link($host->rpc_time)
);
}
echo "
\n";
}
// Logic for deciding whether two host records might actually
// be the same machine, based on CPU info
//
// p_vendor is typically either AuthenticAMD or GenuineIntel.
// Over time we've changed the contents of p_model.
// Some examples:
// Intel(R) Core(TM)2 Duo CPU E7300 @ 2.66GHz [Family 6 Model 23 Stepping 6]
// AMD Athlon(tm) II X2 250 Processor [Family 16 Model 6 Stepping 3]
// Intel(R) Xeon(R) CPU X5650 @ 2.67GHz [x86 Family 6 Model 44 Stepping 2]
// Intel(R) Core(TM) i5-2500K CPU @ 3.30GHz [Intel64 Family 6 Model 42 Stepping 7]
//
// in the last 2 cases, let's call x86 and Intel64 the "architecture"
//
// so, here's the policy:
//
// if p_ncpus different, return false
// if p_vendor different, return false
// if both have family/model/stepping info
// if info disagrees, return false
// if both have GHz info, and they disagree, return false
// if both have architecture, and they disagree, return false
// return true
// if p_model different, return false
// return true
//
// parse p_model to produce the following structure:
// x->speed "3.00GHz" etc. or null
// x->arch "x86" etc. or null
// x->info "Family 6 Model 23 Stepping 6" etc. or null
//
function parse_model($model) {
$y = explode(" ", $model);
$x = new StdClass;
$x->speed = null;
$x->arch = null;
$x->info = null;
foreach ($y as $z) {
if (strstr($z, "GHz")) $x->speed = $z;
if (strstr($z, "MHz")) $x->speed = $z;
}
$pos1 = strpos($model, '[');
if ($pos1 === false) return $x;
$pos2 = strpos($model, ']');
if ($pos2 === false) return $x;
$a = substr($model, $pos1+1, $pos2-$pos1-1);
$y = explode(" ", $a);
if (count($y) == 0) return $x;
if ($y[0] == "Family") {
$x->info = $a;
} else {
$x->arch = $y[0];
$x->info = substr($a, strlen($y[0])+1);
}
return $x;
}
function cpus_compatible($host1, $host2) {
if ($host1->p_ncpus != $host2->p_ncpus) return false;
if ($host1->p_vendor != $host2->p_vendor) return false;
$x1 = parse_model($host1->p_model);
$x2 = parse_model($host2->p_model);
if ($x1->info && $x2->info) {
if ($x1->info != $x2->info) return false;
if ($x1->speed && $x2->speed) {
if ($x1->speed != $x2->speed) return false;
}
if ($x1->arch && $x2->arch) {
if ($x1->arch != $x2->arch) return false;
}
return true;
}
if ($host1->p_model != $host2->p_model) return false;
return true;
}
// does one host strictly precede the other?
//
function times_disjoint($host1, $host2) {
if ($host1->rpc_time < $host2->create_time) return true;
if ($host2->rpc_time < $host1->create_time) return true;
return false;
}
function os_compatible($host1, $host2) {
if (strstr($host1->os_name, "Windows") && strstr($host2->os_name, "Windows")) return true;
if (strstr($host1->os_name, "Linux") && strstr($host2->os_name, "Linux")) return true;
if (strstr($host1->os_name, "Darwin") && strstr($host2->os_name, "Darwin")) return true;
if (strstr($host1->os_name, "SunOS") && strstr($host2->os_name, "SunOS")) return true;
if ($host1->os_name == $host2->os_name) return true;
return false;
}
// Return true if it's possible that the two host records
// correspond to the same host
// NOTE: the cheat-proofing comes from checking
// that their time intervals are disjoint.
// So the CPU/OS checks don't have to be very strict.
//
function hosts_compatible($host1, $host2, $show_detail) {
// A host is "new" if it has no credit and no results.
// Skip disjoint-time check if one host or other is new
//
$new1 = !$host1->total_credit && !host_nresults($host1);
$new2 = !$host2->total_credit && !host_nresults($host2);
if (!$new1 && !$new2) {
if (!times_disjoint($host1, $host2)) {
if ($show_detail) {
$c1 = date_str($host1->create_time);
$r1 = date_str($host1->rpc_time);
$c2 = date_str($host2->create_time);
$r2 = date_str($host2->rpc_time);
echo "
".tra("Host %1 has overlapping lifetime:", $host2->id)." ($c1 - $r1), ($c2 - $r2)";
}
return false;
}
}
if (!os_compatible($host1, $host2)) {
if ($show_detail) {
echo "
".tra("Host %1 has an incompatible OS:", $host2->id)." ($host1->os_name, $host2->os_name)\n";
}
return false;
}
if (!cpus_compatible($host1, $host2)) {
if ($show_detail) {
echo "
".tra("Host %1 has an incompatible CPU:", $host2->id)." ($host1->p_vendor $host1->p_model, $host2->p_vendor $host2->p_model)\n";
}
return false;
}
return true;
}
// recompute host's average credit by scanning results.
// Could be expensive if lots of results!
//
function host_update_credit($hostid) {
$total = 0;
$avg = 0;
$avg_time = 0;
$results = BoincResult::enum("hostid=$hostid order by received_time");
foreach($results as $result) {
if ($result->granted_credit <= 0) continue;
$total += $result->granted_credit;
update_average(
$result->received_time,
$result->sent_time,
$result->granted_credit,
$avg,
$avg_time
);
//echo "
$avg\n";
}
// do a final decay
//
$now = time();
update_average(now, 0, 0, $avg, $avg_time);
$host = new BoincHost();
$host->id = hostid;
$host->update("total_credit=$total, expavg_credit=$avg, expavg_time=$now");
}
// decay a host's average credit
//
function host_decay_credit($host) {
$avg = $host->expavg_credit;
$avg_time = $host->expavg_time;
$now = time(0);
update_average($now, 0, 0, $avg, $avg_time);
$host->update("expavg_credit=$avg, expavg_time=$now");
}
// if the host hasn't received new credit for ndays,
// decay its average and return true
//
function host_inactive_ndays($host, $ndays) {
$diff = time() - $host->expavg_time;
if ($diff > $ndays*86400) {
host_decay_credit($host);
return true;
}
return false;
}
// invariant: old_host.create_time < new_host.create_time
//
function merge_hosts($old_host, $new_host) {
if ($old_host->id == $new_host->id) {
return tra("same host");
}
if (!hosts_compatible($old_host, $new_host, false)) {
return tra("Can't merge host %1 into %2 - they're incompatible", $old_host->id, $new_host->id);
}
echo "
".tra("Merging host %1 into host %2", $old_host->id, $new_host->id)."\n";
// decay the average credit of both hosts
//
$now = time();
update_average($now, 0, 0, $old_host->expavg_credit, $old_host->expavg_time);
update_average($now, 0, 0, $new_host->expavg_credit, $new_host->expavg_time);
// update the database:
// - add credit from old to new host
// - change results to refer to new host
// - put old host in "zombie" state (userid=0, rpc_seqno=new host ID)
//
$total_credit = $old_host->total_credit + $new_host->total_credit;
$recent_credit = $old_host->expavg_credit + $new_host->expavg_credit;
$result = $new_host->update("total_credit=$total_credit, expavg_credit=$recent_credit, expavg_time=$now");
if (!$result) {
return tra("Couldn't update credit of new computer");
}
$result = BoincResult::update_aux("hostid=$new_host->id where hostid=$old_host->id");
if (!$result) {
return tra("Couldn't update results");
}
$result = $old_host->update("total_credit=0, expavg_credit=0, userid=0, rpc_seqno=$new_host->id");
if (!$result) {
return tra("Couldn't retire old computer");
}
echo "
".tra("Retired old computer %1", $old_host->id)."\n";
return 0;
}
//////////////// helper functions for hosts_user.php ////////////////
function link_url($sort, $rev, $show_all) {
global $userid;
$x = $userid ? "&userid=$userid":"";
return "hosts_user.php?sort=$sort&rev=$rev&show_all=$show_all$x";
}
function link_url_rev($actual_sort, $sort, $rev, $show_all) {
if ($actual_sort == $sort) {
$rev = 1 - $rev;
}
return link_url($sort, $rev, $show_all);
}
function more_or_less($sort, $rev, $show_all) {
echo "";
if ($show_all) {
$url = link_url($sort, $rev, 0);
echo tra("Show:")." ".tra("All computers")." · ".tra("Only computers active in past 30 days")."";
} else {
$url = link_url($sort, $rev, 1);
echo tra("Show:")." ".tra("All computers")." · ".tra("Only computers active in past 30 days");
}
echo "
";
}
function user_host_table_start(
$private, $sort, $rev, $show_all, $any_product_name
) {
start_table('table-striped');
$x = array();
$a = array();
$url = link_url_rev($sort, "id", $rev, $show_all);
$x[] = "".tra("Computer ID")."";
$a[] = '';
if ($private) {
$url = link_url_rev($sort, "name", $rev, $show_all);
$x[] = "".tra("Name")."";
$a[] = null;
$url = link_url_rev($sort, "venue", $rev, $show_all);
if ($any_product_name) {
$x[] = tra("Model");
$a[] = null;
}
$x[] = "".tra("Location")."";
$a[] = null;
} else {
$x[] = tra("Rank");
$a[] = null;
}
if (!NO_STATS) {
$url = link_url_rev($sort, "expavg_credit", $rev, $show_all);
$x[] = "".tra("Avg. credit")."";
$a[] = ALIGN_RIGHT;
$url = link_url_rev($sort, "total_credit", $rev, $show_all);
$x[] = "".tra("Total credit")."";
$a[] = ALIGN_RIGHT;
}
$x[] = tra("BOINC
version");
$a[] = null;
$url = link_url_rev($sort, "cpu", $rev, $show_all);
$x[] = "".tra("CPU")."";
$a[] = null;
$x[] = tra("GPU");
$a[] = null;
$url = link_url_rev($sort, "os", $rev, $show_all);
$x[] = "".tra("Operating System")."";
$a[] = null;
$url = link_url_rev($sort, "rpc_time", $rev, $show_all);
$x[] = "".tra("Last contact")."";
$a[] = null;
row_heading_array($x, $a, "bg-default");
}
function show_user_hosts($userid, $private, $show_all, $sort, $rev) {
$desc = false; // whether the sort order's default is decreasing
switch ($sort) {
case "total_credit": $sort_clause = "total_credit"; $desc = true; break;
case "expavg_credit": $sort_clause = "expavg_credit"; $desc = true; break;
case "name": $sort_clause = "domain_name"; break;
case "id": $sort_clause = "id"; break;
case "cpu": $sort_clause = "p_vendor"; break;
case "gpu": $sort_clause = "serialnum"; break;
case "os": $sort_clause = "os_name"; break;
case "venue": $sort_clause = "venue"; break;
default:
// default value -- sort by RPC time
$sort = "rpc_time";
$sort_clause = "rpc_time";
$desc = true;
}
if ($rev != $desc) {
$sort_clause .= " desc";
}
more_or_less($sort, $rev, $show_all);
$now = time();
$old_hosts=0;
$i = 1;
$hosts = BoincHost::enum("userid=$userid order by $sort_clause");
$any_product_name = false;
foreach ($hosts as $host) {
if ($host->product_name) {
$any_product_name = true;
break;
}
}
user_host_table_start($private, $sort, $rev, $show_all, $any_product_name);
foreach ($hosts as $host) {
$is_old=false;
if (($now - $host->rpc_time) > 30*86400) {
$is_old=true;
$old_hosts++;
}
if (!$show_all && $is_old) continue;
show_host_row($host, $i, $private, false, $any_product_name);
$i++;
}
end_table();
if ($old_hosts>0) {
more_or_less($sort, $rev, $show_all);
}
if ($private) {
echo "
".tra("Merge computers by name")."
";
}
}
// remove user-specific info from a user's hosts
//
function anonymize_hosts($user) {
$hosts = BoincHost::enum("userid=$user->id");
foreach ($hosts as $h) {
$h->update("domain_name='deleted', last_ip_addr=''");
}
}
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
?>