Ejemplo n.º 1
0
static int
Turbine_Init_Cmd(ClientData cdata, Tcl_Interp *interp,
                 int objc, Tcl_Obj *const objv[])
{
  TCL_ARGS(4);
  int amserver, rank, size;

  get_tcl_version();

  int rc;
  rc = Tcl_GetIntFromObj(interp, objv[1], &amserver);
  TCL_CHECK(rc);
  rc = Tcl_GetIntFromObj(interp, objv[2], &rank);
  TCL_CHECK(rc);
  rc = Tcl_GetIntFromObj(interp, objv[3], &size);
  TCL_CHECK(rc);

  turbine_code code = turbine_init(amserver, rank, size);
  if (code != TURBINE_SUCCESS)
  {
    Tcl_AddErrorInfo(interp, " Could not initialize Turbine!\n");
    return TCL_ERROR;
  }

  log_setup(rank);

  return TCL_OK;
}
Ejemplo n.º 2
0
static int
Turbine_Cache_Retrieve_Cmd(ClientData cdata, Tcl_Interp *interp,
                   int objc, Tcl_Obj *const objv[])
{
  TCL_ARGS(2);
  turbine_datum_id td;
  const char *subscript;
  size_t subscript_len;
  int error = ADLB_EXTRACT_HANDLE(objv[1], &td, &subscript,
                                  &subscript_len);
  TCL_CHECK(error);

  // TODO: handle caching subscripts
  TCL_CONDITION(subscript_len == 0, "Don't handle caching subscripts");

  turbine_type type;
  void* data;
  size_t length;
  turbine_code rc = turbine_cache_retrieve(td, &type, &data, &length);
  TURBINE_CHECK(rc, "cache retrieve failed: %"PRId64"", td);

  Tcl_Obj* result = NULL;
  int tcl_code = adlb_datum2tclobj(interp, objv, td, type,
                      ADLB_TYPE_EXTRA_NULL, data, length, &result);
  TCL_CHECK(tcl_code);
  Tcl_SetObjResult(interp, result);
  return TCL_OK;
}
Ejemplo n.º 3
0
/**
   @param persist: If true, retain the Python interpreter,
                   else finalize it
   @param code: The multiline string of Python code.
                The last line is evaluated to the returned result
   @param output: Store result pointer here
   @return Tcl error code
 */
static int
python_eval(bool persist, const char* code, const char* expression,
            Tcl_Obj** output)
{
  int rc;
  char* result = python_result_default;

  // Initialize:
  rc = python_init();
  TCL_CHECK(rc);

  // Execute code:
  DEBUG_TCL_TURBINE("python: code: %s", code);
  PyObject* localDictionary = PyDict_New();
  PyRun_String(code, Py_file_input, main_dict, localDictionary);
  if (PyErr_Occurred()) return handle_python_exception();

  // Evaluate expression:
  DEBUG_TCL_TURBINE("python: expression: %s", expression);
  PyObject* o = PyRun_String(expression, Py_eval_input, main_dict, localDictionary);
  if (o == NULL) return handle_python_exception();

  // Convert Python result to C string, then to Tcl string:
  rc = PyArg_Parse(o, "s", &result);
  if (rc != 1) return handle_python_non_string(o);
  DEBUG_TCL_TURBINE("python: result: %s\n", result);
  *output = Tcl_NewStringObj(result, -1);

  // Clean up and return:
  Py_DECREF(o);
  if (!persist) python_finalize();
  return TCL_OK;
}
Ejemplo n.º 4
0
static int
Turbine_Cache_Check_Cmd(ClientData cdata, Tcl_Interp *interp,
                int objc, Tcl_Obj *const objv[])
{
  TCL_ARGS(2);
  turbine_datum_id td;
  const char *subscript;
  size_t subscript_len;
  int error = ADLB_EXTRACT_HANDLE(objv[1], &td, &subscript,
                                  &subscript_len);
  TCL_CHECK(error);

  bool found;
  if (subscript_len == 0)
  {
    found = turbine_cache_check(td);
  }
  else
  {
    // TODO: handle caching subscripts - currently just ignore
    found = false;
  }

  Tcl_Obj* result = Tcl_NewBooleanObj(found);
  Tcl_SetObjResult(interp, result);
  return TCL_OK;
}
Ejemplo n.º 5
0
/**
  Fill in struct from list

  Note that strings may be filled in with pointers to
  other Tcl data structures.  If these pointers are going to
  escape from the caller into arbitrary Tcl code, the caller
  must make a copy.
   @param interp : just here for error cases
   @param objv : just here for error messages
   @return Tcl error code
 */
