/** \ingroup m_task_management * \brief Changes the CPU affinity of a computation task. * * When pinning the given task to the first CPU core of the given host, use * 0x01 for the mask value. Each bit of the mask value corresponds to each CPU * core. See taskset(1) on Linux. * * \param task a target task * \param host the host having a multi-core CPU * \param mask the bit mask of a new CPU affinity setting for the task * * * Usage: * 0. Define a host with multiple cores. * \<host id="PM0" power="1E8" core="2"/\> * * 1. Pin a given task to the first CPU core of a host. * MSG_task_set_affinity(task, pm0, 0x01); * * 2. Pin a given task to the third CPU core of a host. Turn on the third bit of the mask. * MSG_task_set_affinity(task, pm0, 0x04); // 0x04 == 100B * * 3. Pin a given VM to the first CPU core of a host. * MSG_vm_set_affinity(vm, pm0, 0x01); * * See examples/msg/cloud/multicore.c for more information. * * * Note: * 1. The current code does not allow an affinity of a task to multiple cores. * The mask value 0x03 (i.e., a given task will be executed on the first core * or the second core) is not allowed. The mask value 0x01 or 0x02 works. See * cpu_cas01.c for details. * * 2. It is recommended to first compare simulation results in both the Lazy * and Full calculation modes (using --cfg=cpu/optim:Full or not). Fix * cpu_cas01.c if you find wrong results in the Lazy mode. * */ void MSG_task_set_affinity(msg_task_t task, msg_host_t host, unsigned long mask) { xbt_assert(task, "Invalid parameter"); xbt_assert(task->simdata, "Invalid parameter"); if (mask == 0) { /* 0 means clear */ { /* We need remove_ext() not throwing exception. */ void *ret = xbt_dict_get_or_null_ext(task->simdata->affinity_mask_db, (char *) host, sizeof(msg_host_t)); if (ret != NULL) xbt_dict_remove_ext(task->simdata->affinity_mask_db, (char *) host, sizeof(host)); } } else xbt_dict_set_ext(task->simdata->affinity_mask_db, (char *) host, sizeof(host), (void *) mask, NULL); /* We set affinity data of this task. If the task is being executed, we * actually change the affinity setting of the task. Otherwise, this change * will be applied when the task is executed. */ if (!task->simdata->compute) { /* task is not yet executed */ XBT_INFO("set affinity(0x%04lx@%s) for %s (not active now)", mask, MSG_host_get_name(host), MSG_task_get_name(task)); return; } { smx_synchro_t compute = task->simdata->compute; msg_host_t host_now = compute->execution.host; // simix_private.h is necessary if (host_now != host) { /* task is not yet executed on this host */ XBT_INFO("set affinity(0x%04lx@%s) for %s (not active now)", mask, MSG_host_get_name(host), MSG_task_get_name(task)); return; } /* task is being executed on this host. so change the affinity now */ { /* check it works. remove me if it works. */ xbt_assert((unsigned long) xbt_dict_get_or_null_ext(task->simdata->affinity_mask_db, (char *) host, sizeof(msg_host_t)) == mask); } XBT_INFO("set affinity(0x%04lx@%s) for %s", mask, MSG_host_get_name(host), MSG_task_get_name(task)); simcall_process_execution_set_affinity(task->simdata->compute, host, mask); } }
static graph_node_map_element_t graph_node_map_search(as_dijkstra_t as, int id) { graph_node_map_element_t elm = (graph_node_map_element_t) xbt_dict_get_or_null_ext(as->graph_node_map, (char *) (&id), sizeof(int)); return elm; }
static void route_new_dijkstra(as_dijkstra_t as, int src_id, int dst_id, sg_platf_route_cbarg_t e_route) { XBT_DEBUG("Load Route from \"%d\" to \"%d\"", src_id, dst_id); xbt_node_t src = NULL; xbt_node_t dst = NULL; graph_node_map_element_t src_elm = (graph_node_map_element_t) xbt_dict_get_or_null_ext(as->graph_node_map, (char *) (&src_id), sizeof(int)); graph_node_map_element_t dst_elm = (graph_node_map_element_t) xbt_dict_get_or_null_ext(as->graph_node_map, (char *) (&dst_id), sizeof(int)); if (src_elm) src = src_elm->node; if (dst_elm) dst = dst_elm->node; /* add nodes if they don't exist in the graph */ if (src_id == dst_id && src == NULL && dst == NULL) { src = route_graph_new_node(as, src_id, -1); dst = src; } else { if (src == NULL) { src = route_graph_new_node(as, src_id, -1); } if (dst == NULL) { dst = route_graph_new_node(as, dst_id, -1); } } /* add link as edge to graph */ xbt_graph_new_edge(as->route_graph, src, dst, e_route); }
void xbt_multidict_set_ext(xbt_dict_t mdict, xbt_dynar_t keys, xbt_dynar_t lens, void *data, void_f_pvoid_t free_ctn) { xbt_dict_t thislevel, nextlevel = NULL; int i; unsigned long int thislen; char *thiskey; int keys_len = xbt_dynar_length(keys); xbt_assert(xbt_dynar_length(keys) == xbt_dynar_length(lens)); xbt_assert(keys_len, "Can't set a zero-long key set in a multidict"); XBT_DEBUG("xbt_multidict_set(%p,%d)", mdict, keys_len); for (i = 0, thislevel = mdict; i < keys_len - 1; i++, thislevel = nextlevel) { xbt_dynar_get_cpy(keys, i, &thiskey); xbt_dynar_get_cpy(lens, i, &thislen); XBT_DEBUG("multi_set: at level %d, len=%ld, key=%p |%*s|", i, thislen, thiskey, (int) thislen, thiskey); /* search the dict of next level */ nextlevel = xbt_dict_get_or_null_ext(thislevel, thiskey, thislen); if (nextlevel == NULL) { /* make sure the dict of next level exists */ nextlevel = xbt_dict_new(); XBT_VERB("Create a dict (%p)", nextlevel); xbt_dict_set_ext(thislevel, thiskey, thislen, nextlevel, &_free_dict); } } xbt_dynar_get_cpy(keys, i, &thiskey); xbt_dynar_get_cpy(lens, i, &thislen); xbt_dict_set_ext(thislevel, thiskey, thislen, data, free_ctn); }
/** * \brief Retrieve data from the dict (key considered as a uintptr_t) * * \param dict the dealer of data * \param key the key to find data * \return the data that we are looking for (or 0 if not found) * * Mixing uintptr_t keys with regular keys in the same dict is discouraged */ XBT_INLINE uintptr_t xbt_dicti_get(xbt_dict_t dict, uintptr_t key) { return (uintptr_t)xbt_dict_get_or_null_ext(dict, (void *)&key, sizeof key); }
/** \ingroup msg_task_usage * \brief Executes a parallel task and waits for its termination. * * \param task a #msg_task_t to execute on the location on which the process is running. * * \return #MSG_OK if the task was successfully completed, #MSG_TASK_CANCELED * or #MSG_HOST_FAILURE otherwise */ msg_error_t MSG_parallel_task_execute(msg_task_t task) { xbt_ex_t e; simdata_task_t simdata = task->simdata; msg_process_t self = SIMIX_process_self(); simdata_process_t p_simdata = SIMIX_process_self_get_data(self); e_smx_state_t comp_state; msg_error_t status = MSG_OK; TRACE_msg_task_execute_start(task); xbt_assert((!simdata->compute) && (task->simdata->isused == 0), "This task is executed somewhere else. Go fix your code! %d", task->simdata->isused!=NULL); XBT_DEBUG("Computing on %s", MSG_process_get_name(MSG_process_self())); if (simdata->flops_amount == 0 && !simdata->host_nb) { TRACE_msg_task_execute_end(task); return MSG_OK; } TRY { if (msg_global->debug_multiple_use) MSG_BT(simdata->isused, "Using Backtrace"); else simdata->isused = (void*)1; if (simdata->host_nb > 0) { simdata->compute = simcall_process_parallel_execute(task->name, simdata->host_nb, simdata->host_list, simdata->flops_parallel_amount, simdata->bytes_parallel_amount, 1.0, -1.0); XBT_DEBUG("Parallel execution action created: %p", simdata->compute); } else { unsigned long affinity_mask = (unsigned long) xbt_dict_get_or_null_ext(simdata->affinity_mask_db, (char *) p_simdata->m_host, sizeof(msg_host_t)); XBT_DEBUG("execute %s@%s with affinity(0x%04lx)", MSG_task_get_name(task), MSG_host_get_name(p_simdata->m_host), affinity_mask); simdata->compute = simcall_process_execute(task->name, simdata->flops_amount, simdata->priority, simdata->bound, affinity_mask ); } simcall_set_category(simdata->compute, task->category); p_simdata->waiting_action = simdata->compute; comp_state = simcall_process_execution_wait(simdata->compute); p_simdata->waiting_action = NULL; if (msg_global->debug_multiple_use && simdata->isused!=0) xbt_ex_free(*(xbt_ex_t*)simdata->isused); simdata->isused = 0; XBT_DEBUG("Execution task '%s' finished in state %d", task->name, (int)comp_state); } CATCH(e) { switch (e.category) { case cancel_error: status = MSG_TASK_CANCELED; break; case host_error: status = MSG_HOST_FAILURE; break; default: RETHROW; } xbt_ex_free(e); } /* action ended, set comm and compute = NULL, the actions is already destroyed * in the main function */ simdata->flops_amount = 0.0; simdata->comm = NULL; simdata->compute = NULL; TRACE_msg_task_execute_end(task); MSG_RETURN(status); }
void AsDijkstra::getRouteAndLatency(NetCard *src, NetCard *dst, sg_platf_route_cbarg_t route, double *lat) { getRouteCheckParams(src, dst); int src_id = src->id(); int dst_id = dst->id(); int *pred_arr = nullptr; sg_platf_route_cbarg_t e_route; int size = 0; xbt_dynar_t nodes = xbt_graph_get_nodes(routeGraph_); /* Use the graph_node id mapping set to quickly find the nodes */ graph_node_map_element_t src_elm = nodeMapSearch(src_id); graph_node_map_element_t dst_elm = nodeMapSearch(dst_id); int src_node_id = ((graph_node_data_t) xbt_graph_node_get_data(src_elm->node))->graph_id; int dst_node_id = ((graph_node_data_t) xbt_graph_node_get_data(dst_elm->node))->graph_id; /* if the src and dst are the same */ if (src_node_id == dst_node_id) { xbt_node_t node_s_v = xbt_dynar_get_as(nodes, src_node_id, xbt_node_t); xbt_node_t node_e_v = xbt_dynar_get_as(nodes, dst_node_id, xbt_node_t); xbt_edge_t edge = xbt_graph_get_edge(routeGraph_, node_s_v, node_e_v); if (edge == nullptr) THROWF(arg_error, 0, "No route from '%s' to '%s'", src->name(), dst->name()); e_route = (sg_platf_route_cbarg_t) xbt_graph_edge_get_data(edge); for (auto link: *e_route->link_list) { route->link_list->insert(route->link_list->begin(), link); if (lat) *lat += static_cast<Link*>(link)->getLatency(); } } route_cache_element_t elm = nullptr; if (routeCache_) { /* cache mode */ elm = (route_cache_element_t) xbt_dict_get_or_null_ext(routeCache_, (char *) (&src_id), sizeof(int)); } if (elm) { /* cached mode and cache hit */ pred_arr = elm->pred_arr; } else { /* not cached mode, or cache miss */ int nr_nodes = xbt_dynar_length(nodes); double * cost_arr = xbt_new0(double, nr_nodes); /* link cost from src to other hosts */ pred_arr = xbt_new0(int, nr_nodes); /* predecessors in path from src */ xbt_heap_t pqueue = xbt_heap_new(nr_nodes, xbt_free_f); /* initialize */ cost_arr[src_node_id] = 0.0; for (int i = 0; i < nr_nodes; i++) { if (i != src_node_id) { cost_arr[i] = DBL_MAX; } pred_arr[i] = 0; /* initialize priority queue */ int *nodeid = xbt_new0(int, 1); *nodeid = i; xbt_heap_push(pqueue, nodeid, cost_arr[i]); } /* apply dijkstra using the indexes from the graph's node array */ while (xbt_heap_size(pqueue) > 0) { int *v_id = (int *) xbt_heap_pop(pqueue); xbt_node_t v_node = xbt_dynar_get_as(nodes, *v_id, xbt_node_t); xbt_edge_t edge = nullptr; unsigned int cursor; xbt_dynar_foreach(xbt_graph_node_get_outedges(v_node), cursor, edge) { xbt_node_t u_node = xbt_graph_edge_get_target(edge); graph_node_data_t data = (graph_node_data_t) xbt_graph_node_get_data(u_node); int u_id = data->graph_id; sg_platf_route_cbarg_t tmp_e_route = (sg_platf_route_cbarg_t) xbt_graph_edge_get_data(edge); int cost_v_u = tmp_e_route->link_list->size(); /* count of links, old model assume 1 */ if (cost_v_u + cost_arr[*v_id] < cost_arr[u_id]) { pred_arr[u_id] = *v_id; cost_arr[u_id] = cost_v_u + cost_arr[*v_id]; int *nodeid = xbt_new0(int, 1); *nodeid = u_id; xbt_heap_push(pqueue, nodeid, cost_arr[u_id]); } } /* free item popped from pqueue */ xbt_free(v_id); }
graph_node_map_element_t AsDijkstra::nodeMapSearch(int id) { return (graph_node_map_element_t)xbt_dict_get_or_null_ext(graphNodeMap_, (char *) (&id), sizeof(int)); }
/** \ingroup msg_task_usage * \brief Executes a parallel task and waits for its termination. * * \param task a #msg_task_t to execute on the location on which the process is running. * * \return #MSG_OK if the task was successfully completed, #MSG_TASK_CANCELED * or #MSG_HOST_FAILURE otherwise */ msg_error_t MSG_parallel_task_execute(msg_task_t task) { simdata_task_t simdata = task->simdata; simdata_process_t p_simdata = (simdata_process_t) SIMIX_process_self_get_data(); e_smx_state_t comp_state; msg_error_t status = MSG_OK; TRACE_msg_task_execute_start(task); xbt_assert((!simdata->compute) && !task->simdata->isused, "This task is executed somewhere else. Go fix your code!"); XBT_DEBUG("Computing on %s", MSG_process_get_name(MSG_process_self())); if (simdata->flops_amount == 0 && !simdata->host_nb) { TRACE_msg_task_execute_end(task); return MSG_OK; } try { simdata->setUsed(); if (simdata->host_nb > 0) { simdata->compute = static_cast<simgrid::simix::Exec*>( simcall_execution_parallel_start(task->name, simdata->host_nb,simdata->host_list, simdata->flops_parallel_amount, simdata->bytes_parallel_amount, 1.0, -1.0)); XBT_DEBUG("Parallel execution action created: %p", simdata->compute); } else { unsigned long affinity_mask = (unsigned long)(uintptr_t) xbt_dict_get_or_null_ext(simdata->affinity_mask_db, (char *) p_simdata->m_host, sizeof(msg_host_t)); XBT_DEBUG("execute %s@%s with affinity(0x%04lx)", MSG_task_get_name(task), MSG_host_get_name(p_simdata->m_host), affinity_mask); simdata->compute = static_cast<simgrid::simix::Exec*>( simcall_execution_start(task->name, simdata->flops_amount, simdata->priority, simdata->bound, affinity_mask)); } simcall_set_category(simdata->compute, task->category); p_simdata->waiting_action = simdata->compute; comp_state = simcall_execution_wait(simdata->compute); p_simdata->waiting_action = nullptr; simdata->setNotUsed(); XBT_DEBUG("Execution task '%s' finished in state %d", task->name, (int)comp_state); } catch (xbt_ex& e) { switch (e.category) { case cancel_error: status = MSG_TASK_CANCELED; break; case host_error: status = MSG_HOST_FAILURE; break; default: throw; } } /* action ended, set comm and compute = nullptr, the actions is already destroyed in the main function */ simdata->flops_amount = 0.0; simdata->comm = nullptr; simdata->compute = nullptr; TRACE_msg_task_execute_end(task); MSG_RETURN(status); }
/** @brief Replaces a set of variables by their values * * @param b buffer to modify * @param patterns variables to substitute in the buffer * * Both '$toto' and '${toto}' are valid (and the two writing are equivalent). * * If the variable name contains spaces, use the brace version (ie, ${toto tutu}) * * You can provide a default value to use if the variable is not set in the dict by using * '${var:=default}' or '${var:-default}'. These two forms are equivalent, even if they * shouldn't to respect the shell standard (:= form should set the value in the dict, * but does not) (BUG). */ void xbt_strbuff_varsubst(xbt_strbuff_t b, xbt_dict_t patterns) { char *end; /* pointers around the parsed chunk */ int in_simple_quote = 0, in_double_quote = 0; int done = 0; if (b->data[0] == '\0') return; end = b->data; while (!done) { switch (*end) { case '\\': /* Protected char; pass the protection */ end++; if (*end == '\0') THROWF(arg_error, 0, "String ends with \\"); break; case '\'': if (!in_double_quote) { /* simple quote not protected by double ones, note it */ in_simple_quote = !in_simple_quote; } break; case '"': if (!in_simple_quote) { /* double quote protected by simple ones, note it */ in_double_quote = !in_double_quote; } break; case '$': if (!in_simple_quote) { /* Go for the substitution. First search the variable name */ char *beg_var, *end_var; /* variable name boundary */ char *beg_subst, *end_subst = NULL; /* where value should be written to */ char *value, *default_value = NULL; int val_len; beg_subst = end; if (*(++end) == '{') { /* the variable name is enclosed in braces. */ beg_var = end + 1; /* Search name's end */ end_var = beg_var; while (*end_var != '\0' && *end_var != '}') { /* TODO: we do not respect the standard for ":=", we should set this value in the dict */ if (*end_var == ':' && ((*(end_var + 1) == '=') || (*(end_var + 1) == '-'))) { /* damn, we have a default value */ char *p = end_var + 1; while (*p != '\0' && *p != '}') p++; if (*p == '\0') THROWF(arg_error, 0, "Variable default value not terminated ('}' missing)"); default_value = xbt_malloc(p - end_var - 1); memcpy(default_value, end_var + 2, p - end_var - 2); default_value[p - end_var - 2] = '\0'; end_subst = p + 1; /* eat '}' */ break; } end_var++; } if (*end_var == '\0') THROWF(arg_error, 0, "Variable name not terminated ('}' missing)"); if (!end_subst) /* already set if there's a default value */ end_subst = end_var + 1; /* also kill the } in the name */ if (end_var == beg_var) THROWF(arg_error, 0, "Variable name empty (${} is not valid)"); } else { /* name given directly */ beg_var = end; end_var = beg_var; while (*end_var != '\0' && *end_var != ' ' && *end_var != '\t' && *end_var != '\n') end_var++; end_subst = end_var; if (end_var == beg_var) THROWF(arg_error, 0, "Variable name empty ($ is not valid)"); } /* XBT_DEBUG("var='%.*s'; subst='%.*s'; End_var = '%s'", end_var-beg_var,beg_var, end_subst-beg_subst,beg_subst, end_var);*/ /* ok, we now have the variable name. Search the dictionary for the substituted value */ value = xbt_dict_get_or_null_ext(patterns, beg_var, end_var - beg_var); /* XBT_DEBUG("Deal with '%s'",b->data); XBT_DEBUG("Search for %.*s, found %s (default value = %s)\n", end_var-beg_var,beg_var, (value?value:"(no value)"), (default_value?default_value:"(no value)"));*/ if (value) value = xbt_strdup(value); else if (default_value) value = xbt_strdup(default_value); else value = xbt_strdup(""); /* En route for the actual substitution */ val_len = strlen(value); // XBT_DEBUG("val_len = %d, key_len=%d",val_len,end_subst-beg_subst); if (val_len <= end_subst - beg_subst) { /* enough room to do the substitute in place */ // XBT_DEBUG("Substitute key name by its value: ie '%.*s' by '%.*s'",end_subst-beg_subst,beg_subst,val_len,value); memmove(beg_subst, value, val_len); /* substitute */ // XBT_DEBUG("String is now: '%s'",b->data); /* XBT_DEBUG("Move end of string closer (%d chars moved) :\n-'%.*s%.*s'\n+'%.*s%s'", b->used - (end_subst - b->data) + 1, beg_subst-b->data,b->data, b->used-(end_subst-b->data)+1,beg_subst+val_len, beg_subst-b->data,b->data, end_subst);*/ memmove(beg_subst + val_len, end_subst, b->used - (end_subst - b->data) + 1); /* move the end of the string closer */ // XBT_DEBUG("String is now: '%s'",b->data); end = beg_subst + val_len; /* update the currently explored char in the overall loop */ // XBT_DEBUG("end of substituted section is now '%s'",end); b->used -= end_subst - beg_subst - val_len; /* update string buffer used size */ // XBT_DEBUG("Used:%d end:%d ending char:%d",b->used,end-b->data,*end); } else { /* we have to extend the data area */ int tooshort = val_len - (end_subst - beg_subst) + 1 /*don't forget \0 */ ; int newused = b->used + tooshort; end += tooshort; /* update the pointer of the overall loop */ // XBT_DEBUG("Too short (by %d chars; %d chars left in area)",val_len- (end_subst-beg_subst), b->size - b->used); if (newused > b->size) { /* We have to realloc the data area before (because b->size is too small). We have to update our pointers, too */ char *newdata = realloc(b->data, b->used + MAX(minimal_increment, tooshort)); int offset = newdata - b->data; b->data = newdata; b->size = b->used + MAX(minimal_increment, tooshort); end += offset; beg_subst += offset; end_subst += offset; } memmove(beg_subst + val_len, end_subst, b->used - (end_subst - b->data) + 1); /* move the end of the string a bit further */ memmove(beg_subst, value, val_len); /* substitute */ b->used = newused; // XBT_DEBUG("String is now: %s",b->data); } free(value); free(default_value); end--; /* compensate the next end++ */ } break; case '\0': done = 1; } end++; } }