Esempio n. 1
0
/*
 * Tests for correct handling of -m and --socket-mem flags
 */
static int
test_memory_flags(void)
{
#ifdef RTE_EXEC_ENV_BSDAPP
	/* BSD target doesn't support prefixes at this point */
	const char * prefix = "";
#else
	char prefix[PATH_MAX], tmp[PATH_MAX];
	if (get_current_prefix(tmp, sizeof(tmp)) == NULL) {
		printf("Error - unable to get current prefix!\n");
		return -1;
	}
	snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp);
#endif

	/* valid -m flag and mp flag */
	const char *argv0[] = {prgname, prefix, mp_flag, "-c", "10",
			"-n", "2", "-m", DEFAULT_MEM_SIZE};

	/* valid -m flag */
	const char *argv1[] = {prgname, "-c", "10", "-n", "2",
			"--file-prefix=" memtest, "-m", DEFAULT_MEM_SIZE};

	/* invalid (zero) --socket-mem flag */
	const char *argv2[] = {prgname, "-c", "10", "-n", "2",
			"--file-prefix=" memtest, "--socket-mem=0,0,0,0"};

	/* invalid (incomplete) --socket-mem flag */
	const char *argv3[] = {prgname, "-c", "10", "-n", "2",
			"--file-prefix=" memtest, "--socket-mem=2,2,"};

	/* invalid (mixed with invalid data) --socket-mem flag */
	const char *argv4[] = {prgname, "-c", "10", "-n", "2",
			"--file-prefix=" memtest, "--socket-mem=2,2,Fred"};

	/* invalid (with numeric value as last character) --socket-mem flag */
	const char *argv5[] = {prgname, "-c", "10", "-n", "2",
			"--file-prefix=" memtest, "--socket-mem=2,2,Fred0"};

	/* invalid (with empty socket) --socket-mem flag */
	const char *argv6[] = {prgname, "-c", "10", "-n", "2",
			"--file-prefix=" memtest, "--socket-mem=2,,2"};

	/* invalid (null) --socket-mem flag */
	const char *argv7[] = {prgname, "-c", "10", "-n", "2",
			"--file-prefix=" memtest, "--socket-mem="};

	/* valid --socket-mem specified together with -m flag */
	const char *argv8[] = {prgname, "-c", "10", "-n", "2",
			"--file-prefix=" memtest, "-m", DEFAULT_MEM_SIZE, "--socket-mem=2,2"};

	/* construct an invalid socket mask with 2 megs on each socket plus
	 * extra 2 megs on socket that doesn't exist on current system */
	char invalid_socket_mem[SOCKET_MEM_STRLEN];
	char buf[SOCKET_MEM_STRLEN];	/* to avoid copying string onto itself */

#ifdef RTE_EXEC_ENV_BSDAPP
	int i, num_sockets = 1;
#else
	int i, num_sockets = get_number_of_sockets();
#endif

	if (num_sockets <= 0 || num_sockets > RTE_MAX_NUMA_NODES) {
		printf("Error - cannot get number of sockets!\n");
		return -1;
	}

	snprintf(invalid_socket_mem, sizeof(invalid_socket_mem), "--socket-mem=");

	/* add one extra socket */
	for (i = 0; i < num_sockets + 1; i++) {
		snprintf(buf, sizeof(buf), "%s%s", invalid_socket_mem, DEFAULT_MEM_SIZE);
		snprintf(invalid_socket_mem, sizeof(invalid_socket_mem), "%s", buf);

		if (num_sockets + 1 - i > 1) {
			snprintf(buf, sizeof(buf), "%s,", invalid_socket_mem);
			snprintf(invalid_socket_mem, sizeof(invalid_socket_mem), "%s", buf);
		}
	}

	/* construct a valid socket mask with 2 megs on each existing socket */
	char valid_socket_mem[SOCKET_MEM_STRLEN];

	snprintf(valid_socket_mem, sizeof(valid_socket_mem), "--socket-mem=");

	/* add one extra socket */
	for (i = 0; i < num_sockets; i++) {
		snprintf(buf, sizeof(buf), "%s%s", valid_socket_mem, DEFAULT_MEM_SIZE);
		snprintf(valid_socket_mem, sizeof(valid_socket_mem), "%s", buf);

		if (num_sockets - i > 1) {
			snprintf(buf, sizeof(buf), "%s,", valid_socket_mem);
			snprintf(valid_socket_mem, sizeof(valid_socket_mem), "%s", buf);
		}
	}

	/* invalid --socket-mem flag (with extra socket) */
	const char *argv9[] = {prgname, "-c", "10", "-n", "2",
			"--file-prefix=" memtest, invalid_socket_mem};

	/* valid --socket-mem flag */
	const char *argv10[] = {prgname, "-c", "10", "-n", "2",
			"--file-prefix=" memtest, valid_socket_mem};

	if (launch_proc(argv0) != 0) {
		printf("Error - secondary process failed with valid -m flag !\n");
		return -1;
	}

