Logo Search packages:      
Sourcecode: slurm-llnl version File versions  Download package

select_linear.c

/*****************************************************************************\
 *  select_linear.c - node selection plugin for simple one-dimensional 
 *  address space. Selects nodes for a job so as to minimize the number 
 *  of sets of consecutive nodes using a best-fit algorithm.
 *
 *  $Id: select_linear.c 12419 2007-09-27 16:33:13Z jette $
 *****************************************************************************
 *  Copyright (C) 2004-2006 The Regents of the University of California.
 *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
 *  Written by Morris Jette <jette1@llnl.gov>
 *  UCRL-CODE-226842.
 *  
 *  This file is part of SLURM, a resource management program.
 *  For details, see <http://www.llnl.gov/linux/slurm/>.
 *  
 *  SLURM is free software; you can redistribute it and/or modify it under
 *  the terms of the GNU General Public License as published by the Free
 *  Software Foundation; either version 2 of the License, or (at your option)
 *  any later version.
 *
 *  In addition, as a special exception, the copyright holders give permission 
 *  to link the code of portions of this program with the OpenSSL library under
 *  certain conditions as described in each individual source file, and 
 *  distribute linked combinations including the two. You must obey the GNU 
 *  General Public License in all respects for all of the code used other than 
 *  OpenSSL. If you modify file(s) with this exception, you may extend this 
 *  exception to your version of the file(s), but you are not obligated to do 
 *  so. If you do not wish to do so, delete this exception statement from your
 *  version.  If you delete this exception statement from all source files in 
 *  the program, then also delete it here.
 *  
 *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
 *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 *  details.
 *  
 *  You should have received a copy of the GNU General Public License along
 *  with SLURM; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
\*****************************************************************************/

#ifdef HAVE_CONFIG_H
#  include "config.h"
#  if HAVE_STDINT_H
#    include <stdint.h>
#  endif
#  if HAVE_INTTYPES_H
#    include <inttypes.h>
#  endif
#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <slurm/slurm.h>
#include <slurm/slurm_errno.h>

#include "src/common/list.h"
#include "src/common/log.h"
#include "src/common/node_select.h"
#include "src/common/parse_time.h"
#include "src/common/slurm_protocol_api.h"
#include "src/common/xassert.h"
#include "src/common/xmalloc.h"

#include "src/common/slurm_resource_info.h"

#include "src/slurmctld/slurmctld.h"
#include "src/slurmctld/proc_req.h"

#define SELECT_DEBUG 0

/*
 * These variables are required by the generic plugin interface.  If they
 * are not found in the plugin, the plugin loader will ignore it.
 *
 * plugin_name - a string giving a human-readable description of the
 * plugin.  There is no maximum length, but the symbol must refer to
 * a valid string.
 *
 * plugin_type - a string suggesting the type of the plugin or its
 * applicability to a particular form of data or method of data handling.
 * If the low-level plugin API is used, the contents of this string are
 * unimportant and may be anything.  SLURM uses the higher-level plugin
 * interface which requires this string to be of the form
 *
 *    <application>/<method>
 *
 * where <application> is a description of the intended application of
 * the plugin (e.g., "select" for SLURM node selection) and <method>
 * is a description of how this plugin satisfies that application.  SLURM will
 * only load select plugins if the plugin_type string has a 
 * prefix of "select/".
 *
 * plugin_version - an unsigned 32-bit integer giving the version number
 * of the plugin.  If major and minor revisions are desired, the major
 * version number may be multiplied by a suitable magnitude constant such
 * as 100 or 1000.  Various SLURM versions will likely require a certain
 * minimum versions for their plugins as the node selection API matures.
 */
const char plugin_name[]            = "Linear node selection plugin";
const char plugin_type[]            = "select/linear";
const uint32_t plugin_version = 90;

static struct node_record *select_node_ptr = NULL;
static int select_node_cnt = 0;
static uint16_t select_fast_schedule;