static inline int
rule_opts_from_list(Tcl_Interp* interp, Tcl_Obj *const objv[],
                    struct rule_opts* opts,
                    Tcl_Obj *const objs[], int count,
                    char *name_buffer, int name_buffer_size,
                    const char *action)
{
  TCL_CONDITION(count % 2 == 0,
                "Must have matching key-value args, but "
                "found odd number: %i", count);

  rule_set_opts_default(opts, NULL, NULL, 0);

  for (int keypos = 0; keypos < count; keypos+=2)
  {
    int valpos = keypos + 1;
    int rc = rule_opt_from_kv(interp, objv, opts,
                              objs[keypos], objs[valpos]);
    TCL_CHECK(rc);
  }
  if (opts->name == NULL) {
    rule_set_name_default(name_buffer, name_buffer_size, action);
    opts->name = name_buffer;
  }
  return TCL_OK;
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
/*
  turbine::parse_int_impl <string> <base>
  Convert string in any base to wide integer
 */
static int
Turbine_ParseIntImpl_Cmd(ClientData cdata, Tcl_Interp *interp,
                  int objc, Tcl_Obj *const objv[])
{
  TCL_ARGS(3);

  int base;
  int rc = Tcl_GetIntFromObj(interp, objv[2], &base);
  TCL_CHECK(rc);

  TCL_CONDITION(base >= 1, "Base must be positive: %i", base);
  return Turbine_ParseInt_Impl(cdata, interp, objv, objv[1], base);
}
Ejemplo n.º 9
0
/* usage: worker_loop <work type> [<keyword arg dict>]
   Repeatedly run units of work from ADLB of provided type
  Optional key-value arguments:
    buffer_size: size of payload buffer in bytes (must be large enough
                                                   for work units)
 */
static int
Turbine_Worker_Loop_Cmd(ClientData cdata, Tcl_Interp* interp,
                        int objc, Tcl_Obj* const objv[])
{
  TCL_CONDITION(objc == 2 || objc == 3, "Need 1 or 2 arguments");

  int work_type;
  int rc = TCL_OK;
  rc = Tcl_GetIntFromObj(interp, objv[1], &work_type);
  TCL_CHECK(rc);

  int buffer_size = TURBINE_ASYNC_EXEC_DEFAULT_BUFFER_SIZE;

  if (objc >= 3)
  {
    int buffer_count = 1; // Deliberately ignored
    rc = worker_keyword_args(interp, objv, objv[2], &buffer_count,
                             &buffer_size);
    TCL_CHECK(rc);
  }

  // Maintain separate buffer from xfer, since xfer may be
  // used in code that we call.
  void* buffer = malloc((size_t)buffer_size);
  TCL_CONDITION(buffer != NULL, "Out of memory");

  turbine_code code = turbine_worker_loop(interp, buffer, buffer_size,
                                          work_type);
  free(buffer);

  if (code == TURBINE_ERROR_EXTERNAL)
    // turbine_worker_loop() has added the error info
    rc = TCL_ERROR;
  else
    TCL_CONDITION(code == TURBINE_SUCCESS, "Unknown worker error!");
  return rc;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
0
/*
  turbine::coaster_run <executable> <argument list> <infiles>
              <outfiles> <options dict>
              <success callback> <failure callback>
  options dict: optional arguments. Valid keys are:
    stdin/stdout/stderr: redirect output
    job_manager: coaster job manager to use,
                  e.g. "local:slurm" or "local:local"
    staging_mode: staging mode to use
              ("always", "if_present", "on_error", "on_success")
 */
static int
Coaster_Run_Cmd(ClientData cdata, Tcl_Interp *interp,
                  int objc, Tcl_Obj *const objv[])
{
#if HAVE_COASTER == 0
  TCL_CONDITION(false, "Coaster extension not enabled");
  return TCL_ERROR;
#else
  TCL_CONDITION(objc == 8, "Wrong # args: %i", objc - 1);
  turbine_code tc;
  int rc;

  const turbine_executor *coaster_exec;
  bool started;
  coaster_exec = turbine_get_async_exec(COASTER_EXECUTOR_NAME, &started);
  TCL_CONDITION(coaster_exec != NULL, "Coaster executor not registered");
  TCL_CONDITION(started, "Coaster executor not started");
  const char *executable;
  int executable_len;
  executable = Tcl_GetStringFromObj(objv[1], &executable_len);

  int argc, stageinc, stageoutc;
  const char **argv;
  size_t *arg_lens;
  coaster_stage_entry *stageins, *stageouts;

  rc = turbine_tcllist_to_strings(interp, objv, objv[2], &argc, &argv, &arg_lens);
  TCL_CHECK(rc);

  const char *stdin_s = NULL, *stdout_s = NULL, *stderr_s = NULL;
  size_t stdin_slen = 0, stdout_slen = 0, stderr_slen = 0;

  const char *job_manager;
  size_t job_manager_len;
  tc = coaster_default_job_manager(coaster_exec, &job_manager,
                                   &job_manager_len);
  TCL_CONDITION(tc == TURBINE_SUCCESS, "Error getting coaster default "
                                       "job manager");

  coaster_staging_mode staging_mode = COASTER_DEFAULT_STAGING_MODE;

  rc = parse_coaster_opts(interp, objv, objv[5], &stdin_s, &stdin_slen,
            &stdout_s, &stdout_slen, &stderr_s, &stderr_slen,
            &job_manager, &job_manager_len, &staging_mode);
  TCL_CHECK(rc);

  // Parse stages after we know staging mode
  rc = parse_coaster_stages(interp, objv, objv[3], staging_mode,
                    &stageinc, &stageins);
  TCL_CHECK(rc);

  rc = parse_coaster_stages(interp, objv, objv[4], staging_mode,
                    &stageoutc, &stageouts);
  TCL_CHECK(rc);

  turbine_task_callbacks callbacks;
  callbacks.success.code = objv[6];
  callbacks.failure.code = objv[7];

  coaster_job *job;
  coaster_rc crc;

  DEBUG_COASTER("Coaster jobManager: %.*s", (int)job_manager_len,
                 job_manager);
  crc = coaster_job_create(executable, (size_t)executable_len, argc,
                argv, arg_lens, job_manager, job_manager_len, &job);
  TCL_CONDITION(crc == COASTER_SUCCESS, "Error constructing coaster job: "
                "%s", coaster_last_err_info());

  if (stageinc > 0 || stageoutc > 0)
  {
    crc = coaster_job_add_stages(job, stageinc, stageins,
                                stageoutc, stageouts);
    TCL_CONDITION(crc == COASTER_SUCCESS, "Error adding coaster stages: "
                "%s", coaster_last_err_info());
  }

  if (stdin_s != NULL || stdout_s != NULL || stderr_s != NULL)
  {
    crc = coaster_job_set_redirects(job, stdin_s, stdin_slen,
                stdout_s, stdout_slen, stderr_s, stderr_slen);
    TCL_CONDITION(crc == COASTER_SUCCESS, "Error adding coaster stages: "
                "%s", coaster_last_err_info())

  }
Ejemplo n.º 12
0
/*
  turbine::async_exec_worker_loop <executor name> <adlb work type>
                                  [<keyword arg dict>]
  Optional key-value arguments:
    buffer_count: number of payload buffers to allocate
    buffer_size: size of payload buffers in bytes (must be large enough
                                                   for work units)
 */
static int
Async_Exec_Worker_Loop_Cmd(ClientData cdata, Tcl_Interp *interp,
                  int objc, Tcl_Obj *const objv[])
{
  TCL_CONDITION(objc == 3 || objc == 4, "Need 2 or 3 arguments");

  int rc;
  turbine_code tc;

  adlb_payload_buf *bufs = NULL;

  const char *exec_name = Tcl_GetString(objv[1]);

  turbine_executor *exec = turbine_get_async_exec(exec_name, NULL);
  TCL_CONDITION(exec != NULL, "Executor %s not registered", exec_name);

  int adlb_work_type;
  rc = Tcl_GetIntFromObj(interp, objv[2], &adlb_work_type);
  TCL_CHECK(rc);

  int buffer_count = TURBINE_ASYNC_EXEC_DEFAULT_BUFFER_COUNT;
  int buffer_size = TURBINE_ASYNC_EXEC_DEFAULT_BUFFER_SIZE;

  if (objc >= 4)
  {
    DEBUG_TURBINE("Keyword args for %s: %s", exec_name,
                  Tcl_GetString(objv[3]));
    rc = worker_keyword_args(interp, objv, objv[3], &buffer_count,
                             &buffer_size);
    TCL_CHECK(rc);
  }

  DEBUG_TURBINE("Allocating %i buffers of %i bytes each for %s",
                buffer_count, buffer_size, exec_name);

  int max_slots;
  tc = turbine_async_exec_max_slots(interp, exec, &max_slots);
  TCL_CONDITION(tc == TURBINE_SUCCESS, "Executor error in %s getting "
                                       "max slots!", exec_name);

  // Only allocate as many buffers as can be used
  if (max_slots >= 1 && max_slots < buffer_count) {
    buffer_count = max_slots;
  }

  bufs = malloc(sizeof(adlb_payload_buf) *
                                  (size_t)buffer_count);
  TCL_MALLOC_CHECK(bufs);

  // Initialize to allow cleanup
  for (int i = 0; i < buffer_count; i++)
  {
    bufs[i].payload = NULL;
  }

  for (int i = 0; i < buffer_count; i++)
  {
    // Maintain separate buffers from xfer, since xfer may be
    // used in code that we call.

    bufs[i].payload = malloc((size_t)buffer_size);
    TCL_MALLOC_CHECK_GOTO(bufs[i].payload, cleanup);
    bufs[i].size = buffer_size;
  }

  tc = turbine_async_worker_loop(interp, exec, adlb_work_type,
                                  bufs, buffer_count);

  if (tc == TURBINE_ERROR_EXTERNAL)
  {
    // turbine_async_worker_loop() has added the error info
   rc = TCL_ERROR;
   goto cleanup;
  }
  else
  {
    TCL_CONDITION_GOTO(tc == TURBINE_SUCCESS, cleanup,
                       "Unknown worker error!");
  }

  rc = TCL_OK;
cleanup:
  if (bufs != NULL)
  {
    for (int i = 0; i < buffer_count; i++)
    {
      free(bufs[i].payload);
    }
    free(bufs);
  }

  return rc;
}