int harmony_best(hdesc_t *hdesc) { int retval = 0; if (hdesc->state >= HARMONY_STATE_CONNECTED) { /* Prepare a Harmony message. */ hmesg_scrub(&hdesc->mesg); if (send_request(hdesc, HMESG_BEST) != 0) return -1; if (hdesc->mesg.status != HMESG_STATUS_OK) { hdesc->errstr = "Invalid message received from server."; errno = EINVAL; return -1; } if (hdesc->best.id < hdesc->mesg.data.point.id) { if (update_best(hdesc, &hdesc->mesg.data.point) != 0) return -1; retval = 1; } } /* Make sure our best known point is valid. */ if (hdesc->best.id < 0) { errno = EINVAL; return -1; } if (set_values(hdesc, &hdesc->best) != 0) return -1; return retval; }
int harmony_fetch(hdesc_t *hdesc) { int i; if (hdesc->state < HARMONY_STATE_CONNECTED) { hdesc->errstr = "Descriptor not currently joined to any session."; errno = EINVAL; return -1; } /* Prepare a Harmony message. */ hmesg_scrub(&hdesc->mesg); if (send_request(hdesc, HMESG_FETCH) != 0) return -1; if (hdesc->mesg.status == HMESG_STATUS_BUSY) { if (update_best(hdesc, &hdesc->mesg.data.point) != 0) return -1; if (hdesc->best.id == -1) { /* No best point is available. Inform the user by returning 0. */ return 0; } /* Set current point to best point. */ if (hpoint_copy(&hdesc->curr, &hdesc->best) != 0) { hdesc->errstr = "Internal error copying point data."; errno = EINVAL; return -1; } } else if (hdesc->mesg.status == HMESG_STATUS_OK) { if (hpoint_copy(&hdesc->curr, &hdesc->mesg.data.point) != 0) { hdesc->errstr = "Internal error copying point data."; errno = EINVAL; return -1; } } else { hdesc->errstr = "Invalid message received from server."; errno = EINVAL; return -1; } /* Update the variables from the content of the message. */ if (set_values(hdesc, &hdesc->curr) != 0) return -1; /* Initialize our internal performance array. */ for (i = 0; i < hdesc->perf->n; ++i) hdesc->perf->p[i] = NAN; /* Client variables were changed. Inform the user by returning 1. */ hdesc->state = HARMONY_STATE_TESTING; return 1; }
int harmony_report(hdesc_t *hdesc, double *perf) { int i; if (hdesc->state < HARMONY_STATE_CONNECTED) { hdesc->errstr = "Descriptor not currently joined to any session."; errno = EINVAL; return -1; } if (hdesc->state < HARMONY_STATE_TESTING) return 0; if (perf) memcpy(hdesc->perf->p, perf, sizeof(double) * hdesc->perf->n); for (i = 0; i < hdesc->perf->n; ++i) { if (isnan(hdesc->perf->p[i])) { hdesc->errstr = "Error: Performance report incomplete."; errno = EINVAL; return -1; } } /* Prepare a Harmony message. */ hmesg_scrub(&hdesc->mesg); hdesc->mesg.data.report.cand_id = hdesc->curr.id; hdesc->mesg.data.report.perf = hperf_clone(hdesc->perf); if (!hdesc->mesg.data.report.perf) { hdesc->errstr = "Error allocating performance array for message."; return -1; } if (send_request(hdesc, HMESG_REPORT) != 0) return -1; if (hdesc->mesg.status != HMESG_STATUS_OK) { hdesc->errstr = "Invalid message received from server."; errno = EINVAL; return -1; } hdesc->state = HARMONY_STATE_READY; return 0; }
char *harmony_setcfg(hdesc_t *hdesc, const char *key, const char *val) { char *buf; int retval; if (hdesc->state < HARMONY_STATE_CONNECTED) { /* User must be preparing for a new session since we're not * connected yet. Store the key/value pair in a local cache. */ buf = stralloc( hcfg_get(hdesc->sess.cfg, key) ); hcfg_set(hdesc->sess.cfg, key, val); return buf; } if (!key) { hdesc->errstr = "Invalid key string."; errno = EINVAL; return NULL; } buf = sprintf_alloc("%s=%s", key, val ? val : ""); if (!buf) { hdesc->errstr = "Internal memory allocation error."; return NULL; } /* Prepare a Harmony message. */ hmesg_scrub(&hdesc->mesg); hdesc->mesg.data.string = buf; retval = send_request(hdesc, HMESG_SETCFG); free(buf); if (retval < 0) return NULL; if (hdesc->mesg.status != HMESG_STATUS_OK) { hdesc->errstr = "Invalid message received from server."; errno = EINVAL; return NULL; } /* It is the user's responsibility to free this memory. */ return stralloc(hdesc->mesg.data.string); }
char *harmony_getcfg(hdesc_t *hdesc, const char *key) { if (hdesc->state < HARMONY_STATE_CONNECTED) { hdesc->errstr = "Descriptor not currently joined to any session."; errno = EINVAL; return NULL; } /* Prepare a Harmony message. */ hmesg_scrub(&hdesc->mesg); hdesc->mesg.data.string = key; if (send_request(hdesc, HMESG_GETCFG) != 0) return NULL; if (hdesc->mesg.status != HMESG_STATUS_OK) { hdesc->errstr = "Invalid message received from server."; errno = EINVAL; return NULL; } /* It is the user's responsibility to free this memory. */ return stralloc(hdesc->mesg.data.string); }
int harmony_join(hdesc_t *hdesc, const char *host, int port, const char *name) { int i, perf_len; int apply_argv = (hdesc->state < HARMONY_STATE_CONNECTED); char *cfgval; /* Verify that we have *at least* one variable bound, and that * this descriptor isn't already associated with a tuning * session. */ if (hdesc->ptr_len == 0) { hdesc->errstr = "No variables bound to Harmony session"; errno = EINVAL; return -1; } if (hdesc->state >= HARMONY_STATE_READY) { hdesc->errstr = "Descriptor already joined with an existing session"; errno = EINVAL; return -1; } if (hdesc->state == HARMONY_STATE_INIT) { hdesc->socket = tcp_connect(host, port); if (hdesc->socket < 0) { hdesc->errstr = "Error establishing TCP connection with server"; return -1; } if (hdesc->id == NULL) hdesc->id = default_id(hdesc->socket); hdesc->state = HARMONY_STATE_CONNECTED; hdesc->sess.sig.name = stralloc(name); if (!hdesc->sess.sig.name) { hdesc->errstr = "Error allocating memory for signature name"; return -1; } } /* Prepare a Harmony message. */ hmesg_scrub(&hdesc->mesg); hdesc->mesg.data.join = HSIGNATURE_INITIALIZER; if (hsignature_copy(&hdesc->mesg.data.join, &hdesc->sess.sig) < 0) { hdesc->errstr = "Internal error copying signature data"; return -1; } /* send the client registration message */ if (send_request(hdesc, HMESG_JOIN) != 0) return -1; if (hdesc->mesg.status != HMESG_STATUS_OK) { hdesc->errstr = "Invalid message received"; errno = EINVAL; return -1; } hsignature_fini(&hdesc->sess.sig); if (hsignature_copy(&hdesc->sess.sig, &hdesc->mesg.data.join) < 0) { hdesc->errstr = "Error copying received signature structure"; return -1; } /* Apply argv configuration directives now, if necessary. */ if (apply_argv) { for (i = 0; i < hdesc->cmd_len; ++i) { char *key, *val, *cpy; cpy = stralloc(hdesc->cmd[i]); if (hcfg_parse(cpy, &key, &val)) { /* This should never fail, but just in case. */ hdesc->errstr = "Error parsing argv config directive."; return -1; } if (hcfg_set(hdesc->sess.cfg, key, val)) { hdesc->errstr = "Error applying argv config directive."; return -1; } free(cpy); } } cfgval = harmony_getcfg(hdesc, CFGKEY_PERF_COUNT); if (cfgval) { perf_len = atoi(cfgval); if (perf_len < 1) { hdesc->errstr = "Invalid value for " CFGKEY_PERF_COUNT; return -1; } free(cfgval); } else { perf_len = DEFAULT_PERF_COUNT; } hdesc->perf = hperf_alloc(perf_len); if (!hdesc->perf) { hdesc->errstr = "Error allocating performance array."; return -1; } hdesc->state = HARMONY_STATE_READY; return 0; }
int harmony_launch(hdesc_t *hdesc, const char *host, int port) { int i; /* Sanity check input */ if (hdesc->sess.sig.range_len < 1) { hdesc->errstr = "No tuning variables defined"; errno = EINVAL; return -1; } if (!host && !getenv("HARMONY_S_HOST")) { char *path; const char *home; /* Provide a default name, if one isn't defined. */ if (!hdesc->sess.sig.name) { if (hsignature_name(&hdesc->sess.sig, "NONAME")) return -1; } /* Find the Active Harmony installation. */ home = getenv("HARMONY_HOME"); if (!home) { hdesc->errstr = "No host or HARMONY_HOME specified"; return -1; } if (hcfg_set(hdesc->sess.cfg, CFGKEY_HARMONY_HOME, home) != 0) { hdesc->errstr = "Could not set " CFGKEY_HARMONY_HOME; return -1; } /* Fork a local tuning session. */ path = sprintf_alloc("%s/libexec/session-core", home); hdesc->socket = socket_launch(path, NULL, NULL); free(path); } else { hdesc->socket = tcp_connect(host, port); } if (hdesc->socket < 0) { hdesc->errstr = strerror(errno); return -1; } /* Prepare a default client id, if necessary. */ if (hdesc->id == NULL) hdesc->id = default_id(hdesc->socket); hdesc->state = HARMONY_STATE_CONNECTED; /* Apply argv configuration directives now, if necessary. */ for (i = 0; i < hdesc->cmd_len; ++i) { char *key, *val, *cpy; cpy = stralloc(hdesc->cmd[i]); if (hcfg_parse(cpy, &key, &val) == NULL) { /* This should never fail, but just in case. */ hdesc->errstr = "Internal error parsing argv config directive."; return -1; } if (hcfg_set(hdesc->sess.cfg, key, val) != 0) { hdesc->errstr = "Internal error applying argv config directive."; return -1; } free(cpy); } /* Prepare a Harmony message. */ hmesg_scrub(&hdesc->mesg); hsession_init(&hdesc->mesg.data.session); hsession_copy(&hdesc->mesg.data.session, &hdesc->sess); return send_request(hdesc, HMESG_SESSION); }
void hmesg_fini(hmesg_t *mesg) { hmesg_scrub(mesg); free(mesg->buf); }