#ifdef HAVE_XCPU
#define XCPU_POLL_TIME 120
static pthread_t xcpu_thread = 0;
static pthread_mutex_t thread_flag_mutex = PTHREAD_MUTEX_INITIALIZER;
static int agent_fini = 0;

static void *xcpu_agent(void *args)
{
      int i;
      static time_t last_xcpu_test;
      char reason[12], clone_path[128], down_node_list[512];
      struct stat buf;
      time_t now;

      last_xcpu_test = time(NULL) + XCPU_POLL_TIME;
      while (!agent_fini) {
            now = time(NULL);

            if (difftime(now, last_xcpu_test) >= XCPU_POLL_TIME) {
                  debug3("Running XCPU node state test");
                  down_node_list[0] = '\0';

                  for (i=0; i<select_node_cnt; i++) {
                        snprintf(clone_path, sizeof(clone_path), 
                              "%s/%s/xcpu/clone", XCPU_DIR, 
                              select_node_ptr[i].name);
                        if (stat(clone_path, &buf) == 0)
                              continue;
                        error("stat %s: %m", clone_path);
                        if ((strlen(select_node_ptr[i].name) +
                             strlen(down_node_list) + 2) <
                            sizeof(down_node_list)) {
                              if (down_node_list[0] != '\0')
                                    strcat(down_node_list,",");
                              strcat(down_node_list, 
                                    select_node_ptr[i].name);
                        } else
                              error("down_node_list overflow");
                  }
                  if (down_node_list[0]) {
                        char time_str[32];
                        slurm_make_time_str(&now, time_str,       
                              sizeof(time_str));
                        snprintf(reason, sizeof(reason),
                              "select_linear: Can not stat XCPU "
                              "[SLURM@%s]", time_str);
                        slurm_drain_nodes(down_node_list, reason);
                  }
                  last_xcpu_test = now;
            }

            sleep(1);
      }
      return NULL;
}

static int _init_status_pthread(void)
{
      pthread_attr_t attr;

      slurm_mutex_lock( &thread_flag_mutex );
      if ( xcpu_thread ) {
            debug2("XCPU thread already running, not starting "
                  "another");
            slurm_mutex_unlock( &thread_flag_mutex );
            return SLURM_ERROR;
      }

      slurm_attr_init( &attr );
      pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
      pthread_create( &xcpu_thread, &attr, xcpu_agent, NULL);
      slurm_mutex_unlock( &thread_flag_mutex );
      slurm_attr_destroy( &attr );

      return SLURM_SUCCESS;
}

static int _fini_status_pthread(void)
{
      int i, rc=SLURM_SUCCESS;

      slurm_mutex_lock( &thread_flag_mutex );
      if ( xcpu_thread ) {
            agent_fini = 1;
            for (i=0; i<4; i++) {
                  if (pthread_kill(xcpu_thread, 0)) {
                        xcpu_thread = 0;
                        break;
                  }
                  sleep(1);
            }
            if ( xcpu_thread ) {
                  error("could not kill XCPU agent thread");
                  rc = SLURM_ERROR;
            }
      }
      slurm_mutex_unlock( &thread_flag_mutex );
      return rc;
}
#endif

static bool 
_enough_nodes(int avail_nodes, int rem_nodes, 
            uint32_t min_nodes, uint32_t req_nodes)
{
      int needed_nodes;

      if (req_nodes > min_nodes)
            needed_nodes = rem_nodes + min_nodes - req_nodes;
      else
            needed_nodes = rem_nodes;

      return(avail_nodes >= needed_nodes);
}

/*
 * init() is called when the plugin is loaded, before any other functions
 * are called.  Put global initialization here.
 */
extern int init ( void )
{
      int rc = SLURM_SUCCESS;
#ifdef HAVE_XCPU
      rc = _init_status_pthread();
#endif
      return rc;
}

