Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scheduler: allow negation of regular expressions in plan class XML specs #4390

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 47 additions & 31 deletions sched/plan_class_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@

using std::string;

int REGEX_CLAUSE::init(const char* p) {
present = true;
negate = false;
expr = p;
if (*p == '!') {
p++;
negate = true;
}
if (regcomp(&regex, p, REG_EXTENDED|REG_NOSUB) ) {
return ERR_XML_PARSE;
}
return 0;
}

// return true if clause is present and string doesn't match
//
bool REGEX_CLAUSE::mismatch(const char* p) {
if (!present) {
return false;
}
bool match = (regexec(&regex, p, 0, NULL, 0) == 0);
return negate?match:!match;
}

// return a numerical OS version for Darwin/OSX and Windows,
// letting us define numerical ranges for these OS versions
//
Expand Down Expand Up @@ -302,25 +326,25 @@ bool PLAN_CLASS_SPEC::check(

// host summary
//
if (have_host_summary_regex
&& regexec(&(host_summary_regex), g_reply->host.serialnum, 0, NULL, 0)
) {
if (host_summary_regex.mismatch(g_reply->host.serialnum)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: host summary '%s' didn't match regexp\n",
g_reply->host.serialnum
"[version] plan_class_spec: host summary '%s' didn't match regexp %s\n",
g_reply->host.serialnum,
host_summary_regex.expr.c_str()
);
}
return false;
}

// OS version
//
if (have_os_regex && regexec(&(os_regex), sreq.host.os_version, 0, NULL, 0)) {
if (os_regex.mismatch(sreq.host.os_version)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: OS version '%s' didn't match regexp\n",
sreq.host.os_version
"[version] plan_class_spec: OS version '%s' didn't match regexp %s\n",
sreq.host.os_version,
os_regex.expr.c_str()
);
}
return false;
Expand Down Expand Up @@ -389,21 +413,23 @@ bool PLAN_CLASS_SPEC::check(

// CPU vendor and model
//
if (have_cpu_vendor_regex && regexec(&(cpu_vendor_regex), sreq.host.p_vendor, 0, NULL, 0)) {
if (cpu_vendor_regex.mismatch(sreq.host.p_vendor)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: CPU vendor '%s' didn't match regexp\n",
sreq.host.p_vendor
"[version] plan_class_spec: CPU vendor '%s' didn't match regexp %s\n",
sreq.host.p_vendor,
cpu_vendor_regex.expr.c_str()
);
}
return false;
}

