void test_linux_plpa() { dstring error = DSTRING_INIT; char* topology = NULL; int length = 0; int s, c; struct utsname name; if (uname(&name) != -1) { printf("Your Linux kernel version is: %s\n", name.release); } if (!_has_core_binding(&error)) { printf("Your Linux kernel seems not to offer core binding capabilities for PLPA!\nReason: %s\n", sge_dstring_get_string(&error)); } if (!_has_topology_information()) { printf("No topology information could by retrieved by PLPA!\n"); } else { /* get amount of sockets */ printf("Amount of sockets:\t\t%d\n", get_amount_of_sockets()); /* get amount of cores */ printf("Amount of cores:\t\t%d\n", get_total_amount_of_cores()); /* get topology */ get_topology_linux(&topology, &length); printf("Topology:\t\t\t%s\n", topology); sge_free(&topology); printf("Mapping of logical socket and core numbers to internal\n"); /* for each socket,core pair get the internal processor number */ /* try multi-mapping */ for (s = 0; s < get_amount_of_sockets(); s++) { for (c = 0; c < get_amount_of_cores(s); c++) { int* proc_ids = NULL; int amount = 0; if (get_processor_ids_linux(s, c, &proc_ids, &amount)) { int i = 0; printf("Internal processor ids for socket %5d core %5d: ", s , c); for (i = 0; i < amount; i++) { printf(" %5d", proc_ids[i]); } printf("\n"); sge_free(&proc_ids); } else { printf("Couldn't get processor ids for socket %5d core %5d\n", s, c); } } } } sge_dstring_free(&error); return; }
/****** shepherd_binding/binding_set_striding_linux() ************************************* * NAME * binding_set_striding_linux() -- Binds current process to cores. * * SYNOPSIS * bool binding_set_striding_linux(int first_socket, int first_core, int * amount_of_cores, int offset, int stepsize) * * FUNCTION * Performs a core binding for the calling process according to the * 'striding' strategy. The first core used is specified by first_socket * (beginning with 0) and first_core (beginning with 0). If first_core is * greater than available cores on first_socket, the next socket is examined * and first_core is reduced by the skipped cores. If the first_core could * not be found on system (because it was to high) no binding will be done. * * If the first core was choosen the next one is defined by the step size 'n' * which is incremented to the first core found. If the socket has not the * core (because it was the last core of the socket for example) the next * socket is examined. * * If the system is out of cores and there are still some cores to select * (because of the amount_of_cores parameter) no core binding will be performed. * * INPUTS * int first_socket - first socket to begin with * int first_core - first core to start with * int amount_of_cores - total amount of cores to be used * int offset - core offset for first core (increments first core used) * int stepsize - step size * int type - type of binding (set or env or pe) * * RESULT * bool - Returns true if the binding was performed, otherwise false. * * NOTES * MT-NOTE: binding_set_striding() is MT safe * *******************************************************************************/ bool binding_set_striding_linux(int first_socket, int first_core, int amount_of_cores, int offset, int stepsize, const binding_type_t type) { /* n := take every n-th core */ bool bound = false; dstring error = DSTRING_INIT; if (_has_core_binding(&error) == true) { sge_dstring_free(&error); /* bitmask for processors to turn on and off */ plpa_cpu_set_t cpuset; /* turn off all processors */ PLPA_CPU_ZERO(&cpuset); /* when library offers architecture: - get virtual processor ids in the following manner: * on socket "first_socket" choose core number "first_core + offset" * then add n: if core is not available go to next socket * ... */ if (_has_topology_information()) { /* amount of cores set in processor binding mask */ int cores_set = 0; /* next socket to use */ int next_socket = first_socket; /* next core to use */ int next_core = first_core + offset; /* all the processor ids selected for the mask */ int* proc_id = NULL; int proc_id_size = 0; /* maximal amount of sockets on this system */ int max_amount_of_sockets = get_amount_of_plpa_sockets(); /* check if we are already out of range */ if (next_socket >= max_amount_of_sockets) { shepherd_trace("binding_set_striding_linux: already out of sockets"); return false; } while (get_amount_of_plpa_cores(next_socket) <= next_core) { /* move on to next socket - could be that we have to deal only with cores instead of <socket><core> tuples */ next_core -= get_amount_of_plpa_cores(next_socket); next_socket++; if (next_socket >= max_amount_of_sockets) { /* we are out of sockets - we do nothing */ shepherd_trace("binding_set_striding_linux: first core: out of sockets"); return false; } } add_proc_ids_linux(next_socket, next_core, &proc_id, &proc_id_size); /* turn on processor id in mask */ /* collect the rest of the processor ids */ for (cores_set = 1; cores_set < amount_of_cores; cores_set++) { /* calculate next_core number */ next_core += stepsize; /* check if we are already out of range */ if (next_socket >= max_amount_of_sockets) { shepherd_trace("binding_set_striding_linux: out of sockets"); sge_free(&proc_id); return false; } while (get_amount_of_plpa_cores(next_socket) <= next_core) { /* move on to next socket - could be that we have to deal only with cores instead of <socket><core> tuples */ next_core -= get_amount_of_plpa_cores(next_socket); next_socket++; if (next_socket >= max_amount_of_sockets) { /* we are out of sockets - we do nothing */ shepherd_trace("binding_set_striding_linux: out of sockets!"); sge_free(&proc_id); return false; } } /* add processor ids for core */ add_proc_ids_linux(next_socket, next_core, &proc_id, &proc_id_size); } /* collecting processor ids */ /* set the mask for all processor ids */ set_processor_binding_mask(&cpuset, proc_id, proc_id_size); if (type == BINDING_TYPE_PE) { /* rankfile is created: do nothing */ } else if (type == BINDING_TYPE_ENV) { /* set the environment variable */ if (create_binding_env_linux(proc_id, proc_id_size) == true) { shepherd_trace("binding_set_striding_linux: SGE_BINDING env var created"); } else { shepherd_trace("binding_set_striding_linux: problems while creating SGE_BINDING env"); } } else { /* bind process to mask */ if (bind_process_to_mask((pid_t) 0, cpuset) == true) { /* there was an error while binding */ bound = true; } } sge_free(&proc_id); } else { /* setting bitmask without topology information which could not be right? */ shepherd_trace("binding_set_striding_linux: bitmask without topology information"); return false; } } else { /* has no core binding feature */ sge_dstring_free(&error); return false; } return bound; }
/****** shepherd_binding/binding_set_linear_linux() *************************************** * NAME * binding_set_linear_linux() -- Bind current process linear to chunk of cores. * * SYNOPSIS * bool binding_set_linear(int first_socket, int first_core, int * amount_of_cores, int offset) * * FUNCTION * Binds current process (shepherd) to a set of cores. All processes * started by the current process are inheriting the core binding (Linux). * * The core binding is done in a linear manner, that means that * the process is bound to 'amount_of_cores' cores using one core * after another starting at socket 'first_socket' (usually 0) and * core = 'first_core' (usually 0) + 'offset'. If the core number * is higher than the number of cores which are provided by socket * 'first_socket' then the next socket is taken (the core number * defines how many cores are skiped). * * INPUTS * int first_socket - The first socket (starting at 0) to bind to. * int first_core - The first core to bind. * int amount_of_cores - The amount of cores to bind to. * int offset - The user specified core number offset. * binding_type_t type - The type of binding ONLY FOR EXECD ( set | env | pe ) * * RESULT * bool - true if binding for current process was done, false if not * * NOTES * MT-NOTE: binding_set_linear() is not MT safe * *******************************************************************************/ static bool binding_set_linear_linux(int first_socket, int first_core, int amount_of_cores, int offset, const binding_type_t type) { /* sets bitmask in a linear manner */ /* first core is on exclusive host 0 */ /* first core could be set from scheduler */ /* offset is the first core to start with (make sense only with exclusive host) */ dstring error = DSTRING_INIT; if (_has_core_binding(&error) == true) { sge_dstring_clear(&error); /* bitmask for processors to turn on and off */ plpa_cpu_set_t cpuset; /* turn off all processors */ PLPA_CPU_ZERO(&cpuset); sge_dstring_free(&error); if (_has_topology_information()) { /* amount of cores set in processor binding mask */ int cores_set; /* next socket to use */ int next_socket = first_socket; /* the amount of cores of the next socket */ int socket_amount_of_cores; /* next core to use */ int next_core = first_core + offset; /* all the processor ids selected for the mask */ int* proc_id = NULL; /* size of proc_id array */ int proc_id_size = 0; /* maximal amount of sockets on this system */ int max_amount_of_sockets = get_amount_of_plpa_sockets(); /* strategy: go to the first_socket and the first_core + offset and fill up socket and go to the next one. */ /* TODO maybe better to search for using a core exclusively? */ while (get_amount_of_plpa_cores(next_socket) <= next_core) { /* TODO which kind of warning when first socket does not offer this? */ /* move on to next socket - could be that we have to deal only with cores instead of <socket><core> tuples */ next_core -= get_amount_of_plpa_cores(next_socket); next_socket++; if (next_socket >= max_amount_of_sockets) { /* we are out of sockets - we do nothing */ return false; } } add_proc_ids_linux(next_socket, next_core, &proc_id, &proc_id_size); /* collect the other processor ids with the strategy */ for (cores_set = 1; cores_set < amount_of_cores; cores_set++) { next_core++; /* jump to next socket when it is needed */ /* maybe the next socket could offer 0 cores (I can' see when, but just to be sure) */ while ((socket_amount_of_cores = get_amount_of_plpa_cores(next_socket)) <= next_core) { next_socket++; next_core = next_core - socket_amount_of_cores; if (next_socket >= max_amount_of_sockets) { /* we are out of sockets - we do nothing */ sge_free(&proc_id); return false; } } /* get processor ids */ add_proc_ids_linux(next_socket, next_core, &proc_id, &proc_id_size); } /* set the mask for all processor ids */ set_processor_binding_mask(&cpuset, proc_id, proc_id_size); /* check what to do with the processor ids (set, env or pe) */ if (type == BINDING_TYPE_PE) { /* is done outside */ } else if (type == BINDING_TYPE_ENV) { /* set the environment variable */ /* this does not show up in "environment" file !!! */ if (create_binding_env_linux(proc_id, proc_id_size) == true) { shepherd_trace("binding_set_linear_linux: SGE_BINDING env var created"); } else { shepherd_trace("binding_set_linear_linux: problems while creating SGE_BINDING env"); } } else { /* bind SET process to mask */ if (bind_process_to_mask((pid_t) 0, cpuset) == false) { /* there was an error while binding */ sge_free(&proc_id); return false; } } sge_free(&proc_id); } else { /* TODO DG strategy without topology information but with working library? */ shepherd_trace("binding_set_linear_linux: no information about topology"); return false; } } else { shepherd_trace("binding_set_linear_linux: PLPA binding not supported: %s", sge_dstring_get_string(&error)); sge_dstring_free(&error); } return true; }