Beispiel #1
0
/**
   usage:
   rule [ list inputs ] action [ name ... ] [ work_type ... ]
                             [ target ... ] [ parallelism ... ]
                             [ soft_target ... ]
             keyword args are optional
   DEFAULTS: name=<first token of action plus output list>
             type=TURBINE_ACTION_WORK
             target=TURBINE_RANK_ANY
             parallelism=1
   The name is just for debugging
   soft_target will enable soft targeting mode and specify the target rank
 */
static int
Turbine_Rule_Cmd(ClientData cdata, Tcl_Interp* interp,
                 int objc, Tcl_Obj *const objv[])
{
  const int BASIC_ARGS = 3;
  TCL_CONDITION(objc >= BASIC_ARGS,
                "turbine::c::rule requires at least %i args!",
                BASIC_ARGS);
  int rc;
  int inputs = 0, input_pairs = 0;
  adlb_datum_id input_list[TCL_TURBINE_MAX_INPUTS];
  adlb_datum_id_sub input_pair_list[TCL_TURBINE_MAX_INPUTS];
  char name_buffer[TURBINE_NAME_MAX];

  // Get the action string
  int action_len;
  char* action = Tcl_GetStringFromObj(objv[2], &action_len);
  assert(action);
  action_len++; // Include null terminator

  struct rule_opts opts = {NULL, 0, 0, ADLB_DEFAULT_PUT_OPTS};

  if (objc > BASIC_ARGS)
  {
    // User gave us a list of optional args
    rc = rule_opts_from_list(interp, objv, &opts, objv + BASIC_ARGS,
                             objc - BASIC_ARGS,
                             name_buffer, TURBINE_NAME_MAX, action);
    TCL_CHECK(rc);
  }
  else
  {
    rule_set_opts_default(&opts, action, name_buffer,
                          TURBINE_NAME_MAX);
  }

  // Get the input list - done last so we can report name on error
  rc = turbine_extract_ids(interp, objv, objv[1], TCL_TURBINE_MAX_INPUTS,
              input_list, &inputs, input_pair_list, &input_pairs);
  TCL_CHECK_MSG(rc, "could not parse inputs list as ids or id/subscript "
                "pairs:\n in rule: %s inputs: \"%s\"",
                opts.name, Tcl_GetString(objv[1]));

  opts.opts.priority = ADLB_curr_priority;

  adlb_code ac = ADLB_Dput(action, action_len, opts.target,
        adlb_comm_rank, opts.work_type, opts.opts, opts.name,
        input_list, inputs, input_pair_list, input_pairs);
  TCL_CONDITION(ac == ADLB_SUCCESS, "could not process rule!");

  // Free subscripts that were allocated
  for (int i = 0; i < input_pairs; i++)
  {
    free((void*)input_pair_list[i].subscript.key);
  }
  return TCL_OK;
}
Beispiel #2
0
/*
 * Process worker keyword arguments.
 * Only modifies arguments if the keyword arg was encountered, i.e.
 * caller should initialise the arguments to their default values.
 *
 * This will validate any values received.
 */
static int
worker_keyword_args(Tcl_Interp *interp, Tcl_Obj *const objv[],
                  Tcl_Obj *dict, int *buffer_count, int *buffer_size) {
  int rc;
  Tcl_DictSearch search;
  Tcl_Obj *key_obj, *val_obj;
  int done;

  rc = Tcl_DictObjFirst(interp, dict, &search, &key_obj, &val_obj,
                        &done);
  TCL_CHECK_MSG(rc, "Error iterating over dict: %s",
                Tcl_GetString(dict));

  for (; !done; Tcl_DictObjNext(&search, &key_obj, &val_obj, &done))
  {
    const char *key = Tcl_GetString(key_obj);
    if (strcmp(key, "buffer_count") == 0)
    {
      rc = Tcl_GetIntFromObj(interp, val_obj, buffer_count);
      TCL_CHECK_MSG(rc, "Expected integer value for buffer_count");

      TCL_CONDITION(*buffer_count >= 0, "Positive value for "
            "buffer_count expected, but got %i", *buffer_count);
    }
    else if (strcmp(key, "buffer_size") == 0)
    {
      rc = Tcl_GetIntFromObj(interp, val_obj, buffer_size);
      TCL_CHECK_MSG(rc, "Expected integer value for buffer_size");

      TCL_CONDITION(*buffer_size >= 0, "Positive value for buffer_size "
                                  "expected, but got %i", *buffer_size);
    }
    else
    {
      TCL_RETURN_ERROR("Invalid key for key-value argument: %s\n", key);
      return TCL_ERROR;
    }
  }

  Tcl_DictObjDone(&search);

  return TCL_OK;
}
Beispiel #3
0
/*
  Extract IDs and ID/Sub pairs

  Ownership of subscript memory in id_subs is passed to caller.
 */