extern int fini ( void )
{
      int rc = SLURM_SUCCESS;
#ifdef HAVE_XCPU
      rc = _fini_status_pthread();
#endif
      return rc;
}

/*
 * The remainder of this file implements the standard SLURM 
 * node selection API.
 */

extern int select_p_state_save(char *dir_name)
{
      return SLURM_SUCCESS;
}

extern int select_p_state_restore(char *dir_name)
{
      return SLURM_SUCCESS;
}

extern int select_p_job_init(List job_list)
{
      return SLURM_SUCCESS;
}

extern int select_p_node_init(struct node_record *node_ptr, int node_cnt)
{
      if (node_ptr == NULL) {
            error("select_p_node_init: node_ptr == NULL");
            return SLURM_ERROR;
      }

      if (node_cnt < 0) {
            error("select_p_node_init: node_cnt < 0");
            return SLURM_ERROR;
      }

      select_node_ptr = node_ptr;
      select_node_cnt = node_cnt;
      select_fast_schedule = slurm_get_fast_schedule();

      return SLURM_SUCCESS;
}

extern int select_p_block_init(List part_list)
{
      return SLURM_SUCCESS;
}

/*
 * _get_avail_cpus - Get the number of "available" cpus on a node
 *    given this number given the number of cpus_per_task and
 *    maximum sockets, cores, threads.  Note that the value of
 *    cpus is the lowest-level logical processor (LLLP).
 * IN job_ptr - pointer to job being scheduled
 * IN index - index of node's configuration information in select_node_ptr
 */
static uint16_t _get_avail_cpus(struct job_record *job_ptr, int index)
{
      struct node_record *node_ptr;
      uint16_t avail_cpus;
      uint16_t cpus, sockets, cores, threads;
      uint16_t cpus_per_task = 1;
      uint16_t ntasks_per_node = 0, ntasks_per_socket = 0, ntasks_per_core = 0;
      uint16_t max_sockets = 0xffff, max_cores = 0xffff, max_threads = 0xffff;
      multi_core_data_t *mc_ptr = NULL;
      int min_sockets = 0, min_cores = 0;

      if (job_ptr->details) {
            if (job_ptr->details->cpus_per_task)
                  cpus_per_task = job_ptr->details->cpus_per_task;
            if (job_ptr->details->ntasks_per_node)
                  ntasks_per_node = job_ptr->details->ntasks_per_node;
            mc_ptr = job_ptr->details->mc_ptr;
      }
      if (mc_ptr) {
            max_sockets       = job_ptr->details->mc_ptr->max_sockets;
            max_cores         = job_ptr->details->mc_ptr->max_cores;
            max_threads       = job_ptr->details->mc_ptr->max_threads;
            ntasks_per_socket = job_ptr->details->mc_ptr->ntasks_per_socket;
            ntasks_per_core   = job_ptr->details->mc_ptr->ntasks_per_core;
      }

      node_ptr = &(select_node_ptr[index]);
      if (select_fast_schedule) { /* don't bother checking each node */
            cpus    = node_ptr->config_ptr->cpus;
            sockets = node_ptr->config_ptr->sockets;
            cores   = node_ptr->config_ptr->cores;
            threads = node_ptr->config_ptr->threads;
      } else {
            cpus    = node_ptr->cpus;
            sockets = node_ptr->sockets;
            cores   = node_ptr->cores;
            threads = node_ptr->threads;
      }

#if 0
      info("host %s User_ sockets %u cores %u threads %u ", 
           node_ptr->name, max_sockets, max_cores, max_threads);

      info("host %s HW_ cpus %u sockets %u cores %u threads %u ", 
           node_ptr->name, cpus, sockets, cores, threads);
#endif

      avail_cpus = slurm_get_avail_procs(
                  max_sockets, max_cores, max_threads, 
                  min_sockets, min_cores, cpus_per_task,
                  ntasks_per_node, ntasks_per_socket, ntasks_per_core,
                  &cpus, &sockets, &cores, &threads, 
                  (uint16_t) 0, NULL, (uint16_t) 0, 
                  SELECT_TYPE_INFO_NONE,
                  job_ptr->job_id, node_ptr->name);

#if 0
      debug3("avail_cpus index %d = %d (out of %d %d %d %d)",
                        index, avail_cpus,
                        cpus, sockets, cores, threads);
#endif
      return(avail_cpus);
}