#ifdef RTE_EXEC_ENV_BSDAPP
	/* no other tests are applicable to BSD */
	return 0;
#endif

	if (launch_proc(argv1) != 0) {
		printf("Error - process failed with valid -m flag!\n");
		return -1;
	}
#ifdef RTE_LIBRTE_XEN_DOM0
	return 0;
#endif
	if (launch_proc(argv2) == 0) {
		printf("Error - process run ok with invalid (zero) --socket-mem!\n");
		return -1;
	}

	if (launch_proc(argv3) == 0) {
		printf("Error - process run ok with invalid "
				"(incomplete) --socket-mem!\n");
		return -1;
	}

	if (launch_proc(argv4) == 0) {
		printf("Error - process run ok with invalid "
				"(mixed with invalid input) --socket-mem!\n");
		return -1;
	}

	if (launch_proc(argv5) == 0) {
		printf("Error - process run ok with invalid "
				"(mixed with invalid input with a numeric value as "
				"last character) --socket-mem!\n");
		return -1;
	}

	if (launch_proc(argv6) == 0) {
		printf("Error - process run ok with invalid "
				"(with empty socket) --socket-mem!\n");
		return -1;
	}

	if (launch_proc(argv7) == 0) {
		printf("Error - process run ok with invalid (null) --socket-mem!\n");
		return -1;
	}

	if (launch_proc(argv8) == 0) {
		printf("Error - process run ok with --socket-mem and -m specified!\n");
		return -1;
	}

	if (launch_proc(argv9) == 0) {
		printf("Error - process run ok with extra socket in --socket-mem!\n");
		return -1;
	}

	if (launch_proc(argv10) != 0) {
		printf("Error - process failed with valid --socket-mem!\n");
		return -1;
	}

	return 0;
}
/****** shepherd_binding/binding_set_striding() *************************************
*  NAME
*     binding_set_striding() -- Binds current process to cores.
*
*  SYNOPSIS
*     bool binding_set_striding(int first_socket, int first_core, int
*     number_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 number_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 number_of_cores - total number 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 
*
*******************************************************************************/
static bool
binding_set_striding(int first_socket, int first_core, int number_of_cores,
                          int offset, int stepsize, const binding_type_t type)
{
   /* n := take every n-th core */ 
   bool bound = false;

#if HAVE_HWLOC
   dstring error = DSTRING_INIT;

   if (has_core_binding() == true) {

      sge_dstring_free(&error);

         /* bitmask for processors to turn on and off */
         hwloc_bitmap_t cpuset = hwloc_bitmap_alloc();

         /* 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()) {
            /* number 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;
            /* maximal number of sockets on this system */
            int max_number_of_sockets = get_number_of_sockets();
            hwloc_obj_t core;
            
            /* check if we are already out of range */
            if (next_socket >= max_number_of_sockets) {
               shepherd_trace("binding_set_striding: already out of sockets");
               hwloc_bitmap_free(cpuset);
               return false;
            }   

            while (get_number_of_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_number_of_cores(next_socket);
               next_socket++;
               if (next_socket >= max_number_of_sockets) {
                  /* we are out of sockets - we do nothing */
                  shepherd_trace("binding_set_striding: first core: out of sockets");
                  hwloc_bitmap_free(cpuset);
                  return false;
               }
            }  
            core = hwloc_get_obj_below_by_type(sge_hwloc_topology,
                                               HWLOC_OBJ_SOCKET, next_socket,
                                               HWLOC_OBJ_CORE, next_core);
            hwloc_bitmap_or(cpuset, cpuset, core->cpuset);
            
            /* collect the rest of the processor ids */ 
            for (cores_set = 1; cores_set < number_of_cores; cores_set++) {
               /* calculate next_core number */ 
               next_core += stepsize;
               
               /* check if we are already out of range */
               if (next_socket >= max_number_of_sockets) {
                  shepherd_trace("binding_set_striding: out of sockets");
                  hwloc_bitmap_free(cpuset);
                  return false;
               }   

               while (get_number_of_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_number_of_cores(next_socket);
                  next_socket++;
                  if (next_socket >= max_number_of_sockets) {
                     /* we are out of sockets - we do nothing */
                     shepherd_trace("binding_set_striding: out of sockets!");
                     hwloc_bitmap_free(cpuset);
                     return false;
                  }
                  core = hwloc_get_obj_below_by_type(sge_hwloc_topology,
                                                     HWLOC_OBJ_SOCKET,
                                                     next_socket,
                                                     HWLOC_OBJ_CORE,
                                                     next_core);
                  hwloc_bitmap_or(cpuset, cpuset, core->cpuset);
               }    
                
            } /* collecting processor ids */
           
            if (type == BINDING_TYPE_PE) {
            
               /* rankfile is created: do nothing */

            } else if (type == BINDING_TYPE_ENV) {

               /* set the environment variable */
               if (create_binding_env(cpuset) == true) {
                  shepherd_trace("binding_set_striding: SGE_BINDING env var created");
               } else {
                  shepherd_trace("binding_set_striding: problems while creating SGE_BINDING env");
               }

            } else {
               
               /* bind process to mask */ 
               if (bind_process_to_mask(cpuset) == true) {
                  /* there was an error while binding */ 
                  bound = true;
               }
            }
         
            hwloc_bitmap_free(cpuset);
            
         } else {
            /* setting bitmask without topology information which could 
               not be right? */
            shepherd_trace("binding_set_striding: bitmask without topology information");
            return false;
         }

   } else {
      /* has no core binding feature */
      sge_dstring_free(&error);
      
      return false;
   }
   