static int
turbine_extract_ids(Tcl_Interp* interp, Tcl_Obj *const objv[],
            Tcl_Obj* list, int max,
            adlb_datum_id* ids, int* id_count,
            adlb_datum_id_sub* id_subs, int* id_sub_count)
{
  Tcl_Obj** entry;
  int n;
  int code = Tcl_ListObjGetElements(interp, list, &n, &entry);
  assert(code == TCL_OK);
  TCL_CONDITION(n < max, "Rule IDs exceed supported max: %i > %i",
                n, max);
  for (int i = 0; i < n; i++)
  {
    Tcl_Obj *obj = entry[i];

    // Parse, allocating memory for subscripts
    tcl_adlb_handle handle;
    code = ADLB_PARSE_HANDLE(obj, &handle, false);
    TCL_CHECK_MSG(code, "Error parsing handle %s", Tcl_GetString(obj));
    if (handle.sub.val.key == NULL)
    {
      ids[(*id_count)++] = handle.id;
    }
    else
    {
      adlb_datum_id_sub *pair = &id_subs[(*id_sub_count)++];

      pair->id = handle.id;
      pair->subscript.length = handle.sub.val.length;

      // check if key memory was allocated and owned by us
      if (handle.sub.buf.data == handle.sub.val.key)
      {
        pair->subscript.key = handle.sub.buf.data;
      }
      else
      {
        // Don't own data, alloc and copy
        // TODO: avoid malloc somehow?
        char *tmp_key = malloc(handle.sub.val.length);
        TCL_MALLOC_CHECK(tmp_key);
        memcpy(tmp_key, handle.sub.val.key, handle.sub.val.length);
        pair->subscript.key = tmp_key;
      }
    }
  }
  return TURBINE_SUCCESS;
}
Beispiel #4
0
static int
Python_Eval_Cmd(ClientData cdata, Tcl_Interp *interp,
                int objc, Tcl_Obj *const objv[])
{
  TCL_ARGS(4);
  int rc;
  int persist;
  rc = Tcl_GetBooleanFromObj(interp, objv[1], &persist);
  TCL_CHECK_MSG(rc, "first arg should be integer!");
  char* code = Tcl_GetString(objv[2]);
  char* expression = Tcl_GetString(objv[3]);
  Tcl_Obj* result = NULL;
  rc = python_eval(persist, code, expression, &result);
  TCL_CHECK(rc);
  Tcl_SetObjResult(interp, result);
  return TCL_OK;
}
Beispiel #5
0
/**
   usage turbine::cache_store $td $type [ extra type info ] $value
 */