/*
 * select_p_job_test - Given a specification of scheduling requirements, 
 *    identify the nodes which "best" satisfy the request.
 *    "best" is defined as either single set of consecutive nodes satisfying 
 *    the request and leaving the minimum number of unused nodes OR 
 *    the fewest number of consecutive node sets
 * IN job_ptr - pointer to job being scheduled
 * IN/OUT bitmap - usable nodes are set on input, nodes not required to 
 *    satisfy the request are cleared, other left set
 * IN min_nodes - minimum count of nodes
 * IN req_nodes - requested (or desired) count of nodes
 * IN max_nodes - maximum count of nodes (0==don't care)
 * IN test_only - if true, only test if ever could run, not necessarily now,
 *    not used in this implementation of plugin
 * RET zero on success, EINVAL otherwise
 * globals (passed via select_p_node_init): 
 *    node_record_count - count of nodes configured
 *    node_record_table_ptr - pointer to global node table
 * NOTE: the job information that is considered for scheduling includes:
 *    req_node_bitmap: bitmap of specific nodes required by the job
 *    contiguous: allocated nodes must be sequentially located
 *    num_procs: minimum number of processors required by the job
 * NOTE: bitmap must be a superset of the job's required at the time that 
 *    select_p_job_test is called
 */
extern int select_p_job_test(struct job_record *job_ptr, bitstr_t *bitmap,
                  uint32_t min_nodes, uint32_t max_nodes, 
                  uint32_t req_nodes, bool test_only)
{
      int i, index, error_code = EINVAL, sufficient;
      int *consec_nodes;      /* how many nodes we can add from this 
                         * consecutive set of nodes */
      int *consec_cpus; /* how many nodes we can add from this 
                         * consecutive set of nodes */
      int *consec_start;      /* where this consecutive set starts (index) */
      int *consec_end;  /* where this consecutive set ends (index) */
      int *consec_req;  /* are nodes from this set required 
                         * (in req_bitmap) */
      int consec_index, consec_size;
      int rem_cpus, rem_nodes;      /* remaining resources desired */
      int best_fit_nodes, best_fit_cpus, best_fit_req;
      int best_fit_location = 0, best_fit_sufficient;
      int avail_cpus;
      multi_core_data_t *mc_ptr = job_ptr->details->mc_ptr;

      xassert(bitmap);
      if (mc_ptr) {
            debug3("job min-[max]: -N %u-[%u]:%u-[%u]:%u-[%u]:%u-[%u]",
                  job_ptr->details->min_nodes,   job_ptr->details->max_nodes,
                  mc_ptr->min_sockets, mc_ptr->max_sockets,
                  mc_ptr->min_cores,   mc_ptr->max_cores,
                  mc_ptr->min_threads, mc_ptr->max_threads);
            debug3("job ntasks-per: -node=%u -socket=%u -core=%u",
                  job_ptr->details->ntasks_per_node,
                  mc_ptr->ntasks_per_socket, mc_ptr->ntasks_per_core);
      }

      consec_index = 0;
      consec_size  = 50;      /* start allocation for 50 sets of 
                         * consecutive nodes */
      consec_cpus  = xmalloc(sizeof(int) * consec_size);
      consec_nodes = xmalloc(sizeof(int) * consec_size);
      consec_start = xmalloc(sizeof(int) * consec_size);
      consec_end   = xmalloc(sizeof(int) * consec_size);
      consec_req   = xmalloc(sizeof(int) * consec_size);


      /* Build table with information about sets of consecutive nodes */
      consec_cpus[consec_index] = consec_nodes[consec_index] = 0;
      consec_req[consec_index] = -1;      /* no required nodes here by default */
      rem_cpus = job_ptr->num_procs;
      if (req_nodes > min_nodes)
            rem_nodes = req_nodes;
      else
            rem_nodes = min_nodes;

      for (index = 0; index < select_node_cnt; index++) {
            if (bit_test(bitmap, index)) {
                  if (consec_nodes[consec_index] == 0)
                        consec_start[consec_index] = index;

                  avail_cpus = _get_avail_cpus(job_ptr, index);

                  if (job_ptr->details->req_node_bitmap
                  &&  bit_test(job_ptr->details->req_node_bitmap, index)
                  &&  (max_nodes > 0)) {
                        if (consec_req[consec_index] == -1) {
                              /* first required node in set */
                              consec_req[consec_index] = index;
                        }
                        rem_cpus -= avail_cpus;
                        rem_nodes--;
                        max_nodes--;
                  } else {     /* node not required (yet) */
                        bit_clear(bitmap, index); 
                        consec_cpus[consec_index] += avail_cpus;
                        consec_nodes[consec_index]++;
                  }
            } else if (consec_nodes[consec_index] == 0) {
                  consec_req[consec_index] = -1;
                  /* already picked up any required nodes */
                  /* re-use this record */
            } else {
                  consec_end[consec_index] = index - 1;
                  if (++consec_index >= consec_size) {
                        consec_size *= 2;
                        xrealloc(consec_cpus,
                               sizeof(int) * consec_size);
                        xrealloc(consec_nodes,
                               sizeof(int) * consec_size);
                        xrealloc(consec_start,
                               sizeof(int) * consec_size);
                        xrealloc(consec_end,
                               sizeof(int) * consec_size);
                        xrealloc(consec_req,
                               sizeof(int) * consec_size);
                  }
                  consec_cpus[consec_index] = 0;
                  consec_nodes[consec_index] = 0;
                  consec_req[consec_index] = -1;
            }
      }
      if (consec_nodes[consec_index] != 0)
            consec_end[consec_index++] = index - 1;

#if SELECT_DEBUG
      /* don't compile this, slows things down too much */
      debug3("rem_cpus=%d, rem_nodes=%d", rem_cpus, rem_nodes);
      for (i = 0; i < consec_index; i++) {
            if (consec_req[i] != -1)
                  debug3
                      ("start=%s, end=%s, nodes=%d, cpus=%d, req=%s",
                       select_node_ptr[consec_start[i]].name,
                       select_node_ptr[consec_end[i]].name,
                       consec_nodes[i], consec_cpus[i],
                       select_node_ptr[consec_req[i]].name);
            else
                  debug3("start=%s, end=%s, nodes=%d, cpus=%d",
                         select_node_ptr[consec_start[i]].name,
                         select_node_ptr[consec_end[i]].name,
                         consec_nodes[i], consec_cpus[i]);
      }
#endif

      /* accumulate nodes from these sets of consecutive nodes until */
      /*   sufficient resources have been accumulated */
      while (consec_index && (max_nodes > 0)) {
            best_fit_cpus = best_fit_nodes = best_fit_sufficient = 0;
            best_fit_req = -1;      /* first required node, -1 if none */
            for (i = 0; i < consec_index; i++) {
                  if (consec_nodes[i] == 0)
                        continue;
                  sufficient = (consec_cpus[i] >= rem_cpus)
                  && _enough_nodes(consec_nodes[i], rem_nodes,
                               min_nodes, req_nodes);

                  /* if first possibility OR */
                  /* contains required nodes OR */
                  /* first set large enough for request OR */
                  /* tightest fit (less resource waste) OR */
                  /* nothing yet large enough, but this is biggest */
                  if ((best_fit_nodes == 0) ||  
                      ((best_fit_req == -1) && (consec_req[i] != -1)) ||
                      (sufficient && (best_fit_sufficient == 0)) ||
                      (sufficient && (consec_cpus[i] < best_fit_cpus)) ||     
                      ((sufficient == 0) && 
                       (consec_cpus[i] > best_fit_cpus))) {
                        best_fit_cpus = consec_cpus[i];
                        best_fit_nodes = consec_nodes[i];
                        best_fit_location = i;
                        best_fit_req = consec_req[i];
                        best_fit_sufficient = sufficient;
                  }
            }
            if (best_fit_nodes == 0)
                  break;
            if (job_ptr->details->contiguous && 
                ((best_fit_cpus < rem_cpus) ||
                 (!_enough_nodes(best_fit_nodes, rem_nodes, 
                             min_nodes, req_nodes))))
                  break;      /* no hole large enough */
            if (best_fit_req != -1) {
                  /* This collection of nodes includes required ones
                   * select nodes from this set, first working up
                   * then down from the required nodes */
                  for (i = best_fit_req;
                       i <= consec_end[best_fit_location]; i++) {
                        if ((max_nodes <= 0)
                        ||  ((rem_nodes <= 0) && (rem_cpus <= 0)))
                              break;
                        if (bit_test(bitmap, i))
                              continue;
                        bit_set(bitmap, i);
                        rem_nodes--;
                        max_nodes--;
                        avail_cpus = _get_avail_cpus(job_ptr, i);
                        rem_cpus -= avail_cpus;
                  }
                  for (i = (best_fit_req - 1);
                       i >= consec_start[best_fit_location]; i--) {
                        if ((max_nodes <= 0)
                        ||  ((rem_nodes <= 0) && (rem_cpus <= 0)))
                              break;
                        if (bit_test(bitmap, i)) 
                              continue;
                        bit_set(bitmap, i);
                        rem_nodes--;
                        max_nodes--;
                        avail_cpus = _get_avail_cpus(job_ptr, i);
                        rem_cpus -= avail_cpus;
                  }
            } else {
                  for (i = consec_start[best_fit_location];
                       i <= consec_end[best_fit_location]; i++) {
                        if ((max_nodes <= 0)
                        ||  ((rem_nodes <= 0) && (rem_cpus <= 0)))
                              break;
                        if (bit_test(bitmap, i))
                              continue;
                        bit_set(bitmap, i);
                        rem_nodes--;
                        max_nodes--;
                        avail_cpus = _get_avail_cpus(job_ptr, i);
                        rem_cpus -= avail_cpus;
                  }
            }
            if (job_ptr->details->contiguous || 
                ((rem_nodes <= 0) && (rem_cpus <= 0))) {
                  error_code = SLURM_SUCCESS;
                  break;
            }
            consec_cpus[best_fit_location] = 0;
            consec_nodes[best_fit_location] = 0;
      }

      if (error_code && (rem_cpus <= 0)
      &&  _enough_nodes(0, rem_nodes, min_nodes, req_nodes)) {
            error_code = SLURM_SUCCESS;
      }

      xfree(consec_cpus);
      xfree(consec_nodes);
      xfree(consec_start);
      xfree(consec_end);
      xfree(consec_req);
      return error_code;
}

