1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
|
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2022 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
#ifndef BOINC_RESULT_H
#define BOINC_RESULT_H
#include "project.h"
struct RESULT {
char name[256];
char wu_name[256];
double received_time; // when we got this from server
double report_deadline;
int version_num; // identifies the app used
char plan_class[64];
char platform[256];
APP_VERSION* avp;
std::vector<FILE_REF> output_files;
bool ready_to_report;
// we're ready to report this result to the server;
// either computation is done and all the files have been uploaded
// or there was an error
double completed_time;
// time when ready_to_report was set
bool got_server_ack;
// we've received the ack for this result from the server
double final_cpu_time;
double final_elapsed_time;
double final_peak_working_set_size;
double final_peak_swap_size;
double final_peak_disk_usage;
double final_bytes_sent;
double final_bytes_received;
#ifdef SIM
double peak_flop_count;
double sim_flops_left;
#endif
// the following are nonzero if reported by app
double fpops_per_cpu_sec;
double fpops_cumulative;
double intops_per_cpu_sec;
double intops_cumulative;
int _state;
// state of this result: see lib/result_state.h
inline int state() { return _state; }
inline void set_ready_to_report() {
ready_to_report = true;
}
void set_state(int, const char*);
int exit_status;
// return value from the application
std::string stderr_out;
// the concatenation of:
//
// - if report_result_error() is called for this result:
// <message>x</message>
// <exit_status>x</exit_status>
// <signal>x</signal>
// - if called in FILES_DOWNLOADED state:
// <couldnt_start>x</couldnt_start>
// - if called in NEW state:
// <download_error>x</download_error> for each failed download
// - if called in COMPUTE_DONE state:
// <upload_error>x</upload_error> for each failed upload
//
// - <stderr_txt>X</stderr_txt>, where X is the app's stderr output
bool suspended_via_gui;
bool coproc_missing;
// a coproc needed by this job is missing
// (e.g. because user removed their GPU board).
bool report_immediately;
bool not_started; // temp for CPU sched
std::string name_md5; // see sort_results();
int index; // index in results vector
APP* app;
WORKUNIT* wup;
PROJECT* project;
RESULT(){
clear();
}
~RESULT(){}
void clear();
int parse_server(XML_PARSER&);
int parse_state(XML_PARSER&);
int parse_name(XML_PARSER&, const char* end_tag);
int write(MIOFILE&, bool to_server);
int write_gui(MIOFILE&, bool check_resources = false);
bool is_upload_done(); // files uploaded?
void clear_uploaded_flags();
FILE_REF* lookup_file(FILE_INFO*);
FILE_INFO* lookup_file_logical(const char*);
void abort_inactive(int);
// abort the result if it hasn't started computing yet
// Called only for results with no active task
// (otherwise you need to abort the active task)
void append_log_record();
// stuff related to CPU scheduling
bool is_not_started();
double estimated_runtime();
double estimated_runtime_uncorrected();
double estimated_runtime_remaining();
inline double estimated_flops_remaining() {
#ifdef SIM
return sim_flops_left;
#else
return estimated_runtime_remaining()*avp->flops;
#endif
}
inline bool computing_done() {
if (state() >= RESULT_COMPUTE_ERROR) return true;
if (ready_to_report) return true;
return false;
}
bool runnable();
// downloaded, not finished, not suspended, project not suspended
bool nearly_runnable();
// downloading or downloaded,
// not finished, suspended, project not suspended
bool downloading();
// downloading, not downloaded, not suspended, project not suspended
bool some_download_stalled();
// some input or app file is downloading, and backed off
// i.e. it may be a long time before we can run this result
inline bool uses_coprocs() {
return (avp->gpu_usage.rsc_type != 0);
}
inline bool uses_gpu() {
int rt = avp->gpu_usage.rsc_type;
if (!rt) return false;
if (coprocs.coprocs[rt].non_gpu) return false;
return true;
}
inline int resource_type() {
return avp->gpu_usage.rsc_type;
}
inline bool non_cpu_intensive() {
if (project->non_cpu_intensive) return true;
return app->non_cpu_intensive;
}
inline bool sporadic() {
return app->sporadic;
}
inline bool always_run() {
return non_cpu_intensive() || sporadic();
}
inline bool dont_throttle() {
if (non_cpu_intensive()) return true;
if (avp->dont_throttle) return true;
return false;
}
// make a string describing resource usage
inline void rsc_string(char* buf, int len) {
if (avp->gpu_usage.rsc_type) {
snprintf(buf, len,
"%.2f CPU + %.2f %s",
avp->avg_ncpus, avp->gpu_usage.usage,
rsc_name_long(avp->gpu_usage.rsc_type)
);
} else {
snprintf(buf, len, "%.2f CPU", avp->avg_ncpus);
}
}
// temporaries used in CLIENT_STATE::rr_simulation():
double rrsim_flops_left;
double rrsim_finish_delay;
double rrsim_flops;
bool rrsim_done;
bool already_selected;
// used to keep cpu scheduler from scheduling a result twice
// transient; used only within schedule_cpus()
// also used in round-robin simulation
double computation_deadline();
// report deadline - prefs.work_buf_min - time slice
bool rr_sim_misses_deadline;
// temporaries used in enforce_schedule():
bool unfinished_time_slice;
int seqno;
bool edf_scheduled;
// temporary used to tell GUI that this result is deadline-scheduled
int coproc_indices[MAX_COPROCS_PER_JOB];
// keep track of coprocessor reservations
char resources[256];
// textual description of resources used
double schedule_backoff;
// don't try to schedule until this time
// (because the app called boinc_temporary_exit())
char schedule_backoff_reason[256];
};
#define CONCURRENT_LIMIT_APP 1
#define CONCURRENT_LIMIT_PROJECT 2
// are we at or beyond a max_concurrent limit for this job?
//
inline int max_concurrent_exceeded(RESULT* rp) {
APP* app = rp->app;
if (app->max_concurrent) {
if (app->app_n_concurrent >= app->max_concurrent) {
return CONCURRENT_LIMIT_APP;
}
}
PROJECT* p = rp->project;
if (p->app_configs.project_max_concurrent) {
if (p->proj_n_concurrent >= p->app_configs.project_max_concurrent) {
return CONCURRENT_LIMIT_PROJECT;
}
}
return 0;
}
// we're about to run this job.
// increment counters for enforcing max_concurrent prefs
// Used in RR simulation (RR_SIM::activate())
// and in job scheduling (enforce_run_list())
//
inline void max_concurrent_inc(RESULT* rp) {
rp->app->app_n_concurrent++;
rp->project->proj_n_concurrent++;
}
// a completed result, for which the RESULT record no longer exists.
// We keep an in-memory log of these.
// Keep this consistent with lib/gui_rpc_client.h
//
struct OLD_RESULT {
char project_url[256];
char result_name[256];
char app_name[256];
int exit_status;
double elapsed_time;
double cpu_time;
double completed_time;
double create_time; // when this record was created
};
extern std::deque<OLD_RESULT> old_results;
void add_old_result(RESULT&);
extern void print_old_results(MIOFILE&);
#endif
|