1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2017 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
18 #include "cpp.h"
19
20 #ifdef _WIN32
21 #include "boinc_win.h"
22 #ifdef _MSC_VER
23 #define chdir _chdir
24 #define snprintf _snprintf
25 #endif
26 #else
27 #include "config.h"
28 #include <cstdio>
29 #include <cstring>
30 #include <unistd.h>
31 #endif
32
33 #include "common_defs.h"
34 #include "diagnostics.h"
35 #include "error_numbers.h"
36 #include "filesys.h"
37 #include "parse.h"
38 #include "str_replace.h"
39 #include "str_util.h"
40
41 #include "client_state.h"
42 #include "client_msgs.h"
43 #include "cs_proxy.h"
44 #include "file_names.h"
45 #include "project.h"
46 #include "result.h"
47 #include "sandbox.h"
48
49 using std::string;
50
51 LOG_FLAGS log_flags;
52 CC_CONFIG cc_config;
53
show_flag(char * buf,int len,bool flag,const char * flag_name)54 static void show_flag(char* buf, int len, bool flag, const char* flag_name) {
55 if (!flag) return;
56 int n = (int)strlen(buf);
57 if (!n) {
58 strlcpy(buf, flag_name, len);
59 return;
60 }
61 strlcat(buf, ", ", len);
62 strlcat(buf, flag_name, len);
63 if (strlen(buf) > 60) {
64 msg_printf(NULL, MSG_INFO, "log flags: %s", buf);
65 strlcpy(buf, "", len);
66 }
67 }
68
show()69 void LOG_FLAGS::show() {
70 char buf[256];
71 safe_strcpy(buf, "");
72 show_flag(buf, sizeof(buf), file_xfer, "file_xfer");
73 show_flag(buf, sizeof(buf), sched_ops, "sched_ops");
74 show_flag(buf, sizeof(buf), task, "task");
75
76 show_flag(buf, sizeof(buf), app_msg_receive, "app_msg_receive");
77 show_flag(buf, sizeof(buf), app_msg_send, "app_msg_send");
78 show_flag(buf, sizeof(buf), async_file_debug, "async_file_debug");
79 show_flag(buf, sizeof(buf), benchmark_debug, "benchmark_debug");
80 show_flag(buf, sizeof(buf), checkpoint_debug, "checkpoint_debug");
81 show_flag(buf, sizeof(buf), coproc_debug, "coproc_debug");
82 show_flag(buf, sizeof(buf), cpu_sched, "cpu_sched");
83 show_flag(buf, sizeof(buf), cpu_sched_debug, "cpu_sched_debug");
84 show_flag(buf, sizeof(buf), cpu_sched_status, "cpu_sched_status");
85 show_flag(buf, sizeof(buf), dcf_debug, "dcf_debug");
86 show_flag(buf, sizeof(buf), file_xfer_debug, "file_xfer_debug");
87 show_flag(buf, sizeof(buf), gui_rpc_debug, "gui_rpc_debug");
88 show_flag(buf, sizeof(buf), heartbeat_debug, "heartbeat_debug");
89 show_flag(buf, sizeof(buf), http_debug, "http_debug");
90 show_flag(buf, sizeof(buf), http_xfer_debug, "http_xfer_debug");
91 show_flag(buf, sizeof(buf), idle_detection_debug, "idle_detection_debug");
92 show_flag(buf, sizeof(buf), mem_usage_debug, "mem_usage_debug");
93 show_flag(buf, sizeof(buf), network_status_debug, "network_status_debug");
94 show_flag(buf, sizeof(buf), notice_debug, "notice_debug");
95 show_flag(buf, sizeof(buf), poll_debug, "poll_debug");
96 show_flag(buf, sizeof(buf), priority_debug, "priority_debug");
97 show_flag(buf, sizeof(buf), proxy_debug, "proxy_debug");
98 show_flag(buf, sizeof(buf), rr_simulation, "rr_simulation");
99 show_flag(buf, sizeof(buf), sched_op_debug, "sched_op_debug");
100 show_flag(buf, sizeof(buf), scrsave_debug, "scrsave_debug");
101 show_flag(buf, sizeof(buf), slot_debug, "slot_debug");
102 show_flag(buf, sizeof(buf), state_debug, "state_debug");
103 show_flag(buf, sizeof(buf), statefile_debug, "statefile_debug");
104 show_flag(buf, sizeof(buf), task_debug, "task_debug");
105 show_flag(buf, sizeof(buf), time_debug, "time_debug");
106 show_flag(buf, sizeof(buf), unparsed_xml, "unparsed_xml");
107 show_flag(buf, sizeof(buf), work_fetch_debug, "work_fetch_debug");
108
109 if (strlen(buf)) {
110 msg_printf(NULL, MSG_INFO, "log flags: %s", buf);
111 }
112 }
113
show_gpu_ignore(vector<int> & devs,int rt)114 static void show_gpu_ignore(vector<int>& devs, int rt) {
115 for (unsigned int i=0; i<devs.size(); i++) {
116 msg_printf(NULL, MSG_INFO,
117 "Config: ignoring %s %d", proc_type_name(rt), devs[i]
118 );
119 }
120 }
121
122 // Show GPU exclusions in event log.
123 // Don't show errors - they were already shown when we parsed the config file
124 //
show_exclude_gpu(EXCLUDE_GPU & e)125 static void show_exclude_gpu(EXCLUDE_GPU& e) {
126 char t[256], app_name[256], dev[256];
127 PROJECT *p = gstate.lookup_project(e.url.c_str());
128 if (!p) return;
129 if (e.type.empty()) {
130 safe_strcpy(t, "all");
131 } else {
132 safe_strcpy(t, e.type.c_str());
133 }
134 if (e.appname.empty()) {
135 safe_strcpy(app_name, "all");
136 } else {
137 safe_strcpy(app_name, e.appname.c_str());
138 }
139 if (e.device_num < 0) {
140 safe_strcpy(dev, "all");
141 } else {
142 snprintf(dev, sizeof(dev), "%d", e.device_num);
143 }
144 msg_printf(p, MSG_INFO,
145 "Config: excluded GPU. Type: %s. App: %s. Device: %s",
146 t, app_name, dev
147 );
148 }
149
150 // Print config info.
151 // This is called during startup (after client_state.xml has been read)
152 // and also from the handle_read_cc_config GUI RPC.
153 //
154 // Keep these in alpha order
155 //
156 // TODO: show all config options
157 //
show()158 void CC_CONFIG::show() {
159 unsigned int i;
160 if (abort_jobs_on_exit) {
161 msg_printf(NULL, MSG_INFO, "Config: abort jobs on exit");
162 }
163 if (allow_multiple_clients) {
164 msg_printf(NULL, MSG_INFO, "Config: allow multiple clients");
165 }
166 if (allow_remote_gui_rpc) {
167 msg_printf(NULL, MSG_INFO,
168 "Config: GUI RPC allowed from any host"
169 );
170 }
171 FILE* f = fopen(REMOTEHOST_FILE_NAME, "r");
172 if (f) {
173 msg_printf(NULL, MSG_INFO,
174 "Config: GUI RPCs allowed from:"
175 );
176 char buf[256];
177 while (fgets(buf, 256, f)) {
178 strip_whitespace(buf);
179 if (!(buf[0] =='#' || buf[0] == ';') && strlen(buf) > 0 ) {
180 msg_printf(NULL, MSG_INFO,
181 " %s", buf
182 );
183 }
184 }
185 fclose(f);
186 }
187 if (disallow_attach) {
188 msg_printf(NULL, MSG_INFO, "Config: disallow project attach");
189 }
190 if (dont_check_file_sizes) {
191 msg_printf(NULL, MSG_INFO, "Config: don't check file sizes");
192 }
193 if (dont_suspend_nci) {
194 msg_printf(NULL, MSG_INFO, "Config: don't suspend NCI tasks");
195 }
196 if (dont_use_vbox) {
197 msg_printf(NULL, MSG_INFO, "Config: don't use VirtualBox");
198 }
199 for (i=0; i<alt_platforms.size(); i++) {
200 msg_printf(NULL, MSG_INFO,
201 "Config: alternate platform: %s", alt_platforms[i].c_str()
202 );
203 }
204 for (i=0; i<exclude_gpus.size(); i++) {
205 show_exclude_gpu(exclude_gpus[i]);
206 }
207 for (i=0; i<exclusive_apps.size(); i++) {
208 msg_printf(NULL, MSG_INFO,
209 "Config: don't compute while %s is running",
210 exclusive_apps[i].c_str()
211 );
212 }
213 for (i=0; i<exclusive_gpu_apps.size(); i++) {
214 msg_printf(NULL, MSG_INFO,
215 "Config: don't use GPUs while %s is running",
216 exclusive_gpu_apps[i].c_str()
217 );
218 }
219 if (exit_after_finish) {
220 msg_printf(NULL, MSG_INFO, "Config: exit after finish");
221 }
222 if (exit_before_start) {
223 msg_printf(NULL, MSG_INFO, "Config: exit before start task");
224 }
225 if (exit_when_idle) {
226 msg_printf(NULL, MSG_INFO, "Config: exit when idle");
227 }
228 if (fetch_minimal_work) {
229 msg_printf(NULL, MSG_INFO, "Config: fetch minimal work");
230 }
231 if (fetch_on_update) {
232 msg_printf(NULL, MSG_INFO, "Config: fetch on update");
233 }
234 if (http_1_0) {
235 msg_printf(NULL, MSG_INFO, "Config: use HTTP 1.0");
236 }
237 for (int j=1; j<NPROC_TYPES; j++) {
238 show_gpu_ignore(ignore_gpu_instance[j], j);
239 }
240 if (lower_client_priority) {
241 msg_printf(NULL, MSG_INFO, "Config: lower client priority");
242 }
243 if (max_event_log_lines != DEFAULT_MAX_EVENT_LOG_LINES) {
244 if (max_event_log_lines) {
245 msg_printf(NULL, MSG_INFO,
246 "Config: event log limit %d lines", max_event_log_lines
247 );
248 } else {
249 msg_printf(NULL, MSG_INFO, "Config: event log limit disabled");
250 }
251 }
252 if (ncpus>0) {
253 msg_printf(NULL, MSG_INFO, "Config: simulate %d CPUs", cc_config.ncpus);
254 }
255 if (no_gpus) {
256 msg_printf(NULL, MSG_INFO, "Config: don't use coprocessors");
257 }
258 if (no_info_fetch) {
259 msg_printf(NULL, MSG_INFO, "Config: don't fetch project list or client version info");
260 }
261 if (no_opencl) {
262 msg_printf(NULL, MSG_INFO, "Config: don't use OpenCL");
263 }
264 if (no_priority_change) {
265 msg_printf(NULL, MSG_INFO, "Config: run apps at regular priority");
266 }
267 if (report_results_immediately) {
268 msg_printf(NULL, MSG_INFO, "Config: report completed tasks immediately");
269 }
270 if (unsigned_apps_ok) {
271 msg_printf(NULL, MSG_INFO, "Config: unsigned apps OK");
272 }
273 if (use_all_gpus) {
274 msg_printf(NULL, MSG_INFO, "Config: use all coprocessors");
275 }
276 if (vbox_window) {
277 msg_printf(NULL, MSG_INFO,
278 "Config: open console window for VirtualBox applications"
279 );
280 if (g_use_sandbox) {
281 msg_printf(NULL, MSG_INFO,
282 " NOTE: the client is running in protected mode,"
283 );
284 msg_printf(NULL, MSG_INFO,
285 " so VirtualBox console windows cannot be opened."
286 );
287 }
288 }
289 }
290
291 // This is used by the BOINC client.
292 // KEEP IN SYNCH WITH CC_CONFIG::parse_options()!!
293 // (It's separate so that we can write messages in it)
294
parse_options_client(XML_PARSER & xp)295 int CC_CONFIG::parse_options_client(XML_PARSER& xp) {
296 string s;
297 int n, retval;
298
299 //clear();
300 // don't do this here because some options are set by cmdline args,
301 // which are parsed first
302 // but do clear these, which aren't accessable via cmdline:
303 //
304 alt_platforms.clear();
305 exclusive_apps.clear();
306 exclusive_gpu_apps.clear();
307 for (int i=1; i<NPROC_TYPES; i++) {
308 ignore_gpu_instance[i].clear();
309 }
310
311 while (!xp.get_tag()) {
312 if (!xp.is_tag) {
313 msg_printf_notice(NULL, false,
314 "http://boinc.berkeley.edu/manager_links.php?target=notice&controlid=config",
315 "%s: %s",
316 _("Unexpected text in cc_config.xml"),
317 xp.parsed_tag
318 );
319 continue;
320 }
321 if (xp.match_tag("/options")) {
322 return 0;
323 }
324 if (xp.parse_bool("abort_jobs_on_exit", abort_jobs_on_exit)) continue;
325 if (xp.parse_bool("allow_multiple_clients", allow_multiple_clients)) continue;
326 if (xp.parse_bool("allow_remote_gui_rpc", allow_remote_gui_rpc)) continue;
327 if (xp.parse_string("alt_platform", s)) {
328 alt_platforms.push_back(s);
329 continue;
330 }
331 if (xp.parse_string("client_download_url", client_download_url)) {
332 downcase_string(client_download_url);
333 continue;
334 }
335 if (xp.parse_string("client_new_version_text", client_new_version_text)) {
336 continue;
337 }
338 if (xp.parse_string("client_version_check_url", client_version_check_url)) {
339 downcase_string(client_version_check_url);
340 continue;
341 }
342 if (xp.match_tag("coproc")) {
343 COPROC c;
344 retval = c.parse(xp);
345 if (retval) {
346 msg_printf_notice(NULL, false, NULL,
347 "Can't parse <coproc> element in cc_config.xml"
348 );
349 continue;
350 }
351 retval = config_coprocs.add(c);
352 if (retval) {
353 msg_printf_notice(NULL, false, NULL,
354 "Duplicate <coproc> element in cc_config.xml"
355 );
356 }
357 continue;
358 }
359 if (xp.parse_bool("disallow_attach", disallow_attach)) continue;
360 if (xp.parse_bool("dont_check_file_sizes", dont_check_file_sizes)) continue;
361 if (xp.parse_bool("dont_contact_ref_site", dont_contact_ref_site)) continue;
362 if (xp.parse_bool("lower_client_priority", lower_client_priority)) continue;
363 if (xp.parse_bool("dont_suspend_nci", dont_suspend_nci)) continue;
364 if (xp.parse_bool("dont_use_vbox", dont_use_vbox)) continue;
365 if (xp.match_tag("exclude_gpu")) {
366 EXCLUDE_GPU eg;
367 retval = eg.parse(xp);
368 if (retval) {
369 msg_printf_notice(NULL, false, NULL,
370 "Can't parse <exclude_gpu> element in cc_config.xml"
371 );
372 } else {
373 exclude_gpus.push_back(eg);
374 }
375 continue;
376 }
377 if (xp.parse_string("exclusive_app", s)) {
378 if (!strstr(s.c_str(), "boinc")) {
379 exclusive_apps.push_back(s);
380 }
381 continue;
382 }
383 if (xp.parse_string("exclusive_gpu_app", s)) {
384 if (!strstr(s.c_str(), "boinc")) {
385 exclusive_gpu_apps.push_back(s);
386 }
387 continue;
388 }
389 if (xp.parse_bool("exit_after_finish", exit_after_finish)) continue;
390 if (xp.parse_bool("exit_before_start", exit_before_start)) continue;
391 if (xp.parse_bool("exit_when_idle", exit_when_idle)) {
392 if (exit_when_idle) {
393 report_results_immediately = true;
394 }
395 continue;
396 }
397 if (xp.parse_bool("fetch_minimal_work", fetch_minimal_work)) continue;
398 if (xp.parse_bool("fetch_on_update", fetch_on_update)) continue;
399 if (xp.parse_string("force_auth", force_auth)) {
400 downcase_string(force_auth);
401 continue;
402 }
403 if (xp.parse_bool("http_1_0", http_1_0)) continue;
404 if (xp.parse_int("http_transfer_timeout", http_transfer_timeout)) continue;
405 if (xp.parse_int("http_transfer_timeout_bps", http_transfer_timeout_bps)) continue;
406 if (xp.parse_int("ignore_cuda_dev", n)||xp.parse_int("ignore_nvidia_dev", n)) {
407 ignore_gpu_instance[PROC_TYPE_NVIDIA_GPU].push_back(n);
408 continue;
409 }
410 if (xp.parse_int("ignore_ati_dev", n)) {
411 ignore_gpu_instance[PROC_TYPE_AMD_GPU].push_back(n);
412 continue;
413 }
414 if (xp.parse_int("ignore_intel_dev", n)) {
415 ignore_gpu_instance[PROC_TYPE_INTEL_GPU].push_back(n);
416 continue;
417 }
418 if (xp.parse_int("max_event_log_lines", max_event_log_lines)) continue;
419 if (xp.parse_int("max_file_xfers", max_file_xfers)) continue;
420 if (xp.parse_int("max_file_xfers_per_project", max_file_xfers_per_project)) continue;
421 if (xp.parse_int("max_stderr_file_size", max_stderr_file_size)) continue;
422 if (xp.parse_int("max_stdout_file_size", max_stdout_file_size)) continue;
423 if (xp.parse_int("max_tasks_reported", max_tasks_reported)) continue;
424 if (xp.parse_int("ncpus", ncpus)) continue;
425 if (xp.parse_string("network_test_url", network_test_url)) {
426 downcase_string(network_test_url);
427 continue;
428 }
429 if (xp.parse_bool("no_alt_platform", no_alt_platform)) continue;
430 if (xp.parse_bool("no_gpus", no_gpus)) continue;
431 if (xp.parse_bool("no_info_fetch", no_info_fetch)) continue;
432 if (xp.parse_bool("no_opencl", no_opencl)) continue;
433 if (xp.parse_bool("no_priority_change", no_priority_change)) continue;
434 if (xp.parse_bool("os_random_only", os_random_only)) continue;
435 if (xp.parse_int("process_priority", process_priority)) continue;
436 if (xp.parse_int("process_priority_special", process_priority_special)) continue;
437 #ifndef SIM
438 if (xp.match_tag("proxy_info")) {
439 retval = proxy_info.parse_config(xp);
440 if (retval) {
441 msg_printf_notice(NULL, false, NULL,
442 "Can't parse <proxy_info> element in cc_config.xml"
443 );
444 }
445 continue;
446 }
447 #endif
448 if (xp.parse_double("rec_half_life_days", rec_half_life)) {
449 if (rec_half_life <= 0) rec_half_life = 10;
450 rec_half_life *= 86400;
451 continue;
452 }
453 if (xp.parse_bool("report_results_immediately", report_results_immediately)) continue;
454 if (xp.parse_bool("run_apps_manually", run_apps_manually)) continue;
455 if (xp.parse_int("save_stats_days", save_stats_days)) continue;
456 if (xp.parse_bool("simple_gui_only", simple_gui_only)) continue;
457 if (xp.parse_bool("skip_cpu_benchmarks", skip_cpu_benchmarks)) continue;
458 if (xp.parse_double("start_delay", start_delay)) continue;
459 if (xp.parse_bool("stderr_head", stderr_head)) continue;
460 if (xp.parse_bool("suppress_net_info", suppress_net_info)) continue;
461 if (xp.parse_bool("unsigned_apps_ok", unsigned_apps_ok)) continue;
462 if (xp.parse_bool("use_all_gpus", use_all_gpus)) continue;
463 if (xp.parse_bool("use_certs", use_certs)) continue;
464 if (xp.parse_bool("use_certs_only", use_certs_only)) continue;
465 if (xp.parse_bool("vbox_window", vbox_window)) continue;
466
467 msg_printf_notice(NULL, false,
468 "http://boinc.berkeley.edu/manager_links.php?target=notice&controlid=config",
469 "%s: <%s>",
470 _("Unrecognized tag in cc_config.xml"),
471 xp.parsed_tag
472 );
473 xp.skip_unexpected(true, "CC_CONFIG::parse_options");
474 }
475 return ERR_XML_PARSE;
476 }
477
parse_client(FILE * f)478 int CC_CONFIG::parse_client(FILE* f) {
479 MIOFILE mf;
480 XML_PARSER xp(&mf);
481
482 mf.init_file(f);
483 if (!xp.parse_start("cc_config")) {
484 msg_printf_notice(NULL, false,
485 "http://boinc.berkeley.edu/manager_links.php?target=notice&controlid=config",
486 "%s",
487 _("Missing start tag in cc_config.xml")
488 );
489 return ERR_XML_PARSE;
490 }
491 while (!xp.get_tag()) {
492 if (!xp.is_tag) {
493 msg_printf_notice(NULL, false,
494 "http://boinc.berkeley.edu/manager_links.php?target=notice&controlid=config",
495 "%s: %s",
496 _("Unexpected text in cc_config.xml"),
497 xp.parsed_tag
498 );
499 continue;
500 }
501 if (xp.match_tag("/cc_config")) {
502 notices.remove_notices(NULL, REMOVE_CONFIG_MSG);
503 return 0;
504 }
505 if (xp.match_tag("log_flags")) {
506 log_flags.parse(xp);
507 continue;
508 }
509 if (xp.match_tag("options")) {
510 int retval = parse_options_client(xp);
511 if (retval) {
512 msg_printf_notice(NULL, false,
513 "http://boinc.berkeley.edu/manager_links.php?target=notice&controlid=config",
514 "%s",
515 _("Error in cc_config.xml options")
516 );
517 }
518 continue;
519 }
520 if (xp.match_tag("options/")) continue;
521 if (xp.match_tag("log_flags/")) continue;
522 msg_printf_notice(NULL, false,
523 "http://boinc.berkeley.edu/manager_links.php?target=notice&controlid=config",
524 "%s: <%s>",
525 _("Unrecognized tag in cc_config.xml"),
526 xp.parsed_tag
527 );
528 xp.skip_unexpected(true, "CC_CONFIG.parse");
529 }
530 msg_printf_notice(NULL, false,
531 "http://boinc.berkeley.edu/manager_links.php?target=notice&controlid=config",
532 "%s",
533 _("Missing end tag in cc_config.xml")
534 );
535 return ERR_XML_PARSE;
536 }
537
parse(FILE * f)538 int CC_CONFIG::parse(FILE* f) {
539 MIOFILE mf;
540 mf.init_file(f);
541 XML_PARSER xp(&mf);
542
543 return parse(xp, log_flags);
544 }
545
546 // read config file, e.g. cc_config.xml
547 // Called on startup and in response to GUI RPC requesting reread
548 //
read_config_file(bool init,const char * fname)549 int read_config_file(bool init, const char* fname) {
550 if (!init) {
551 msg_printf(NULL, MSG_INFO, "Re-reading %s", fname);
552 cc_config.defaults();
553 log_flags.init();
554 }
555 FILE* f = boinc_fopen(fname, "r");
556 if (!f) {
557 msg_printf(NULL, MSG_INFO, "cc_config.xml not found - using defaults");
558 return ERR_FOPEN;
559 }
560 cc_config.parse_client(f);
561 fclose(f);
562 #ifndef SIM
563 diagnostics_set_max_file_sizes(
564 cc_config.max_stdout_file_size, cc_config.max_stderr_file_size
565 );
566 #endif
567 config_proxy_info = cc_config.proxy_info;
568
569 if (init) {
570 coprocs = cc_config.config_coprocs;
571 } else {
572 select_proxy_info(); // in case added or removed proxy info
573 }
574 return 0;
575 }
576
577 // Do stuff involving GPU exclusions.
578 // - check syntax
579 // - set APP::non_excluded_instances[rsc_type]
580 // (used in RR sim)
581 // - set PROJECT::rsc_pwf[rsc_type].non_excluded_instances
582 // (used in work fetch)
583 // - set PROJECT::rsc_pwf[rsc_type].ncoprocs_excluded
584 // (used in RR sim and work fetch)
585 // - set APP_VERSION::coproc_missing for app versions where
586 // all instances are excluded
587 // - set RESULT::coproc_missing for results for which
588 // APP_VERSION::coproc_missing is set.
589 //
process_gpu_exclusions()590 void process_gpu_exclusions() {
591 unsigned int i, j, a;
592 PROJECT *p;
593
594 // check the syntactic validity of the exclusions
595 //
596 for (i=0; i<cc_config.exclude_gpus.size(); i++) {
597 EXCLUDE_GPU& eg = cc_config.exclude_gpus[i];
598 p = gstate.lookup_project(eg.url.c_str());
599 if (!p) {
600 msg_printf(0, MSG_USER_ALERT,
601 "cc_config.xml: bad URL in GPU exclusion: %s", eg.url.c_str()
602 );
603 continue;
604 }
605 if (!eg.appname.empty()) {
606 APP* app = gstate.lookup_app(p, eg.appname.c_str());
607 if (!app) {
608 msg_printf(p, MSG_USER_ALERT,
609 "cc_config.xml: a GPU exclusion refers to an unknown application '%s'. Known applications: %s",
610 eg.appname.c_str(),
611 app_list_string(p).c_str()
612 );
613 continue;
614 }
615 }
616 if (!eg.type.empty()) {
617 bool found = false;
618 string types;
619 for (int k=1; k<coprocs.n_rsc; k++) {
620 COPROC& cp = coprocs.coprocs[k];
621 if (eg.type == cp.type) {
622 found = true;
623
624 // skip exclusions of non-existent devices
625 //
626 if (eg.device_num && (cp.device_num_index(eg.device_num) < 0)) {
627 break;
628 }
629 rsc_work_fetch[k].has_exclusions = true;
630 break;
631 }
632 types += " " + string(cp.type);
633 }
634 if (!found) {
635 msg_printf(p, MSG_USER_ALERT,
636 "cc_config.xml: bad type '%s' in GPU exclusion; valid types:%s",
637 eg.type.c_str(), types.c_str()
638 );
639 continue;
640 }
641 } else {
642 for (int k=1; k<coprocs.n_rsc; k++) {
643 rsc_work_fetch[k].has_exclusions = true;
644 }
645 }
646 }
647
648 for (i=0; i<gstate.apps.size(); i++) {
649 APP* app = gstate.apps[i];
650 for (int k=1; k<coprocs.n_rsc; k++) {
651 COPROC& cp = coprocs.coprocs[k];
652 for (int h=0; h<cp.count; h++) {
653 app->non_excluded_instances[k] |= ((COPROC_INSTANCE_BITMAP)1)<<h;
654 }
655 }
656 }
657
658 for (i=0; i<gstate.projects.size(); i++) {
659 p = gstate.projects[i];
660 for (int k=1; k<coprocs.n_rsc; k++) {
661 COPROC& cp = coprocs.coprocs[k];
662 COPROC_INSTANCE_BITMAP all_instances = 0;
663 // bitmap of 1 for all instances
664 //
665 for (int h=0; h<cp.count; h++) {
666 all_instances |= ((COPROC_INSTANCE_BITMAP)1)<<h;
667 }
668 for (j=0; j<cc_config.exclude_gpus.size(); j++) {
669 EXCLUDE_GPU& eg = cc_config.exclude_gpus[j];
670 if (!eg.type.empty() && (eg.type != cp.type)) continue;
671 if (strcmp(eg.url.c_str(), p->master_url)) continue;
672 COPROC_INSTANCE_BITMAP mask;
673 if (eg.device_num >= 0) {
674 int index = cp.device_num_index(eg.device_num);
675 // exclusion may refer to nonexistent GPU
676 //
677 if (index < 0) continue;
678 mask = ((COPROC_INSTANCE_BITMAP)1)<<index;
679 } else {
680 mask = all_instances;
681 }
682 if (eg.appname.empty()) {
683 // exclusion applies to all apps
684 //
685 for (a=0; a<gstate.apps.size(); a++) {
686 APP* app = gstate.apps[a];
687 if (app->project != p) continue;
688 app->non_excluded_instances[k] &= ~mask;
689 }
690 } else {
691 // exclusion applies to a particular app
692 //
693 APP* app = gstate.lookup_app(p, eg.appname.c_str());
694 if (!app) continue;
695 app->non_excluded_instances[k] &= ~mask;
696 }
697 }
698
699 bool found = false;
700 p->rsc_pwf[k].non_excluded_instances = 0;
701 for (a=0; a<gstate.apps.size(); a++) {
702 APP* app = gstate.apps[a];
703 if (app->project != p) continue;
704 found = true;
705 p->rsc_pwf[k].non_excluded_instances |= app->non_excluded_instances[k];
706 }
707 // if project has no apps yet (for some reason)
708 // assume it can use all instances
709 //
710 if (!found) {
711 p->rsc_pwf[k].non_excluded_instances = all_instances;
712 }
713
714 // compute ncoprocs_excluded as the number of instances
715 // excluded for at least 1 app
716 //
717 p->rsc_pwf[k].ncoprocs_excluded = 0;
718 for (int b=0; b<cp.count; b++) {
719 COPROC_INSTANCE_BITMAP mask = ((COPROC_INSTANCE_BITMAP)1)<<b;
720 for (a=0; a<gstate.apps.size(); a++) {
721 APP* app = gstate.apps[a];
722 if (app->project != p) continue;
723 if (!(app->non_excluded_instances[k] & mask)) {
724 p->rsc_pwf[k].ncoprocs_excluded++;
725 break;
726 }
727 }
728 }
729 }
730 }
731
732 for (i=0; i<gstate.app_versions.size(); i++) {
733 APP_VERSION* avp = gstate.app_versions[i];
734 if (avp->missing_coproc) continue;
735 int rt = avp->gpu_usage.rsc_type;
736 if (!rt) continue;
737 COPROC& cp = coprocs.coprocs[rt];
738 bool found = false;
739 for (int k=0; k<cp.count; k++) {
740 if (!gpu_excluded(avp->app, cp, k)) {
741 found = true;
742 break;
743 }
744 }
745 if (found) continue;
746 avp->missing_coproc = true;
747 safe_strcpy(avp->missing_coproc_name, "");
748 for (j=0; j<gstate.results.size(); j++) {
749 RESULT* rp = gstate.results[j];
750 if (rp->avp != avp) continue;
751 rp->coproc_missing = true;
752 msg_printf(avp->project, MSG_INFO,
753 "marking %s as coproc missing",
754 rp->name
755 );
756 }
757 }
758 }
759
gpu_excluded(APP * app,COPROC & cp,int ind)760 bool gpu_excluded(APP* app, COPROC& cp, int ind) {
761 if (cc_config.no_gpus) return true;
762 PROJECT* p = app->project;
763 for (unsigned int i=0; i<cc_config.exclude_gpus.size(); i++) {
764 EXCLUDE_GPU& eg = cc_config.exclude_gpus[i];
765 if (strcmp(eg.url.c_str(), p->master_url)) continue;
766 if (!eg.type.empty() && (eg.type != cp.type)) continue;
767 if (!eg.appname.empty() && (eg.appname != app->name)) continue;
768 if (eg.device_num >= 0 && eg.device_num != cp.device_nums[ind]) continue;
769 return true;
770 }
771 return false;
772 }
773
774 // if the configuration file disallows the use of a GPU type
775 // for a project, set a flag to that effect
776 //
set_no_rsc_config()777 void set_no_rsc_config() {
778 for (unsigned int i=0; i<gstate.projects.size(); i++) {
779 PROJECT& p = *gstate.projects[i];
780 for (int j=1; j<coprocs.n_rsc; j++) {
781 bool allowed[MAX_COPROC_INSTANCES];
782 memset(allowed, 0, sizeof(allowed));
783 COPROC& c = coprocs.coprocs[j];
784 for (int k=0; k<c.count; k++) {
785 allowed[c.device_nums[k]] = true;
786 }
787 for (unsigned int k=0; k<cc_config.exclude_gpus.size(); k++) {
788 EXCLUDE_GPU& e = cc_config.exclude_gpus[k];
789 if (strcmp(e.url.c_str(), p.master_url)) continue;
790 if (!e.type.empty() && strcmp(e.type.c_str(), c.type)) continue;
791 if (!e.appname.empty()) continue;
792 if (e.device_num < 0) {
793 memset(allowed, 0, sizeof(allowed));
794 break;
795 }
796 allowed[e.device_num] = false;
797 }
798 p.no_rsc_config[j] = true;
799 for (int k=0; k<c.count; k++) {
800 if (allowed[c.device_nums[k]]) {
801 p.no_rsc_config[j] = false;
802 break;
803 }
804 }
805 }
806 }
807 }
808