#endif  /* HAVE_HWLOC */
   return bound;
}
/****** binding_support/get_topology() ***********************************
*  NAME
*     get_topology() -- Creates the topology string for the current host.
*
*  SYNOPSIS
*     bool get_topology(char** topology, int* length)
*
*  FUNCTION
*     Creates the topology string for the current host. When created,
*     it has to be freed from outside.
*
*  INPUTS
*     char** topology - The topology string for the current host.
*     int* length     - The length of the topology string.
*
*  RESULT
*     bool - when true the topology string could be generated (and memory
*            is allocated otherwise false
*
*  NOTES
*     MT-NOTE: get_topology() is MT safe
*
*******************************************************************************/
bool get_topology(char** topology, int* length)
{
   bool success = false;

   if (HAVE_HWLOC) {
   /* initialize length of topology string */
   (*length) = 0;

   /* check if topology is supported via hwloc */
   if (has_topology_information()) {
      int num_sockets;

      /* topology string */
      dstring d_topology = DSTRING_INIT;

      /* build the topology string */
      if ((num_sockets = get_number_of_sockets())) {
         int num_cores, ctr_cores, ctr_sockets, ctr_threads;
         char* s = "S"; /* socket */
         char* c = "C"; /* core   */
         char* t = "T"; /* thread */

         for (ctr_sockets = 0; ctr_sockets < num_sockets; ctr_sockets++) {

            /* append new socket */
            sge_dstring_append_char(&d_topology, *s);
            (*length)++;

            /* for each socket get the number of cores */
            if ((num_cores = get_number_of_cores(ctr_sockets))) {
               /* for thread counting */
               int* proc_ids = NULL;
               int number_of_threads = 0;

               /* check each core */
               for (ctr_cores = 0; ctr_cores < num_cores; ctr_cores++) {
                  sge_dstring_append_char(&d_topology, *c);
                  (*length)++;
                  /* check if the core has threads */
                  if (get_processor_ids(ctr_sockets, ctr_cores, &proc_ids,
                                        &number_of_threads)
                        && number_of_threads > 1) {
                     /* print the threads */
                     for (ctr_threads = 0; ctr_threads < number_of_threads;
                          ctr_threads++) {
                        sge_dstring_append_char(&d_topology, *t);
                        (*length)++;
                     }
                  }
                  sge_free(&proc_ids);
               }
            }
         } /* for each socket */

         if ((*length) != 0) {
            /* convert d_topolgy into topology */
            (*length)++; /* we need `\0` at the end */

            /* copy element */
            (*topology) = sge_strdup(NULL, sge_dstring_get_string(&d_topology));
            success = true;
         }

         sge_dstring_free(&d_topology);
      }

   }
   }
   return success;
}
/****** shepherd_binding/binding_set_linear() ***************************************
*  NAME
*     binding_set_linear() -- Bind current process linear to chunk of cores.
*
*  SYNOPSIS
*     bool binding_set_linear(int first_socket, int first_core, int 
*     number_of_cores, int offset)
*
*  FUNCTION
*     Binds current process (shepherd) to a set of cores. All processes 
*     started by the current process inherit the core binding.
*     
*     The core binding is done in a linear manner, that means that 
*     the process is bound to 'number_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 number_of_cores - The number_of_cores 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(int first_socket, int first_core,
               int number_of_cores, int offset, const binding_type_t type)
{

#if HAVE_HWLOC
   /* 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 (makes sense only with
      exclusive host) */
   dstring error = DSTRING_INIT;

   if (has_core_binding() == true) {
      /* bitmask for processors to turn on and off */
      hwloc_bitmap_t cpuset = hwloc_bitmap_alloc();
         
      if (has_topology_information()) {
         /* number of cores set in processor binding mask */
         int cores_set;
         /* next socket to use */
         int next_socket = first_socket;
         /* the number of cores of the next socket */
         int socket_number_of_cores;
         /* next core to use */
         int next_core = first_core + offset;
         /* maximal number of sockets on this system */
         int max_number_of_sockets = get_number_of_sockets();
         hwloc_obj_t this_core;

         /* 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_number_of_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_number_of_cores(next_socket);
            next_socket++;
            if (next_socket >= max_number_of_sockets) {
               /* we are out of sockets - we do nothing */
               hwloc_bitmap_free(cpuset);
               return false;
            }
         }  
         this_core =
            hwloc_get_obj_below_by_type(sge_hwloc_topology,
                                        HWLOC_OBJ_SOCKET, next_socket,
                                        HWLOC_OBJ_CORE, next_core);
         hwloc_bitmap_or(cpuset, cpuset, this_core->cpuset);

         /* collect the other processor ids with the strategy */
         for (cores_set = 1; cores_set < number_of_cores; cores_set++) {
            next_core++;
            /* jump to next socket when it is needed */
            /* maybe the next socket could offer 0 cores (I can't see when, 
               but just to be sure) */
            while ((socket_number_of_cores = get_number_of_cores(next_socket))
                        <= next_core) {
               next_socket++;
               next_core = next_core - socket_number_of_cores;
               if (next_socket >= max_number_of_sockets) {
                  /* we are out of sockets - we do nothing */
                  hwloc_bitmap_free(cpuset);
                  return false;
               }
            }
            this_core =
               hwloc_get_obj_below_by_type(sge_hwloc_topology,
                                           HWLOC_OBJ_SOCKET, next_socket,
                                           HWLOC_OBJ_CORE, next_core);
            hwloc_bitmap_or(cpuset, cpuset, this_core->cpuset);
         }

         /* 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(cpuset) == true) {
               shepherd_trace("binding_set_linear: SGE_BINDING env var created");
            } else {
               shepherd_trace("binding_set_linear: problems while creating SGE_BINDING env");
            }
             
         } else {

             /* bind SET process to mask */ 
            if (bind_process_to_mask(cpuset) == false) {
               /* there was an error while binding */ 
               hwloc_bitmap_free(cpuset);
               return false;
            }
         }

         hwloc_bitmap_free(cpuset);

      } else {
            
         /* TODO DG strategy without topology information but with 
            working library? */
         shepherd_trace("binding_set_linear: no information about topology");
         return false;
      }
         

   } else {

      shepherd_trace("binding_set_linear: binding not supported: %s",
                     sge_dstring_get_string(&error));

      sge_dstring_free(&error);
   }
#endif  /* HAVE_HWLOC */
   return true;
}