mirror of https://github.com/BOINC/boinc.git
server/web: add support for per-application credit
See http://boinc.berkeley.edu/trac/wiki/PerAppCredit If enabled (by the <credit_by_app> config flag) validators will maintain on a per-(app, user, credit type) basis, and same for teams, in new DB tables credit_user and credit_team. This info is displayed in the web site, on user and team pages, using project-supplied functions to generate the HTML. Note: update_stats doesn't decay the recent-average values for per-app credit; I'll add this if needed.
This commit is contained in:
parent
2128990681
commit
dbd2d03a0d
|
@ -97,6 +97,8 @@ void VDA_CHUNK_HOST::clear() {memset(this, 0, sizeof(*this));}
|
|||
void BADGE::clear() {memset(this, 0, sizeof(*this));}
|
||||
void BADGE_USER::clear() {memset(this, 0, sizeof(*this));}
|
||||
void BADGE_TEAM::clear() {memset(this, 0, sizeof(*this));}
|
||||
void CREDIT_USER::clear() {memset(this, 0, sizeof(*this));}
|
||||
void CREDIT_TEAM::clear() {memset(this, 0, sizeof(*this));}
|
||||
|
||||
DB_PLATFORM::DB_PLATFORM(DB_CONN* dc) :
|
||||
DB_BASE("platform", dc?dc:&boinc_db){}
|
||||
|
@ -170,6 +172,10 @@ DB_BADGE_USER::DB_BADGE_USER(DB_CONN* dc) :
|
|||
DB_BASE("badge_user", dc?dc:&boinc_db){}
|
||||
DB_BADGE_TEAM::DB_BADGE_TEAM(DB_CONN* dc) :
|
||||
DB_BASE("badge_team", dc?dc:&boinc_db){}
|
||||
DB_CREDIT_USER::DB_CREDIT_USER(DB_CONN* dc) :
|
||||
DB_BASE("credit_user", dc?dc:&boinc_db){}
|
||||
DB_CREDIT_TEAM::DB_CREDIT_TEAM(DB_CONN* dc) :
|
||||
DB_BASE("credit_team", dc?dc:&boinc_db){}
|
||||
|
||||
int DB_PLATFORM::get_id() {return id;}
|
||||
int DB_APP::get_id() {return id;}
|
||||
|
@ -2654,4 +2660,66 @@ void DB_BADGE_TEAM::db_parse(MYSQL_ROW &r) {
|
|||
reassign_time = atof(r[i++]);
|
||||
}
|
||||
|
||||
void DB_CREDIT_USER::db_print(char* buf) {
|
||||
sprintf(buf,
|
||||
"userid=%d, "
|
||||
"appid=%d, "
|
||||
"njobs=%d, "
|
||||
"total=%.15e, "
|
||||
"expavg=%.15e, "
|
||||
"expavg_time=%.15e, "
|
||||
"credit_type=%d ",
|
||||
userid,
|
||||
appid,
|
||||
njobs,
|
||||
total,
|
||||
expavg,
|
||||
expavg_time,
|
||||
credit_type
|
||||
);
|
||||
}
|
||||
|
||||
void DB_CREDIT_USER::db_parse(MYSQL_ROW &r) {
|
||||
int i=0;
|
||||
clear();
|
||||
userid = atoi(r[i++]);
|
||||
appid = atoi(r[i++]);
|
||||
njobs = atoi(r[i++]);
|
||||
total = atof(r[i++]);
|
||||
expavg = atof(r[i++]);
|
||||
expavg_time = atof(r[i++]);
|
||||
credit_type = atoi(r[i++]);
|
||||
}
|
||||
|
||||
void DB_CREDIT_TEAM::db_print(char* buf) {
|
||||
sprintf(buf,
|
||||
"teamid=%d, "
|
||||
"appid=%d, "
|
||||
"njobs=%d, "
|
||||
"total=%.15e, "
|
||||
"expavg=%.15e, "
|
||||
"expavg_time=%.15e, "
|
||||
"credit_type=%d ",
|
||||
teamid,
|
||||
appid,
|
||||
njobs,
|
||||
total,
|
||||
expavg,
|
||||
expavg_time,
|
||||
credit_type
|
||||
);
|
||||
}
|
||||
|
||||
void DB_CREDIT_TEAM::db_parse(MYSQL_ROW &r) {
|
||||
int i=0;
|
||||
clear();
|
||||
teamid = atoi(r[i++]);
|
||||
appid = atoi(r[i++]);
|
||||
njobs = atoi(r[i++]);
|
||||
total = atof(r[i++]);
|
||||
expavg = atof(r[i++]);
|
||||
expavg_time = atof(r[i++]);
|
||||
credit_type = atoi(r[i++]);
|
||||
}
|
||||
|
||||
const char *BOINC_RCSID_ac374386c8 = "$Id$";
|
||||
|
|
|
@ -531,4 +531,16 @@ struct DB_BADGE_TEAM : public DB_BASE, public BADGE_TEAM {
|
|||
void db_parse(MYSQL_ROW&);
|
||||
};
|
||||
|
||||
struct DB_CREDIT_USER : public DB_BASE, public CREDIT_USER {
|
||||
DB_CREDIT_USER(DB_CONN* p=0);
|
||||
void db_print(char*);
|
||||
void db_parse(MYSQL_ROW&);
|
||||
};
|
||||
|
||||
struct DB_CREDIT_TEAM : public DB_BASE, public CREDIT_TEAM {
|
||||
DB_CREDIT_TEAM(DB_CONN* p=0);
|
||||
void db_print(char*);
|
||||
void db_parse(MYSQL_ROW&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -799,4 +799,27 @@ struct BADGE_TEAM {
|
|||
void clear();
|
||||
};
|
||||
|
||||
struct CREDIT_USER {
|
||||
int userid;
|
||||
int appid;
|
||||
// need not be an app ID
|
||||
int njobs;
|
||||
double total;
|
||||
double expavg;
|
||||
double expavg_time;
|
||||
int credit_type;
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct CREDIT_TEAM {
|
||||
int teamid;
|
||||
int appid;
|
||||
int njobs;
|
||||
double total;
|
||||
double expavg;
|
||||
double expavg_time;
|
||||
int credit_type;
|
||||
void clear();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -731,3 +731,25 @@ create table badge_team (
|
|||
create_time double not null,
|
||||
reassign_time double not null
|
||||
);
|
||||
|
||||
create table credit_user (
|
||||
userid integer not null,
|
||||
appid integer not null,
|
||||
njobs integer not null,
|
||||
total double not null,
|
||||
expavg double not null,
|
||||
expavg_time double not null,
|
||||
credit_type integer not null,
|
||||
primary key (userid, appid, credit_type)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table credit_team (
|
||||
teamid integer not null,
|
||||
appid integer not null,
|
||||
njobs integer not null,
|
||||
total double not null,
|
||||
expavg double not null,
|
||||
expavg_time double not null,
|
||||
credit_type integer not null,
|
||||
primary key (teamid, appid, credit_type)
|
||||
) engine=InnoDB;
|
||||
|
|
|
@ -540,6 +540,16 @@ $math = array(
|
|||
"",
|
||||
"Study hash functions"
|
||||
),
|
||||
array(
|
||||
"Moo! Wrapper",
|
||||
"http://moowrap.net/",
|
||||
"Private",
|
||||
tra("Cryptography and combinatorics"),
|
||||
"Run applications from distributed.net",
|
||||
"",
|
||||
"",
|
||||
"Run applications from distributed.net"
|
||||
),
|
||||
array(
|
||||
"Enigma@Home",
|
||||
"http://www.enigmaathome.net/",
|
||||
|
|
|
@ -646,5 +646,18 @@ class BoincBadgeTeam {
|
|||
}
|
||||
}
|
||||
|
||||
class BoincCreditUser {
|
||||
static function lookup($clause) {
|
||||
$db = BoincDb::get();
|
||||
return $db->lookup('credit_user', 'BoincCreditUser', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
class BoincCreditTeam {
|
||||
static function lookup($clause) {
|
||||
$db = BoincDb::get();
|
||||
return $db->lookup('credit_team', 'BoincCreditTeam', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -39,10 +39,6 @@
|
|||
// Various functions are defined below for converting between these forms,
|
||||
// and also to/from HTML form elements
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', true);
|
||||
ini_set('display_startup_errors', true);
|
||||
|
||||
include_once("../inc/prefs_util.inc");
|
||||
|
||||
$cpu_prefs = array(
|
||||
|
|
|
@ -42,10 +42,6 @@
|
|||
// In addition there are some fields of the user table
|
||||
// (send_email and show_hosts) that are treated as project preferences
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', true);
|
||||
ini_set('display_startup_errors', true);
|
||||
|
||||
include_once("../inc/prefs_util.inc");
|
||||
include_once("../project/project_specific_prefs.inc");
|
||||
|
||||
|
|
|
@ -104,6 +104,9 @@ function display_team_page($team, $user) {
|
|||
if (!no_computing()) {
|
||||
row2(tra('Total credit'), format_credit_large($team->total_credit));
|
||||
row2(tra('Recent average credit'), format_credit_large($team->expavg_credit));
|
||||
if (function_exists('project_team_credit')) {
|
||||
project_team_credit($team);
|
||||
}
|
||||
show_badges_row(false, $team);
|
||||
|
||||
$x = "";
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
|
||||
// Utility functions for BOINC web pages
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', true);
|
||||
ini_set('display_startup_errors', true);
|
||||
|
||||
require_once("../inc/util_basic.inc");
|
||||
require_once("../project/project.inc");
|
||||
require_once("../inc/countries.inc");
|
||||
|
|
|
@ -941,6 +941,35 @@ function update_6_5_2014() {
|
|||
);
|
||||
}
|
||||
|
||||
function update_8_15_2014() {
|
||||
do_query(
|
||||
"create table credit_user (
|
||||
userid integer not null,
|
||||
appid integer not null,
|
||||
njobs integer not null,
|
||||
total double not null,
|
||||
expavg double not null,
|
||||
expavg_time double not null,
|
||||
credit_type integer not null,
|
||||
primary key (userid, appid, credit_type)
|
||||
) engine=InnoDB
|
||||
"
|
||||
);
|
||||
do_query(
|
||||
"create table credit_team (
|
||||
teamid integer not null,
|
||||
appid integer not null,
|
||||
njobs integer not null,
|
||||
total double not null,
|
||||
expavg double not null,
|
||||
expavg_time double not null,
|
||||
credit_type integer not null,
|
||||
primary key (teamid, appid, credit_type)
|
||||
) engine=InnoDB
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
// Updates are done automatically if you use "upgrade".
|
||||
//
|
||||
// If you need to do updates manually,
|
||||
|
@ -983,6 +1012,7 @@ $db_updates = array (
|
|||
array(27008, "update_4_2_2014"),
|
||||
array(27009, "update_5_3_2014"),
|
||||
array(27010, "update_6_5_2014"),
|
||||
array(27011, "update_8_15_2014"),
|
||||
);
|
||||
|
||||
?>
|
||||
|
|
|
@ -134,8 +134,62 @@ function project_user_page_private($user){
|
|||
// shown in the private account page
|
||||
}
|
||||
|
||||
|
||||
// show project-specific credit on user/team pages
|
||||
//
|
||||
function show_app_credit_user($user, $app_name, $appids) {
|
||||
$t = 0;
|
||||
$a = 0;
|
||||
$n = 0;
|
||||
foreach ($appids as $appid) {
|
||||
$cu = BoincCreditUser::lookup(
|
||||
"userid=$user->id and appid=$appid and credit_type=0"
|
||||
);
|
||||
if ($cu) {
|
||||
$t += $cu->total;
|
||||
$a += $cu->expavg;
|
||||
$n += $cu->njobs;
|
||||
}
|
||||
}
|
||||
row2("$app_name credit",
|
||||
format_credit_large($t)." total, ".
|
||||
format_credit($a)." average".
|
||||
" ($n tasks)"
|
||||
);
|
||||
}
|
||||
function show_app_credit_team($team, $app_name, $appids) {
|
||||
$t = 0;
|
||||
$a = 0;
|
||||
$n = 0;
|
||||
foreach ($appids as $appid) {
|
||||
$ct = BoincCreditTeam::lookup(
|
||||
"teamid=$team->id and appid=$appid and credit_type=0"
|
||||
);
|
||||
if ($ct) {
|
||||
$t += $ct->total;
|
||||
$a += $ct->expavg;
|
||||
$n += $ct->njobs;
|
||||
}
|
||||
}
|
||||
row2("$app_name credit",
|
||||
format_credit_large($t)." total, ".
|
||||
format_credit($a)." average".
|
||||
" ($n tasks)"
|
||||
);
|
||||
}
|
||||
|
||||
function project_user_credit($user){
|
||||
// shown in the the private account page, credit area
|
||||
if (0) {
|
||||
show_app_credit_user($user, "Remote Test", array(16));
|
||||
show_app_credit_user($user, "Uppercase", array(1, 25));
|
||||
}
|
||||
}
|
||||
|
||||
function project_team_credit($team) {
|
||||
if (0) {
|
||||
show_app_credit_team($team, "Remote Test", array(16));
|
||||
show_app_credit_team($team, "Uppercase", array(1, 25));
|
||||
}
|
||||
}
|
||||
|
||||
function project_forum_post_rules() {
|
||||
|
|
|
@ -213,6 +213,13 @@ enum BATTERY_STATE {
|
|||
// input/output files can be deleted,
|
||||
// result and workunit records can be purged.
|
||||
|
||||
// credit types
|
||||
//
|
||||
#define CREDIT_TYPE_FLOPS 0
|
||||
#define CREDIT_TYPE_STORAGE 1
|
||||
#define CREDIT_TYPE_NETWORK 2
|
||||
#define CREDIT_TYPE_PROJECT 3
|
||||
|
||||
struct TIME_STATS {
|
||||
double now;
|
||||
// the client's current time of day
|
||||
|
|
|
@ -119,3 +119,7 @@ BATCH_STATE_IN_PROGRESS = 1
|
|||
BATCH_STATE_COMPLETE = 2
|
||||
BATCH_STATE_ABORTED = 3
|
||||
BATCH_STATE_RETIRED = 4
|
||||
CREDIT_TYPE_FLOPS = 0
|
||||
CREDIT_TYPE_STORAGE = 1
|
||||
CREDIT_TYPE_NETWORK = 2
|
||||
CREDIT_TYPE_PROJECT = 3
|
||||
|
|
|
@ -124,6 +124,66 @@ int grant_credit(DB_HOST &host, double start_time, double credit) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int grant_credit_by_app(RESULT& result, double credit) {
|
||||
DB_CREDIT_USER cu;
|
||||
char clause1[1024], clause2[1024];
|
||||
double now = dtime();
|
||||
|
||||
sprintf(clause1, "where userid=%d and appid=%d", result.userid, result.appid);
|
||||
int retval = cu.lookup(clause1);
|
||||
if (retval) {
|
||||
cu.clear();
|
||||
cu.userid = result.userid;
|
||||
cu.appid = result.appid;
|
||||
retval = cu.insert();
|
||||
if (retval) return retval;
|
||||
}
|
||||
update_average(
|
||||
now,
|
||||
result.sent_time,
|
||||
credit, CREDIT_HALF_LIFE,
|
||||
cu.expavg, cu.expavg_time
|
||||
);
|
||||
sprintf(clause1,
|
||||
"total=total+%.15e, expavg=%.15e, expavg_time=%.15e, njobs=njobs+1",
|
||||
credit, cu.expavg, cu.expavg_time
|
||||
);
|
||||
sprintf(clause2,
|
||||
"userid=%d and appid=%d", result.userid, result.appid
|
||||
);
|
||||
retval = cu.update_fields_noid(clause1, clause2);
|
||||
if (retval) return retval;
|
||||
|
||||
// team. keep track of credit for zero (no team) also
|
||||
//
|
||||
DB_CREDIT_TEAM ct;
|
||||
sprintf(clause1, "where teamid=%d and appid=%d", result.teamid, result.appid);
|
||||
retval = ct.lookup(clause1);
|
||||
if (retval) {
|
||||
ct.clear();
|
||||
ct.teamid = result.teamid;
|
||||
ct.appid = result.appid;
|
||||
retval = ct.insert();
|
||||
if (retval) return retval;
|
||||
}
|
||||
update_average(
|
||||
now,
|
||||
result.sent_time,
|
||||
credit, CREDIT_HALF_LIFE,
|
||||
ct.expavg, ct.expavg_time
|
||||
);
|
||||
sprintf(clause1,
|
||||
"total=total+%.15e, expavg=%.15e, expavg_time=%.15e, njobs=njobs+1",
|
||||
credit, ct.expavg, ct.expavg_time
|
||||
);
|
||||
sprintf(clause2,
|
||||
"teamid=%d and appid=%d", result.teamid, result.appid
|
||||
);
|
||||
retval = ct.update_fields_noid(clause1, clause2);
|
||||
if (retval) return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////// V2 CREDIT STUFF STARTS HERE ///////////////////
|
||||
|
||||
// levels of confidence in a credit value
|
||||
|
|
|
@ -63,3 +63,5 @@ extern int hav_lookup(DB_HOST_APP_VERSION& hav, int hostid, int avid);
|
|||
extern int write_modified_app_versions(
|
||||
std::vector<DB_APP_VERSION_VAL>& app_versions
|
||||
);
|
||||
|
||||
extern int grant_credit_by_app(RESULT& result, double credit);
|
||||
|
|
|
@ -296,6 +296,7 @@ int SCHED_CONFIG::parse(FILE* f) {
|
|||
if (xp.parse_bool("prefer_primary_platform", prefer_primary_platform)) continue;
|
||||
if (xp.parse_double("version_select_random_factor", version_select_random_factor)) continue;
|
||||
if (xp.parse_double("maintenance_delay", maintenance_delay)) continue;
|
||||
if (xp.parse_bool("credit_by_app", credit_by_app)) continue;
|
||||
|
||||
//////////// SCHEDULER LOG FLAGS /////////
|
||||
|
||||
|
|
|
@ -177,6 +177,8 @@ struct SCHED_CONFIG {
|
|||
bool estimate_flops_from_hav_pfc;
|
||||
// Use host_app_version peak flop count rather than elapsed time
|
||||
// to calculate projected_flops when choosing version.
|
||||
bool credit_by_app;
|
||||
// store per-app credit info in credit_user and credit_team
|
||||
|
||||
// time intervals
|
||||
double maintenance_delay;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
// update_stats:
|
||||
// Update average credit for idle users, hosts and teams.
|
||||
// These fields are updates as new credit is granted;
|
||||
// These fields are updated as new credit is granted;
|
||||
// the purpose of this program is to decay credit of entities
|
||||
// that are inactive for long periods.
|
||||
// Run it about once a day.
|
||||
|
|
|
@ -308,6 +308,9 @@ int handle_wu(
|
|||
if (!no_credit) {
|
||||
result.granted_credit = canonical_result.granted_credit;
|
||||
grant_credit(host, result.sent_time, result.granted_credit);
|
||||
if (config.credit_by_app) {
|
||||
grant_credit_by_app(result, result.granted_credit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VALIDATE_STATE_INVALID:
|
||||
|
@ -534,6 +537,9 @@ int handle_wu(
|
|||
result.id, result.name, result.granted_credit,
|
||||
result.hostid
|
||||
);
|
||||
if (config.credit_by_app) {
|
||||
grant_credit_by_app(result, credit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VALIDATE_STATE_INVALID:
|
||||
|
|
Loading…
Reference in New Issue