extern int select_p_job_begin(struct job_record *job_ptr)
{
#ifdef HAVE_XCPU
      int i;
      int rc = SLURM_SUCCESS;
      char clone_path[128];

      xassert(job_ptr);
      xassert(job_ptr->node_bitmap);

      for (i=0; i<select_node_cnt; i++) {
            if (bit_test(job_ptr->node_bitmap, i) == 0)
                  continue;
            snprintf(clone_path, sizeof(clone_path), 
                  "%s/%s/xcpu/clone", XCPU_DIR, 
                  select_node_ptr[i].name);
            if (chown(clone_path, (uid_t)job_ptr->user_id, 
                        (gid_t)job_ptr->group_id)) {
                  error("chown %s: %m", clone_path);
                  rc = SLURM_ERROR;
            } else {
                  debug("chown %s to %u", clone_path, 
                        job_ptr->user_id);
            }
      }
      return rc;
#else
      return SLURM_SUCCESS;
#endif
}

extern int select_p_job_fini(struct job_record *job_ptr)
{
      int rc = SLURM_SUCCESS;
#ifdef HAVE_XCPU
      int i;
      char clone_path[128];

      for (i=0; i<select_node_cnt; i++) {
            if (bit_test(job_ptr->node_bitmap, i) == 0)
                  continue;
            snprintf(clone_path, sizeof(clone_path), 
                  "%s/%s/xcpu/clone", XCPU_DIR, 
                  select_node_ptr[i].name);
            if (chown(clone_path, (uid_t)0, (gid_t)0)) {
                  error("chown %s: %m", clone_path);
                  rc = SLURM_ERROR;
            } else {
                  debug("chown %s to 0", clone_path);
            }
      }
#endif
      return rc;
}