if (have_cpu_model_regex && regexec(&(cpu_model_regex), sreq.host.p_model, 0, NULL, 0)) {
if (cpu_model_regex.mismatch (sreq.host.p_model)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: CPU model '%s' didn't match regexp\n",
sreq.host.p_model
"[version] plan_class_spec: CPU model '%s' didn't match regexp %s\n",
sreq.host.p_model,
cpu_model_regex.expr.c_str()
);
}
return false;
Expand Down Expand Up @@ -521,7 +547,7 @@ bool PLAN_CLASS_SPEC::check(

// project-specific preference
//
if (have_project_prefs_regex && strlen(project_prefs_tag)) {
if (project_prefs_regex.present && strlen(project_prefs_tag)) {
char tag[256], value[256];
char buf[65536];
extract_venue(g_reply->user.project_prefs, g_reply->host.venue, buf, sizeof(buf));
Expand All @@ -533,7 +559,7 @@ bool PLAN_CLASS_SPEC::check(
project_prefs_tag, p?"true":"false"
);
}
if (p ? regexec(&(project_prefs_regex), value, 0, NULL, 0) : !project_prefs_default_true) {
if (p ? project_prefs_regex.mismatch(value) : !project_prefs_default_true) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: project prefs setting '%s' value='%s' prevents using plan class.\n",
Expand Down Expand Up @@ -1066,35 +1092,31 @@ int PLAN_CLASS_SPEC::parse(XML_PARSER& xp) {
if (xp.parse_bool("nthreads_cmdline", nthreads_cmdline)) continue;
if (xp.parse_double("projected_flops_scale", projected_flops_scale)) continue;
if (xp.parse_str("os_regex", buf, sizeof(buf))) {
if (regcomp(&(os_regex), buf, REG_EXTENDED|REG_NOSUB) ) {
if (os_regex.init(buf)) {
log_messages.printf(MSG_CRITICAL, "BAD OS REGEXP: %s\n", buf);
return ERR_XML_PARSE;
}
have_os_regex = true;
continue;
}
if (xp.parse_str("cpu_vendor_regex", buf, sizeof(buf))) {
if (regcomp(&(cpu_vendor_regex), buf, REG_EXTENDED|REG_NOSUB) ) {
if (cpu_vendor_regex.init(buf)) {
log_messages.printf(MSG_CRITICAL, "BAD CPU VENDOR REGEXP: %s\n", buf);
return ERR_XML_PARSE;
}
have_cpu_vendor_regex = true;
continue;
}
if (xp.parse_str("cpu_model_regex", buf, sizeof(buf))) {
if (regcomp(&(cpu_model_regex), buf, REG_EXTENDED|REG_NOSUB) ) {
if (cpu_model_regex.init(buf)) {
log_messages.printf(MSG_CRITICAL, "BAD CPU MODEL REGEXP: %s\n", buf);
return ERR_XML_PARSE;
}
have_cpu_model_regex = true;
continue;
}
if (xp.parse_str("host_summary_regex", buf, sizeof(buf))) {
if (regcomp(&(host_summary_regex), buf, REG_EXTENDED|REG_NOSUB) ) {
if (host_summary_regex.init(buf)) {
log_messages.printf(MSG_CRITICAL, "BAD HOST SUMMARY REGEXP: %s\n", buf);
return ERR_XML_PARSE;
}
have_host_summary_regex = true;
continue;
}
if (xp.parse_int("user_id", user_id)) continue;
Expand All @@ -1105,11 +1127,10 @@ int PLAN_CLASS_SPEC::parse(XML_PARSER& xp) {
if (xp.parse_int("max_android_version", max_android_version)) continue;
if (xp.parse_str("project_prefs_tag", project_prefs_tag, sizeof(project_prefs_tag))) continue;
if (xp.parse_str("project_prefs_regex", buf, sizeof(buf))) {
if (regcomp(&(project_prefs_regex), buf, REG_EXTENDED|REG_NOSUB) ) {
if (project_prefs_regex.init(buf)) {
log_messages.printf(MSG_CRITICAL, "BAD PROJECT PREFS REGEXP: %s\n", buf);
return ERR_XML_PARSE;
}
have_project_prefs_regex = true;
continue;
}
if (xp.parse_bool("project_prefs_default_true", project_prefs_default_true)) continue;
Expand Down Expand Up @@ -1198,20 +1219,15 @@ PLAN_CLASS_SPEC::PLAN_CLASS_SPEC() {
mem_usage_per_cpu = 0;
nthreads_cmdline = false;
projected_flops_scale = 1;
have_os_regex = false;
have_cpu_vendor_regex = false;
have_cpu_model_regex = false;
min_os_version = 0;
max_os_version = 0;
min_android_version = 0;
max_android_version = 0;
strcpy(project_prefs_tag, "");
have_project_prefs_regex = false;
project_prefs_default_true = false;
avg_ncpus = 0;
min_core_client_version = 0;
max_core_client_version = 0;
have_host_summary_regex = false;
user_id = 0;
infeasible_random = 0;
min_wu_id=0;
Expand Down
36 changes: 25 additions & 11 deletions sched/plan_class_spec.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,26 @@
#include <vector>
#include <regex.h>

// if you add anything here, initialize if in the constructor
// Represents a plan class clause with a regular expression
// (os, cpu_vendor, etc.).
// Has the compiled regex, and whether it's negated
//
struct REGEX_CLAUSE {
bool present; // clause is present
bool negate; // regex is negated (starts with !)
std::string expr; // the regex string
regex_t regex; // compiled regex

REGEX_CLAUSE() {
present = 0;
}
int init(const char* p);
// p is the regex, possibly preceded by !
bool mismatch(const char*);
// return true if clause is present and the string doesn't match it
};

// if you add anything here, initialize it in the constructor
//
struct PLAN_CLASS_SPEC {
char name[256];
Expand All @@ -40,27 +59,22 @@ struct PLAN_CLASS_SPEC {
double mem_usage_per_cpu;
bool nthreads_cmdline;
double projected_flops_scale;
bool have_os_regex;
regex_t os_regex;
bool have_cpu_vendor_regex;
regex_t cpu_vendor_regex;
bool have_cpu_model_regex;
regex_t cpu_model_regex;
REGEX_CLAUSE os_regex;
REGEX_CLAUSE cpu_vendor_regex;
REGEX_CLAUSE cpu_model_regex;
double min_os_version;
// Win versions can be 9 digits; may as well be safe
double max_os_version;
int min_android_version;
int max_android_version;
char project_prefs_tag[256];
bool have_project_prefs_regex;
regex_t project_prefs_regex;
REGEX_CLAUSE project_prefs_regex;
bool project_prefs_default_true;
double avg_ncpus;
int min_core_client_version;
int max_core_client_version;
// for non-compute-intensive, or override for GPU apps
bool have_host_summary_regex;
regex_t host_summary_regex;
REGEX_CLAUSE host_summary_regex;
int user_id;
double infeasible_random;
long min_wu_id;
Expand Down