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; }
/* * Called after search driver generates a candidate point, but before * that point is returned to the client API. * * This routine should fill the flow variable appropriately and return * 0 upon success. Otherwise, it should call session_error() with a * human-readable error message and return -1. */ int codegen_generate(hflow_t *flow, htrial_t *trial) { int i; i = cglog_find(&trial->point); if (i >= 0) { if (cglog[i].status == CODEGEN_STATUS_COMPLETE) flow->status = HFLOW_ACCEPT; if (cglog[i].status == CODEGEN_STATUS_REQUESTED) flow->status = HFLOW_WAIT; return 0; } if (cglog_insert(&trial->point) != 0) { session_error("Internal error: Could not grow codegen log"); return -1; } mesg = HMESG_INITIALIZER; mesg.type = HMESG_FETCH; mesg.status = HMESG_STATUS_OK; mesg.data.fetch.cand = HPOINT_INITIALIZER; mesg.data.fetch.best = HPOINT_INITIALIZER; hpoint_copy(&mesg.data.fetch.cand, &trial->point); if (mesg_send(sockfd, &mesg) < 1) { session_error( strerror(errno) ); return -1; } flow->status = HFLOW_WAIT; return 0; }
int strategy_best(hpoint_t *point) { if (hpoint_copy(point, &best) != 0) { session_error("Could not copy best point during request for best."); return -1; } return 0; }
/* * Return the best performing point thus far in the search. */ int strategy_best(hpoint_t *point) { if (hpoint_copy(point, &best) != 0) { session_error("Internal error: Could not copy point."); return -1; } return 0; }
int update_best(hdesc_t *hdesc, const hpoint_t *pt) { if (hdesc->best.id >= pt->id) return 0; if (hpoint_copy(&hdesc->best, pt) != 0) { hdesc->errstr = "Internal error copying point data."; errno = EINVAL; return -1; } return 0; }
int cglog_insert(const hpoint_t *point) { if (cglog_len == cglog_cap) if (array_grow(&cglog, &cglog_cap, sizeof(codegen_log_t)) < 0) return -1; cglog[cglog_len].point = HPOINT_INITIALIZER; hpoint_copy(&cglog[cglog_len].point, point); cglog[cglog_len].status = CODEGEN_STATUS_REQUESTED; ++cglog_len; return 0; }
/* * Analyze the observed performance for this configuration point. */ int strategy_analyze(htrial_t *trial) { int i; double perf = hperf_unify(trial->perf); for (i = 0; i < simplex_size; ++i) { if (test->vertex[i]->id == trial->point.id) break; } if (i == simplex_size) { /* Ignore rouge vertex reports. */ return 0; } ++reported; hperf_copy(test->vertex[i]->perf, trial->perf); if (hperf_cmp(test->vertex[i]->perf, test->vertex[best_test]->perf) < 0) best_test = i; if (reported == simplex_size) { if (pro_algorithm() != 0) { session_error("Internal error: PRO algorithm failure."); return -1; } reported = 0; send_idx = 0; } /* Update the best performing point, if necessary. */ if (best_perf > perf) { best_perf = perf; if (hpoint_copy(&best, &trial->point) != 0) { session_error( strerror(errno) ); return -1; } } return 0; }
int strategy_analyze(htrial_t *trial) { // find the relevant subtrial // for now I'm being dumb about searching the window, because it's small int window_entry; for (window_entry = 0; window_entry < window_size; window_entry++) { if (window[window_entry].point_id == trial->point.id) break; } if (window_entry == window_size) // i'm not responsible for this return 0; // indicate that this point is complete window[window_entry].complete = 1; // track global optimum // TODO use hperf_cmp to make this suitable for multi-objective search if (hperf_unify(trial->perf) < best_perf) { if (hpoint_copy(&best, &trial->point) < 0) { session_error("failed to copy new global optimum"); return -1; } best_perf = hperf_unify(trial->perf); window[window_entry].new_best = 1; } // decrement count of outstanding generates requests_outstanding--; // now pass the result to the sub-strategies // We call strategy_analyze from the strategy that generated the point, // and strategy_hint for all other strategies. Their interfaces are // identical, so a new strategy can just define strategy_hint to call // strategy_analyze if it doesn't need to match with a point it's found. int strategy_id, sub_point_id; sub_point_id = translate_id_to_sub(trial->point.id, &strategy_id); if (strategy_id < 0 || strategy_id >= MAX_NUM_STRATEGIES) { session_error("Invalid strategy ID in strategy_analyze."); return -1; } // call "analyze" for originating strategy // have to bend over backwards to respect "const" qualifier on trial->point // while still giving the substrategy the id it expects htrial_t trial_clone; hpoint_t point_clone; if (hpoint_copy(&point_clone, &trial->point) < 0) { session_error("Failed to copy point for substrategy"); return -1; } point_clone.id = sub_point_id; if (hpoint_copy((hpoint_t *)&trial_clone.point, &point_clone) < 0) { session_error("Failed second point copy for substrategy"); return -1; } trial_clone.perf = trial->perf; // pointer copy; any reason to clone? int result = strategies[strategy_id].analyze(&trial_clone); if (result < 0) return -1; // call "hint" for all others int i; for (i = 0; i < strat_count; i++) if (i != strategy_id) { if (strategies[i].hint(trial) < 0) return -1; } return 0; }
/* * Regenerate a point deemed invalid by a later plug-in. */ int strategy_rejected(hflow_t *flow, hpoint_t *point) { int i; hpoint_t *hint = &flow->point; /* Find the rejected vertex. */ for (i = 0; i < simplex_size; ++i) { if (test->vertex[i]->id == point->id) break; } if (i == simplex_size) { session_error("Internal error: Could not find rejected point."); return -1; } if (hint && hint->id != -1) { int orig_id = point->id; /* Update our state to include the hint point. */ if (vertex_from_hpoint(hint, test->vertex[i]) != 0) { session_error("Internal error: Could not make vertex from point."); return -1; } if (hpoint_copy(point, hint) != 0) { session_error("Internal error: Could not copy point."); return -1; } point->id = orig_id; } else { if (reject_type == REJECT_METHOD_PENALTY) { /* Apply an infinite penalty to the invalid point and * allow the algorithm to determine the next point to try. */ hperf_reset(test->vertex[i]->perf); ++reported; if (reported == simplex_size) { if (pro_algorithm() != 0) { session_error("Internal error: PRO algorithm failure."); return -1; } reported = 0; send_idx = 0; i = 0; } if (send_idx == simplex_size) { flow->status = HFLOW_WAIT; return 0; } test->vertex[send_idx]->id = next_id; if (vertex_to_hpoint(test->vertex[send_idx], point) != 0) { session_error("Internal error: Could not make point" " from vertex."); return -1; } ++next_id; ++send_idx; } else if (reject_type == REJECT_METHOD_RANDOM) { /* Replace the rejected point with a random point. */ vertex_rand(test->vertex[i]); if (vertex_to_hpoint(test->vertex[i], point) != 0) { session_error("Internal error: Could not make point" " from vertex."); return -1; } } } flow->status = HFLOW_ACCEPT; return 0; }