static int
Turbine_Cache_Store_Cmd(ClientData cdata, Tcl_Interp* interp,
                int objc, Tcl_Obj *const objv[])
{
  TCL_CONDITION(objc >= 4, "requires >= 4 args");

  turbine_datum_id td;
  void* data = NULL;
  size_t length = 0;

  int argpos = 1;
  int error;

  const char *subscript;
  size_t subscript_len;
  error = ADLB_EXTRACT_HANDLE(objv[argpos++], &td, &subscript,
                                  &subscript_len);
  TCL_CHECK(error);

  if (subscript_len != 0)
  {
    // TODO: handle caching subscripts
    return TCL_OK;
  }

  adlb_data_type type;
  adlb_type_extra extra;
  error = adlb_type_from_obj_extra(interp, objv, objv[argpos++], &type,
                              &extra);
  TCL_CHECK(error);

  TCL_CONDITION(argpos < objc, "not enough arguments");
  error = turbine_tclobj2bin(interp, objv, td, type, extra,
                         objv[argpos++], false, &data, &length);
  TCL_CHECK_MSG(error, "object extraction failed: <%"PRId64">", td);

  TCL_CONDITION(argpos == objc, "extra trailing arguments from %i",
                argpos);

  turbine_code rc = turbine_cache_store(td, type, data, length);
  TURBINE_CHECK(rc, "cache store failed: %"PRId64"", td);

  return TCL_OK;
}
Beispiel #6
0
// Allocate a binary buffer and serialize a tcl object into it
//  for the specified ADLB type
static int
turbine_tclobj2bin(Tcl_Interp* interp, Tcl_Obj *const objv[],
               turbine_datum_id td, turbine_type type,
               adlb_type_extra extra, Tcl_Obj* obj,
               bool canonicalize, void** result, size_t* length)
{
  adlb_binary_data data;

  int rc = adlb_tclobj2bin(interp, objv, type, extra, obj, canonicalize,
                          NULL, &data);
  TCL_CHECK_MSG(rc, "failed serializing tcl object to ADLB <%"PRId64">: "
                "\"%s\"", td, Tcl_GetString(obj));

  // Ensure we have ownership of a malloced buffer with the data
  adlb_data_code dc  = ADLB_Own_data(NULL, &data);

  TCL_CONDITION(dc == ADLB_DATA_SUCCESS, "allocating binary buffer for "
        "<%"PRId64"> failed: %s", td, Tcl_GetString(obj));

  assert(data.caller_data != NULL);
  *result = data.caller_data;
  *length = data.length;
  return TCL_OK;
}
Beispiel #7
0
/**
   Translate one key value pair into an opts entry.
   Note that caller is responsible for copying any strings.
 */
static inline int
rule_opt_from_kv(Tcl_Interp* interp, Tcl_Obj *const objv[],
                 struct rule_opts* opts, Tcl_Obj* key, Tcl_Obj* val)
{
  char* k = Tcl_GetString(key);
  int rc;

  switch (k[0])
  {
    case 'a':
      if (strcmp(k, "accuracy") == 0)
      {
        return adlb_parse_accuracy(interp, val, &opts->opts.accuracy);
      }
      break;
    case 'n':
      if (strcmp(k, "name") == 0)
      {
        opts->name = Tcl_GetString(val);
        return TCL_OK;
        // printf("name: %s\n", opts->name);
      }
      break;
    case 'p':
      if (strcmp(k, "parallelism") == 0)
      {
        int t;
        rc = Tcl_GetIntFromObj(interp, val, &t);
        TCL_CHECK_MSG(rc, "parallelism argument must be integer");
        opts->opts.parallelism = t;
        return TCL_OK;
      }
      break;
    case 't':
      if (strcmp(k, "target") == 0)
      {
        int t;
        rc = Tcl_GetIntFromObj(interp, val, &t);
        TCL_CHECK_MSG(rc, "target argument must be integer");
        opts->target = t;

        return TCL_OK;
      }
      else if (strcmp(k, "type") == 0)
      {
        int t;
        rc = Tcl_GetIntFromObj(interp, val, &t);
        TCL_CHECK_MSG(rc, "type argument must be integer");
        if (t == TURBINE_ADLB_WORK_TYPE_LOCAL)
        {
          // Ensure sent back here
          opts->work_type = TURBINE_ADLB_WORK_TYPE_WORK;
          opts->target = adlb_comm_rank;
          opts->opts.strictness = ADLB_TGT_STRICT_HARD;
        }
        else
        {
          opts->work_type = t;
        }
        return TCL_OK;
      }
      break;
    case 's':
      if (strcmp(k, "strictness") == 0)
      {
        return adlb_parse_strictness(interp, val, &opts->opts.strictness);
      }
      break;
  }

  TCL_RETURN_ERROR("rule options: unknown key: %s", k);
  return TCL_ERROR; // unreachable
}