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