extern int select_p_job_suspend(struct job_record *job_ptr)
{
      return SLURM_SUCCESS;
}

extern int select_p_job_resume(struct job_record *job_ptr)
{
      return SLURM_SUCCESS;
}

extern int select_p_job_ready(struct job_record *job_ptr)
{
      if (job_ptr->job_state != JOB_RUNNING)
            return 0;

      return 1;
}

extern int select_p_pack_node_info(time_t last_query_time, Buf *buffer_ptr)
{
      /* This function is always invalid on normal Linux clusters */
      return SLURM_ERROR;
}

extern int select_p_get_select_nodeinfo (struct node_record *node_ptr, 
                                         enum select_data_info info,
                                         void *data)
{
       return SLURM_SUCCESS;
}

extern int select_p_update_nodeinfo (struct job_record *job_ptr)
{
       return SLURM_SUCCESS;
}

extern int select_p_update_block (update_part_msg_t *part_desc_ptr)
{
      return SLURM_SUCCESS;
}

extern int select_p_update_sub_node (update_part_msg_t *part_desc_ptr)
{
      return SLURM_SUCCESS;
}
extern int select_p_get_extra_jobinfo (struct node_record *node_ptr, 
                                       struct job_record *job_ptr, 
                                       enum select_data_info info,
                                       void *data)
{
      int rc = SLURM_SUCCESS;

      xassert(job_ptr);
      xassert(job_ptr->magic == JOB_MAGIC);

      switch (info) {
      case SELECT_AVAIL_CPUS:
      {
            uint16_t *tmp_16 = (uint16_t *) data;

            if ((job_ptr->details->cpus_per_task > 1)
            ||  (job_ptr->details->mc_ptr)) {
                  int index = (node_ptr - node_record_table_ptr);
                  *tmp_16 = _get_avail_cpus(job_ptr, index);
            } else {
                  if (slurmctld_conf.fast_schedule) {
                        *tmp_16 = node_ptr->config_ptr->cpus;
                  } else {
                        *tmp_16 = node_ptr->cpus;
                  }
            }
            break;
      }
      default:
            error("select_g_get_extra_jobinfo info %d invalid", info);
            rc = SLURM_ERROR;
            break;
      }
      
      return rc;
}

extern int select_p_get_info_from_plugin (enum select_data_info info,
                                void *data)
{
      return SLURM_SUCCESS;
}

extern int select_p_update_node_state (int index, uint16_t state)
{
      return SLURM_SUCCESS;
}

extern int select_p_alter_node_cnt(enum select_node_cnt type, void *data)
{
      return SLURM_SUCCESS;
}

Generated by  Doxygen 1.6.0   Back to index