1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2012 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
9 //
10 // BOINC is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC. If not, see <http://www.gnu.org/licenses/>.
17 #ifdef _WIN32
18 #include <boinc_win.h>
19 #endif
20
21 #ifdef _MSC_VER
22 #define snprintf _snprintf
23 #endif
24
25 #include <string.h>
26
27 #include "str_replace.h"
28 #include "url.h"
29
30 #include "client_msgs.h"
31 #include "client_state.h"
32 #include "log_flags.h"
33 #include "result.h"
34 #include "sandbox.h"
35
36 #include "project.h"
37
PROJECT()38 PROJECT::PROJECT() {
39 init();
40 }
41
init()42 void PROJECT::init() {
43 safe_strcpy(master_url, "");
44 safe_strcpy(authenticator, "");
45 safe_strcpy(_project_dir, "");
46 safe_strcpy(_project_dir_absolute, "");
47 project_specific_prefs = "";
48 gui_urls = "";
49 resource_share = 100;
50 desired_disk_usage = 0;
51 for (int i=0; i<MAX_RSC; i++) {
52 no_rsc_pref[i] = false;
53 no_rsc_config[i] = false;
54 no_rsc_apps[i] = false;
55 no_rsc_ams[i] = false;
56 }
57 safe_strcpy(host_venue, "");
58 using_venue_specific_prefs = false;
59 scheduler_urls.clear();
60 safe_strcpy(project_name, "");
61 safe_strcpy(symstore, "");
62 safe_strcpy(user_name, "");
63 safe_strcpy(team_name, "");
64 safe_strcpy(email_hash, "");
65 safe_strcpy(cross_project_id, "");
66 safe_strcpy(external_cpid, "");
67 cpid_time = 0;
68 user_total_credit = 0;
69 user_expavg_credit = 0;
70 user_create_time = 0;
71 ams_resource_share = -1;
72 rpc_seqno = 0;
73 userid = 0;
74 teamid = 0;
75 hostid = 0;
76 host_total_credit = 0;
77 host_expavg_credit = 0;
78 host_create_time = 0;
79 nrpc_failures = 0;
80 master_fetch_failures = 0;
81 min_rpc_time = 0;
82 possibly_backed_off = true;
83 master_url_fetch_pending = false;
84 sched_rpc_pending = 0;
85 next_rpc_time = 0;
86 last_rpc_time = 0;
87 trickle_up_pending = false;
88 anonymous_platform = false;
89 non_cpu_intensive = false;
90 verify_files_on_app_start = false;
91 report_results_immediately = false;
92 pwf.reset(this);
93 send_time_stats_log = 0;
94 send_job_log = 0;
95 send_full_workload = false;
96 dont_use_dcf = false;
97 suspended_via_gui = false;
98 dont_request_more_work = false;
99 detach_when_done = false;
100 attached_via_acct_mgr = false;
101 ended = false;
102 safe_strcpy(code_sign_key, "");
103 user_files.clear();
104 project_files.clear();
105 next_runnable_result = NULL;
106 duration_correction_factor = 1;
107 project_files_downloaded_time = 0;
108 use_symlinks = false;
109 possibly_backed_off = false;
110 nuploading_results = 0;
111 too_many_uploading_results = false;
112 njobs_success = 0;
113 njobs_error = 0;
114 elapsed_time = 0;
115 cpu_ec = 0;
116 cpu_time = 0;
117 gpu_ec = 0;
118 gpu_time = 0;
119 app_configs.clear();
120
121 #ifdef SIM
122 idle_time = 0;
123 idle_time_sumsq = 0;
124 completed_task_count = 0;
125 completions_ratio_mean = 0.0;
126 completions_ratio_s = 0.0;
127 completions_ratio_stdev = 0.1; // for the first couple of completions - guess.
128 completions_required_stdevs = 3.0;
129 result_index = 0;
130 ignore = false;
131 #endif
132 }
133
handle_no_rsc_ams(PROJECT * p,const char * name)134 static void handle_no_rsc_ams(PROJECT* p, const char* name) {
135 int i = rsc_index(name);
136 if (i < 0) return;
137 p->no_rsc_ams[i] = true;
138 }
139
handle_no_rsc_pref(PROJECT * p,const char * name)140 static void handle_no_rsc_pref(PROJECT* p, const char* name) {
141 int i = rsc_index(name);
142 if (i<0) return;
143 p->no_rsc_pref[i] = true;
144 }
145
handle_no_rsc_apps(PROJECT * p,const char * name)146 static void handle_no_rsc_apps(PROJECT* p, const char* name) {
147 int i = rsc_index(name);
148 if (i < 0) return;
149 p->no_rsc_apps[i] = true;
150 }
151
parse_rsc_param(XML_PARSER & xp,const char * end_tag,int & rsc_type,double & value)152 static bool parse_rsc_param(XML_PARSER& xp, const char* end_tag, int& rsc_type, double& value) {
153 char name[256];
154 bool val_found = false;
155
156 rsc_type = -1;
157 while (!xp.get_tag()) {
158 if (xp.match_tag(end_tag)) {
159 return (rsc_type > 0 && val_found);
160 }
161 if (xp.parse_str("name", name, sizeof(name))) {
162 rsc_type = rsc_index(name);
163 continue;
164 }
165 if (xp.parse_double("rsc_type", value)) {
166 val_found = true;
167 }
168 }
169 return false;
170 }
171 // parse project fields from client_state.xml
172 //
parse_state(XML_PARSER & xp)173 int PROJECT::parse_state(XML_PARSER& xp) {
174 char buf[256];
175 string sched_url, stemp;
176 string str1, str2;
177 int retval, rt;
178 double x;
179 bool btemp;
180
181 init();
182 while (!xp.get_tag()) {
183 if (xp.match_tag("/project")) {
184 if (cpid_time == 0) {
185 cpid_time = user_create_time;
186 }
187 if (dont_use_dcf) {
188 duration_correction_factor = 1;
189 }
190 return 0;
191 }
192 if (xp.parse_string("scheduler_url", sched_url)) {
193 scheduler_urls.push_back(sched_url);
194 continue;
195 }
196 if (xp.parse_str("master_url", master_url, sizeof(master_url))) continue;
197 if (xp.parse_str("project_name", project_name, sizeof(project_name))) continue;
198 if (xp.parse_str("symstore", symstore, sizeof(symstore))) continue;
199 if (xp.parse_str("user_name", user_name, sizeof(user_name))) continue;
200 if (xp.parse_str("team_name", team_name, sizeof(team_name))) continue;
201 if (xp.parse_str("host_venue", host_venue, sizeof(host_venue))) continue;
202 if (xp.parse_str("email_hash", email_hash, sizeof(email_hash))) continue;
203 if (xp.parse_str("cross_project_id", cross_project_id, sizeof(cross_project_id))) continue;
204 if (xp.parse_str("external_cpid", external_cpid, sizeof(external_cpid))) continue;
205 if (xp.parse_double("cpid_time", cpid_time)) continue;
206 if (xp.parse_double("user_total_credit", user_total_credit)) continue;
207 if (xp.parse_double("user_expavg_credit", user_expavg_credit)) continue;
208 if (xp.parse_double("user_create_time", user_create_time)) continue;
209 if (xp.parse_int("rpc_seqno", rpc_seqno)) continue;
210 if (xp.parse_int("userid", userid)) continue;
211 if (xp.parse_int("teamid", teamid)) continue;
212 if (xp.parse_int("hostid", hostid)) continue;
213 if (xp.parse_double("host_total_credit", host_total_credit)) continue;
214 if (xp.parse_double("host_expavg_credit", host_expavg_credit)) continue;
215 if (xp.parse_double("host_create_time", host_create_time)) continue;
216 if (xp.match_tag("code_sign_key")) {
217 retval = copy_element_contents(
218 xp.f->f,
219 "</code_sign_key>",
220 code_sign_key,
221 sizeof(code_sign_key)
222 );
223 if (retval) return retval;
224 strip_whitespace(code_sign_key);
225 continue;
226 }
227 if (xp.parse_int("nrpc_failures", nrpc_failures)) continue;
228 if (xp.parse_int("master_fetch_failures", master_fetch_failures)) continue;
229 if (xp.parse_double("min_rpc_time", x)) continue;
230 if (xp.parse_bool("master_url_fetch_pending", master_url_fetch_pending)) continue;
231 if (xp.parse_int("sched_rpc_pending", sched_rpc_pending)) continue;
232 if (xp.parse_double("next_rpc_time", next_rpc_time)) continue;
233 if (xp.parse_bool("trickle_up_pending", trickle_up_pending)) continue;
234 if (xp.parse_int("send_time_stats_log", send_time_stats_log)) continue;
235 if (xp.parse_int("send_job_log", send_job_log)) continue;
236 if (xp.parse_bool("send_full_workload", send_full_workload)) continue;
237 if (xp.parse_bool("dont_use_dcf", dont_use_dcf)) continue;
238 if (xp.parse_bool("non_cpu_intensive", non_cpu_intensive)) continue;
239 if (xp.parse_bool("verify_files_on_app_start", verify_files_on_app_start)) continue;
240 if (xp.parse_bool("suspended_via_gui", suspended_via_gui)) continue;
241 if (xp.parse_bool("dont_request_more_work", dont_request_more_work)) continue;
242 if (xp.parse_bool("detach_when_done", detach_when_done)) continue;
243 if (xp.parse_bool("ended", ended)) continue;
244 if (xp.parse_double("rec", pwf.rec)) continue;
245 if (xp.parse_double("rec_time", pwf.rec_time)) continue;
246 if (xp.parse_double("cpu_backoff_interval", rsc_pwf[0].backoff_interval)) continue;
247 if (xp.parse_double("cpu_backoff_time", rsc_pwf[0].backoff_time)) {
248 if (rsc_pwf[0].backoff_time > gstate.now + 28*SECONDS_PER_DAY) {
249 rsc_pwf[0].backoff_time = gstate.now + 28*SECONDS_PER_DAY;
250 }
251 continue;
252 }
253 if (xp.match_tag("rsc_backoff_interval")) {
254 if (parse_rsc_param(xp, "/rsc_backoff_interval", rt, x)) {
255 rsc_pwf[rt].backoff_interval = x;
256 }
257 continue;
258 }
259 if (xp.match_tag("rsc_backoff_time")) {
260 if (parse_rsc_param(xp, "/rsc_backoff_time", rt, x)) {
261 rsc_pwf[rt].backoff_time = x;
262 }
263 continue;
264 }
265 if (xp.parse_double("resource_share", resource_share)) continue;
266 // not authoritative
267 if (xp.parse_double("duration_correction_factor", duration_correction_factor)) continue;
268 if (xp.parse_bool("attached_via_acct_mgr", attached_via_acct_mgr)) continue;
269 if (xp.parse_bool("no_cpu_apps", btemp)) {
270 if (btemp) handle_no_rsc_apps(this, "CPU");
271 continue;
272 }
273
274 // deprecated
275 if (xp.parse_bool("no_cuda_apps", btemp)) {
276 if (btemp) handle_no_rsc_apps(this, GPU_TYPE_NVIDIA);
277 continue;
278 }
279 if (xp.parse_bool("no_ati_apps", btemp)) {
280 if (btemp) handle_no_rsc_apps(this, GPU_TYPE_ATI);
281 continue;
282 }
283
284 if (xp.parse_str("no_rsc_apps", buf, sizeof(buf))) {
285 handle_no_rsc_apps(this, buf);
286 continue;
287 }
288 if (xp.parse_bool("no_cpu_ams", btemp)) {
289 if (btemp) handle_no_rsc_ams(this, "CPU");
290 continue;
291 }
292 if (xp.parse_bool("no_cuda_ams", btemp)) {
293 if (btemp) handle_no_rsc_ams(this, GPU_TYPE_NVIDIA);
294 continue;
295 }
296 if (xp.parse_bool("no_ati_ams", btemp)) {
297 if (btemp) handle_no_rsc_ams(this, GPU_TYPE_ATI);
298 continue;
299 }
300 if (xp.parse_bool("no_intel_gpu_ams", btemp)) {
301 if (btemp) handle_no_rsc_ams(this, GPU_TYPE_INTEL);
302 continue;
303 }
304 if (xp.parse_str("no_rsc_ams", buf, sizeof(buf))) {
305 handle_no_rsc_ams(this, buf);
306 continue;
307 }
308 if (xp.parse_str("no_rsc_pref", buf, sizeof(buf))) {
309 handle_no_rsc_pref(this, buf);
310 continue;
311 }
312
313 // backwards compat - old state files had ams_resource_share = 0
314 if (xp.parse_double("ams_resource_share_new", ams_resource_share)) continue;
315 if (xp.parse_double("ams_resource_share", x)) {
316 if (x > 0) ams_resource_share = x;
317 continue;
318 }
319 if (xp.parse_bool("scheduler_rpc_in_progress", btemp)) continue;
320 if (xp.parse_bool("use_symlinks", use_symlinks)) continue;
321 if (xp.parse_bool("anonymous_platform", btemp)) continue;
322 if (xp.parse_string("trickle_up_url", stemp)) {
323 trickle_up_ops.push_back(new TRICKLE_UP_OP(stemp));
324 continue;
325 }
326 if (xp.parse_double("desired_disk_usage", desired_disk_usage)) continue;
327 if (xp.parse_int("njobs_success", njobs_success)) continue;
328 if (xp.parse_int("njobs_error", njobs_error)) continue;
329 if (xp.parse_double("elapsed_time", elapsed_time)) continue;
330 if (xp.parse_double("last_rpc_time", last_rpc_time)) continue;
331 if (xp.parse_double("cpu_ec", cpu_ec)) continue;
332 if (xp.parse_double("cpu_time", cpu_time)) continue;
333 if (xp.parse_double("gpu_ec", gpu_ec)) continue;
334 if (xp.parse_double("gpu_time", gpu_time)) continue;
335 if (xp.parse_double("disk_usage", disk_usage)) continue;
336 if (xp.parse_double("disk_share", disk_share)) continue;
337 #ifdef SIM
338 if (xp.match_tag("available")) {
339 available.parse(xp, "/available");
340 continue;
341 }
342 #endif
343 if (log_flags.unparsed_xml) {
344 msg_printf(0, MSG_INFO,
345 "[unparsed_xml] PROJECT::parse_state(): unrecognized: %s",
346 xp.parsed_tag
347 );
348 }
349 xp.skip_unexpected();
350 }
351 return ERR_XML_PARSE;
352 }
353
354 // Write project information to client state file or GUI RPC reply
355 //
write_state(MIOFILE & out,bool gui_rpc)356 int PROJECT::write_state(MIOFILE& out, bool gui_rpc) {
357 unsigned int i;
358 char un[2048], tn[2048];
359
360 out.printf(
361 "<project>\n"
362 );
363
364 xml_escape(user_name, un, sizeof(un));
365 xml_escape(team_name, tn, sizeof(tn));
366 out.printf(
367 " <master_url>%s</master_url>\n"
368 " <project_name>%s</project_name>\n"
369 " <symstore>%s</symstore>\n"
370 " <user_name>%s</user_name>\n"
371 " <team_name>%s</team_name>\n"
372 " <host_venue>%s</host_venue>\n"
373 " <email_hash>%s</email_hash>\n"
374 " <cross_project_id>%s</cross_project_id>\n"
375 " <external_cpid>%s</external_cpid>\n"
376 " <cpid_time>%f</cpid_time>\n"
377 " <user_total_credit>%f</user_total_credit>\n"
378 " <user_expavg_credit>%f</user_expavg_credit>\n"
379 " <user_create_time>%f</user_create_time>\n"
380 " <rpc_seqno>%d</rpc_seqno>\n"
381 " <userid>%d</userid>\n"
382 " <teamid>%d</teamid>\n"
383 " <hostid>%d</hostid>\n"
384 " <host_total_credit>%f</host_total_credit>\n"
385 " <host_expavg_credit>%f</host_expavg_credit>\n"
386 " <host_create_time>%f</host_create_time>\n"
387 " <nrpc_failures>%d</nrpc_failures>\n"
388 " <master_fetch_failures>%d</master_fetch_failures>\n"
389 " <min_rpc_time>%f</min_rpc_time>\n"
390 " <next_rpc_time>%f</next_rpc_time>\n"
391 " <rec>%f</rec>\n"
392 " <rec_time>%f</rec_time>\n"
393 " <resource_share>%f</resource_share>\n"
394 " <desired_disk_usage>%f</desired_disk_usage>\n"
395 " <duration_correction_factor>%f</duration_correction_factor>\n"
396 " <sched_rpc_pending>%d</sched_rpc_pending>\n"
397 " <send_time_stats_log>%d</send_time_stats_log>\n"
398 " <send_job_log>%d</send_job_log>\n"
399 " <njobs_success>%d</njobs_success>\n"
400 " <njobs_error>%d</njobs_error>\n"
401 " <elapsed_time>%f</elapsed_time>\n"
402 " <last_rpc_time>%f</last_rpc_time>\n"
403 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
404 master_url,
405 project_name,
406 symstore,
407 un,
408 tn,
409 host_venue,
410 email_hash,
411 cross_project_id,
412 external_cpid,
413 cpid_time,
414 user_total_credit,
415 user_expavg_credit,
416 user_create_time,
417 rpc_seqno,
418 userid,
419 teamid,
420 hostid,
421 host_total_credit,
422 host_expavg_credit,
423 host_create_time,
424 nrpc_failures,
425 master_fetch_failures,
426 min_rpc_time,
427 next_rpc_time,
428 pwf.rec,
429 pwf.rec_time,
430 resource_share,
431 desired_disk_usage,
432 duration_correction_factor,
433 sched_rpc_pending,
434 send_time_stats_log,
435 send_job_log,
436 njobs_success,
437 njobs_error,
438 elapsed_time,
439 last_rpc_time,
440 anonymous_platform?" <anonymous_platform/>\n":"",
441 master_url_fetch_pending?" <master_url_fetch_pending/>\n":"",
442 trickle_up_pending?" <trickle_up_pending/>\n":"",
443 send_full_workload?" <send_full_workload/>\n":"",
444 dont_use_dcf?" <dont_use_dcf/>\n":"",
445 non_cpu_intensive?" <non_cpu_intensive/>\n":"",
446 verify_files_on_app_start?" <verify_files_on_app_start/>\n":"",
447 suspended_via_gui?" <suspended_via_gui/>\n":"",
448 dont_request_more_work?" <dont_request_more_work/>\n":"",
449 detach_when_done?" <detach_when_done/>\n":"",
450 ended?" <ended/>\n":"",
451 attached_via_acct_mgr?" <attached_via_acct_mgr/>\n":"",
452 (this == gstate.scheduler_op->cur_proj)?" <scheduler_rpc_in_progress/>\n":"",
453 use_symlinks?" <use_symlinks/>\n":""
454 );
455 for (int j=0; j<coprocs.n_rsc; j++) {
456 out.printf(
457 " <rsc_backoff_time>\n"
458 " <name>%s</name>\n"
459 " <value>%f</value>\n"
460 " </rsc_backoff_time>\n"
461 " <rsc_backoff_interval>\n"
462 " <name>%s</name>\n"
463 " <value>%f</value>\n"
464 " </rsc_backoff_interval>\n",
465 rsc_name(j), rsc_pwf[j].backoff_time,
466 rsc_name(j), rsc_pwf[j].backoff_interval
467 );
468 if (no_rsc_ams[j]) {
469 out.printf(" <no_rsc_ams>%s</no_rsc_ams>\n", rsc_name(j));
470 }
471 if (no_rsc_apps[j]) {
472 out.printf(" <no_rsc_apps>%s</no_rsc_apps>\n", rsc_name(j));
473 }
474 if (no_rsc_pref[j]) {
475 out.printf(" <no_rsc_pref>%s</no_rsc_pref>\n", rsc_name(j));
476 }
477 if (j>0 && gui_rpc && (rsc_pwf[j].ncoprocs_excluded == rsc_work_fetch[j].ninstances)) {
478 out.printf(" <no_rsc_config>%s</no_rsc_config>\n", rsc_name(j));
479 }
480 }
481 if (ams_resource_share >= 0) {
482 out.printf(" <ams_resource_share_new>%f</ams_resource_share_new>\n",
483 ams_resource_share
484 );
485 }
486 if (gui_rpc) {
487 out.printf(
488 "%s"
489 " <sched_priority>%f</sched_priority>\n"
490 " <project_files_downloaded_time>%f</project_files_downloaded_time>\n",
491 gui_urls.c_str(),
492 sched_priority,
493 project_files_downloaded_time
494 );
495 if (download_backoff.next_xfer_time > gstate.now) {
496 out.printf(
497 " <download_backoff>%f</download_backoff>\n",
498 download_backoff.next_xfer_time - gstate.now
499 );
500 }
501 if (upload_backoff.next_xfer_time > gstate.now) {
502 out.printf(
503 " <upload_backoff>%f</upload_backoff>\n",
504 upload_backoff.next_xfer_time - gstate.now
505 );
506 }
507 if (strlen(host_venue)) {
508 out.printf(" <venue>%s</venue>\n", host_venue);
509 }
510 out.printf(" <project_dir>%s</project_dir>\n", project_dir_absolute());
511 } else {
512 for (i=0; i<scheduler_urls.size(); i++) {
513 out.printf(
514 " <scheduler_url>%s</scheduler_url>\n",
515 scheduler_urls[i].c_str()
516 );
517 }
518 if (strlen(code_sign_key)) {
519 out.printf(
520 " <code_sign_key>\n%s\n</code_sign_key>\n", code_sign_key
521 );
522 }
523 for (i=0; i<trickle_up_ops.size(); i++) {
524 TRICKLE_UP_OP* t = trickle_up_ops[i];
525 out.printf(
526 " <trickle_up_url>%s</trickle_up_url>\n",
527 t->url.c_str()
528 );
529 }
530 out.printf(
531 " <cpu_ec>%f</cpu_ec>\n"
532 " <cpu_time>%f</cpu_time>\n"
533 " <gpu_ec>%f</gpu_ec>\n"
534 " <gpu_time>%f</gpu_time>\n"
535 " <disk_usage>%f</disk_usage>\n"
536 " <disk_share>%f</disk_share>\n",
537 cpu_ec, cpu_time, gpu_ec, gpu_time, disk_usage, disk_share
538 );
539 }
540 out.printf(
541 "</project>\n"
542 );
543 return 0;
544 }
545
546 // Some project data is stored in account file, other in client_state.xml
547 // Copy fields that are stored in client_state.xml from "p" into "this"
548 //
copy_state_fields(PROJECT & p)549 void PROJECT::copy_state_fields(PROJECT& p) {
550 scheduler_urls = p.scheduler_urls;
551 safe_strcpy(project_name, p.project_name);
552 safe_strcpy(user_name, p.user_name);
553 safe_strcpy(team_name, p.team_name);
554 safe_strcpy(host_venue, p.host_venue);
555 safe_strcpy(email_hash, p.email_hash);
556 safe_strcpy(cross_project_id, p.cross_project_id);
557 safe_strcpy(external_cpid, p.external_cpid);
558 user_total_credit = p.user_total_credit;
559 user_expavg_credit = p.user_expavg_credit;
560 user_create_time = p.user_create_time;
561 cpid_time = p.cpid_time;
562 rpc_seqno = p.rpc_seqno;
563 userid = p.userid;
564 teamid = p.teamid;
565 hostid = p.hostid;
566 host_total_credit = p.host_total_credit;
567 host_expavg_credit = p.host_expavg_credit;
568 host_create_time = p.host_create_time;
569 nrpc_failures = p.nrpc_failures;
570 master_fetch_failures = p.master_fetch_failures;
571 min_rpc_time = p.min_rpc_time;
572 next_rpc_time = p.next_rpc_time;
573 master_url_fetch_pending = p.master_url_fetch_pending;
574 sched_rpc_pending = p.sched_rpc_pending;
575 trickle_up_pending = p.trickle_up_pending;
576 safe_strcpy(code_sign_key, p.code_sign_key);
577 for (int i=0; i<MAX_RSC; i++) {
578 rsc_pwf[i] = p.rsc_pwf[i];
579 no_rsc_pref[i] = p.no_rsc_pref[i];
580 no_rsc_apps[i] = p.no_rsc_apps[i];
581 no_rsc_ams[i] = p.no_rsc_ams[i];
582 }
583 pwf = p.pwf;
584 send_full_workload = p.send_full_workload;
585 dont_use_dcf = p.dont_use_dcf;
586 send_time_stats_log = p.send_time_stats_log;
587 send_job_log = p.send_job_log;
588 non_cpu_intensive = p.non_cpu_intensive;
589 verify_files_on_app_start = p.verify_files_on_app_start;
590 suspended_via_gui = p.suspended_via_gui;
591 dont_request_more_work = p.dont_request_more_work;
592 detach_when_done = p.detach_when_done;
593 attached_via_acct_mgr = p.attached_via_acct_mgr;
594 ended = p.ended;
595 duration_correction_factor = p.duration_correction_factor;
596 ams_resource_share = p.ams_resource_share;
597 if (ams_resource_share >= 0) {
598 resource_share = ams_resource_share;
599 }
600 desired_disk_usage = p.desired_disk_usage;
601 use_symlinks = p.use_symlinks;
602 njobs_success = p.njobs_success;
603 njobs_error = p.njobs_error;
604 elapsed_time = p.elapsed_time;
605 last_rpc_time = p.last_rpc_time;
606 cpu_ec = p.cpu_ec;
607 cpu_time = p.cpu_time;
608 gpu_ec = p.gpu_ec;
609 gpu_time = p.gpu_time;
610 }
611
612 // Write project statistic to GUI RPC reply
613 //
write_statistics(MIOFILE & out)614 int PROJECT::write_statistics(MIOFILE& out) {
615 trim_statistics();
616 out.printf(
617 "<project_statistics>\n"
618 " <master_url>%s</master_url>\n",
619 master_url
620 );
621
622 for (vector<DAILY_STATS>::iterator i=statistics.begin();
623 i!=statistics.end(); ++i
624 ) {
625 out.printf(
626 " <daily_statistics>\n"
627 " <day>%f</day>\n"
628 " <user_total_credit>%f</user_total_credit>\n"
629 " <user_expavg_credit>%f</user_expavg_credit>\n"
630 " <host_total_credit>%f</host_total_credit>\n"
631 " <host_expavg_credit>%f</host_expavg_credit>\n"
632 " </daily_statistics>\n",
633 i->day,
634 i->user_total_credit,
635 i->user_expavg_credit,
636 i->host_total_credit,
637 i->host_expavg_credit
638 );
639 }
640 out.printf(
641 "</project_statistics>\n"
642 );
643 return 0;
644 }
645
suspend()646 void PROJECT::suspend() {
647 suspended_via_gui = true;
648 gstate.request_schedule_cpus("project suspended");
649 gstate.request_work_fetch("project suspended");
650 }
resume()651 void PROJECT::resume() {
652 suspended_via_gui = false;
653 gstate.request_schedule_cpus("project resumed");
654 gstate.request_work_fetch("project resumed");
655 }
656
abort_not_started()657 void PROJECT::abort_not_started() {
658 for (unsigned int i=0; i<gstate.results.size(); i++) {
659 RESULT* rp = gstate.results[i];
660 if (rp->project != this) continue;
661 if (rp->is_not_started()) {
662 rp->abort_inactive(EXIT_ABORTED_VIA_GUI);
663 }
664 }
665 }
666
get_task_durs(double & not_started_dur,double & in_progress_dur)667 void PROJECT::get_task_durs(double& not_started_dur, double& in_progress_dur) {
668 not_started_dur = 0;
669 in_progress_dur = 0;
670 for (unsigned int i=0; i<gstate.results.size(); i++) {
671 RESULT* rp = gstate.results[i];
672 if (rp->project != this) continue;
673 double d = rp->estimated_runtime_remaining();
674 d /= gstate.time_stats.availability_frac(rp->avp->gpu_usage.rsc_type);
675 if (rp->is_not_started()) {
676 not_started_dur += d;
677 } else {
678 in_progress_dur += d;
679 }
680 }
681 }
682
get_scheduler_url(int index,double r)683 const char* PROJECT::get_scheduler_url(int index, double r) {
684 int n = (int) scheduler_urls.size();
685 int ir = (int)(r*n);
686 int i = (index + ir)%n;
687 return scheduler_urls[i].c_str();
688 }
689
690 // delete current sym links.
691 // This is done when parsing scheduler reply,
692 // to ensure that we get rid of sym links for
693 // project files no longer in use
694 //
delete_project_file_symlinks()695 void PROJECT::delete_project_file_symlinks() {
696 unsigned int i;
697 char path[MAXPATHLEN];
698
699 for (i=0; i<project_files.size(); i++) {
700 FILE_REF& fref = project_files[i];
701 snprintf(path, sizeof(path), "%s/%s", project_dir(), fref.open_name);
702 delete_project_owned_file(path, false);
703 }
704 }
705
706 // install pointers from FILE_REFs to FILE_INFOs for project files,
707 // and flag FILE_INFOs as being project files.
708 //
link_project_files()709 void PROJECT::link_project_files() {
710 FILE_INFO* fip;
711 vector<FILE_REF>::iterator fref_iter;
712 fref_iter = project_files.begin();
713 while (fref_iter != project_files.end()) {
714 FILE_REF& fref = *fref_iter;
715 fip = gstate.lookup_file_info(this, fref.file_name);
716 if (!fip) {
717 msg_printf(this, MSG_INTERNAL_ERROR,
718 "project file refers to non-existent %s", fref.file_name
719 );
720 fref_iter = project_files.erase(fref_iter);
721 continue;
722 }
723 fref.file_info = fip;
724 fip->is_project_file = true;
725 ++fref_iter;
726 }
727 }
728
create_project_file_symlinks()729 void PROJECT::create_project_file_symlinks() {
730 for (unsigned i=0; i<gstate.file_infos.size(); i++) {
731 FILE_INFO* fip = gstate.file_infos[i];
732 if (fip->project == this && fip->is_project_file && fip->status == FILE_PRESENT) {
733 write_symlink_for_project_file(fip);
734 }
735 }
736 }
737
write_project_files(MIOFILE & f)738 void PROJECT::write_project_files(MIOFILE& f) {
739 unsigned int i;
740
741 if (!project_files.size()) return;
742 f.printf("<project_files>\n");
743 for (i=0; i<project_files.size(); i++) {
744 FILE_REF& fref = project_files[i];
745 fref.write(f);
746 }
747 f.printf("</project_files>\n");
748 }
749
750 // write symlinks for project files.
751 // Note: it's conceivable that one physical file
752 // has several logical names, so try them all
753 //
write_symlink_for_project_file(FILE_INFO * fip)754 int PROJECT::write_symlink_for_project_file(FILE_INFO* fip) {
755 char link_path[MAXPATHLEN], file_path[MAXPATHLEN];
756 unsigned int i;
757
758 for (i=0; i<project_files.size(); i++) {
759 FILE_REF& fref = project_files[i];
760 if (fref.file_info != fip) continue;
761 snprintf(link_path, sizeof(link_path), "%s/%s", project_dir(), fref.open_name);
762 snprintf(file_path, sizeof(file_path), "%s/%s", project_dir(), fip->name);
763 make_soft_link(this, link_path, file_path);
764 }
765 return 0;
766 }
767
768 // a project file download just finished.
769 // If it's the last one, update project_files_downloaded_time
770 //
update_project_files_downloaded_time()771 void PROJECT::update_project_files_downloaded_time() {
772 unsigned int i;
773 for (i=0; i<project_files.size(); i++) {
774 FILE_REF& fref = project_files[i];
775 FILE_INFO* fip = fref.file_info;
776 if (fip->status != FILE_PRESENT) continue;
777 }
778 project_files_downloaded_time = gstate.now;
779 }
780
some_download_stalled()781 bool PROJECT::some_download_stalled() {
782 #ifndef SIM
783 unsigned int i;
784
785 if (!download_backoff.ok_to_transfer()) return true;
786
787 for (i=0; i<gstate.pers_file_xfers->pers_file_xfers.size(); i++) {
788 PERS_FILE_XFER* pfx = gstate.pers_file_xfers->pers_file_xfers[i];
789 if (pfx->fip->project != this) continue;
790 if (pfx->is_upload) continue;
791 if (pfx->next_request_time > gstate.now) return true;
792 }
793 #endif
794 return false;
795 }
796
runnable(int rsc_type)797 bool PROJECT::runnable(int rsc_type) {
798 if (suspended_via_gui) return false;
799 for (unsigned int i=0; i<gstate.results.size(); i++) {
800 RESULT* rp = gstate.results[i];
801 if (rp->project != this) continue;
802 if (rsc_type != RSC_TYPE_ANY) {
803 if (rp->avp->gpu_usage.rsc_type != rsc_type) {
804 continue;
805 }
806 }
807 if (rp->runnable()) return true;
808 }
809 return false;
810 }
811
uploading()812 bool PROJECT::uploading() {
813 for (unsigned int i=0; i<gstate.file_xfers->file_xfers.size(); i++) {
814 FILE_XFER& fx = *gstate.file_xfers->file_xfers[i];
815 if (fx.fip->project == this && fx.is_upload) {
816 return true;
817 }
818 }
819 return false;
820 }
821
downloading()822 bool PROJECT::downloading() {
823 if (suspended_via_gui) return false;
824 for (unsigned int i=0; i<gstate.results.size(); i++) {
825 RESULT* rp = gstate.results[i];
826 if (rp->project != this) continue;
827 if (rp->downloading()) return true;
828 }
829 return false;
830 }
831
has_results()832 bool PROJECT::has_results() {
833 for (unsigned i=0; i<gstate.results.size(); i++) {
834 RESULT *rp = gstate.results[i];
835 if (rp->project == this) return true;
836 }
837 return false;
838 }
839
some_result_suspended()840 bool PROJECT::some_result_suspended() {
841 unsigned int i;
842 for (i=0; i<gstate.results.size(); i++) {
843 RESULT *rp = gstate.results[i];
844 if (rp->project != this) continue;
845 if (rp->suspended_via_gui) return true;
846 }
847 return false;
848 }
849
can_request_work()850 bool PROJECT::can_request_work() {
851 if (suspended_via_gui) return false;
852 if (master_url_fetch_pending) return false;
853 if (min_rpc_time > gstate.now) return false;
854 if (dont_request_more_work) return false;
855 if (gstate.in_abort_sequence) return false;
856 return true;
857 }
858
potentially_runnable()859 bool PROJECT::potentially_runnable() {
860 if (runnable(RSC_TYPE_ANY)) return true;
861 if (can_request_work()) return true;
862 if (downloading()) return true;
863 return false;
864 }
865
nearly_runnable()866 bool PROJECT::nearly_runnable() {
867 if (runnable(RSC_TYPE_ANY)) return true;
868 if (downloading()) return true;
869 return false;
870 }
871
set_min_rpc_time(double future_time,const char * reason)872 void PROJECT::set_min_rpc_time(double future_time, const char* reason) {
873 if (future_time <= min_rpc_time) return;
874 min_rpc_time = future_time;
875 possibly_backed_off = true;
876 if (log_flags.sched_op_debug) {
877 msg_printf(this, MSG_INFO,
878 "[sched_op] Deferring communication for %s",
879 timediff_format(min_rpc_time - gstate.now).c_str()
880 );
881 msg_printf(this, MSG_INFO, "[sched_op] Reason: %s\n", reason);
882 }
883 }
884
885 // Return true if we should not contact the project yet.
886 //
waiting_until_min_rpc_time()887 bool PROJECT::waiting_until_min_rpc_time() {
888 return (min_rpc_time > gstate.now);
889 }
890
trim_statistics()891 void PROJECT::trim_statistics() {
892 double cutoff = dday() - cc_config.save_stats_days*86400;
893 // delete old stats; fill in the gaps if some days missing
894 //
895 while (!statistics.empty()) {
896 DAILY_STATS& ds = statistics[0];
897 if (ds.day >= cutoff) {
898 break;
899 }
900 if (statistics.size() > 1) {
901 DAILY_STATS& ds2 = statistics[1];
902 if (ds2.day <= cutoff) {
903 statistics.erase(statistics.begin());
904 } else {
905 ds.day = cutoff;
906 break;
907 }
908 } else {
909 ds.day = cutoff;
910 break;
911 }
912 }
913 }
914
project_dir()915 const char* PROJECT::project_dir() {
916 if (_project_dir[0] == 0) {
917 char buf[1024];
918 escape_project_url(master_url, buf);
919 snprintf(_project_dir, sizeof(_project_dir), "%s/%s", PROJECTS_DIR, buf);
920 }
921 return _project_dir;
922 }
923
project_dir_absolute()924 const char* PROJECT::project_dir_absolute() {
925 if (_project_dir_absolute[0] == 0) {
926 relative_to_absolute(project_dir(), _project_dir_absolute);
927 }
928 return _project_dir_absolute;
929 }
930
931 // If no_rsc_apps flags are set for all resource types, something's wrong;
932 // clear them, and fall back to per-resource backoff.
933 // Otherwise we might never contact the project again
934 //
check_no_rsc_apps()935 void PROJECT::check_no_rsc_apps() {
936 for (int i=0; i<coprocs.n_rsc; i++) {
937 if (!no_rsc_apps[i]) return;
938 }
939 msg_printf(this, MSG_INFO,
940 "Warning: no_rsc_apps flag set for all resources. Clearing flags."
941 );
942 for (int i=0; i<coprocs.n_rsc; i++) {
943 no_rsc_apps[i] = false;
944 }
945 }
946
947 // set no_rsc_apps[] for anonymous platform project
948 //
check_no_apps()949 void PROJECT::check_no_apps() {
950 for (int i=0; i<coprocs.n_rsc; i++) {
951 no_rsc_apps[i] = true;
952 }
953
954 for (unsigned int i=0; i<gstate.app_versions.size(); i++) {
955 APP_VERSION* avp = gstate.app_versions[i];
956 if (avp->project != this) continue;
957 no_rsc_apps[avp->gpu_usage.rsc_type] = false;
958 }
959 }
960
961 // show a notice if we can't possibly get work from this project,
962 // and there's something the user could do about it
963 //
show_no_work_notice()964 void PROJECT::show_no_work_notice() {
965 bool show_ams = false, show_prefs=false, show_config = false;
966 bool user_action_possible = false;
967 for (int i=0; i<coprocs.n_rsc; i++) {
968 if (no_rsc_apps[i]) continue;
969 bool banned_by_user = no_rsc_pref[i] || no_rsc_config[i] || no_rsc_ams[i];
970 if (!banned_by_user) {
971 // work for this resource is possible; return
972 notices.remove_notices(this, REMOVE_NO_WORK_MSG);
973 return;
974 }
975 if (no_rsc_pref[i]) show_prefs = true;
976 if (no_rsc_config[i]) show_config = true;
977 if (no_rsc_ams[i]) show_ams = true;
978 user_action_possible = true;
979 }
980 if (!user_action_possible) {
981 // no work is possible because project has no apps for any resource
982 //
983 notices.remove_notices(this, REMOVE_NO_WORK_MSG);
984 return;
985 }
986
987 bool first = true;
988 string x;
989 x = NO_WORK_MSG;
990 x += " ";
991 x += _("To fix this, you can ");
992 if (show_prefs) {
993 first = false;
994 x += _("change Project Preferences on the project's web site");
995 }
996 if (show_config) {
997 if (!first) {
998 x += ", or ";
999 }
1000 x += _("remove GPU exclusions in your cc_config.xml file");
1001 first = false;
1002 }
1003 if (show_ams) {
1004 if (!first) {
1005 x += ", or ";
1006 }
1007 x += _("change your settings at your account manager web site");
1008 }
1009 x += ".";
1010 msg_printf(this, MSG_USER_ALERT, "%s", x.c_str());
1011 }
1012