blob: 41e2e19626fb6922eb7b15c5d3cf703f57534f8c [file]
/*****************************************************************************\
* block_allocator.c - Assorted functions for layout of bluegene blocks,
* wiring, mapping for smap, etc.
* $Id$
*****************************************************************************
* Copyright (C) 2004-2007 The Regents of the University of California.
* Copyright (C) 2008-2009 Lawrence Livermore National Security.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Dan Phung <phung4@llnl.gov>, Danny Auble <da@llnl.gov>
*
* This file is part of SLURM, a resource management program.
* For details, see <http://www.schedmd.com/slurmdocs/>.
* Please also read the included file: DISCLAIMER.
*
* 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.
\*****************************************************************************/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "block_allocator.h"
#include "src/common/slurmdb_defs.h"
#include "src/common/timers.h"
#include "src/common/uid.h"
/*
* structure that holds switch path information for finding the wiring
* path without setting the configuration.
*
* - dim - Which Axis it is on
* - geometry - node location
* - in - ingress port.
* - out - egress port.
*
*/
typedef struct {
int dim;
uint16_t geometry[HIGHEST_DIMENSIONS];
int in;
int out;
} ba_path_switch_t;
#define DEBUG_PA
#define BEST_COUNT_INIT 20
/* Global */
bool _initialized = false;
bool _wires_initialized = false;
bool _mp_map_initialized = false;
/* _ba_system is the "current" system that the structures will work
* on */
List path = NULL;
List best_path = NULL;
int best_count;
uint16_t *deny_pass = NULL;
char *p = '\0';
/* extern Global */
my_bluegene_t *bg = NULL;
ba_mp_t ***ba_main_grid = NULL;
typedef enum {
BLOCK_ALGO_FIRST,
BLOCK_ALGO_SECOND
} block_algo_t;
/** internal helper functions */
/* */
static int _check_for_options(select_ba_request_t* ba_request);
/* */
static int _append_geo(uint16_t *geo, List geos, int rotate);
/* */
static int _fill_in_coords(List results, List start_list,
uint16_t *geometry, int conn_type);
/* */
static int _copy_the_path(List nodes, ba_switch_t *curr_switch,
ba_switch_t *mark_switch,
int source, int dim);
/* */
static int _find_yz_path(ba_mp_t *ba_node, uint16_t *first,
uint16_t *geometry, int conn_type);
#ifndef HAVE_BG_FILES
/* */
static int _emulate_ext_wiring(ba_mp_t ***grid);
#endif
/** */
static int _reset_the_path(ba_switch_t *curr_switch, int source,
int target, int dim);
/* */
static void _delete_path_list(void *object);
/* find the first block match in the system */
static int _find_match(select_ba_request_t* ba_request, List results);
/** */
static bool _node_used(ba_mp_t* ba_node, int x_size);
/* */
static void _switch_config(ba_mp_t* source, ba_mp_t* target, int dim,
int port_src, int port_tar);
/* */
static int _set_external_wires(int dim, int count, ba_mp_t* source,
ba_mp_t* target);
/* */
static char *_set_internal_wires(List nodes, int size, int conn_type);
/* */
static int _find_x_path(List results, ba_mp_t *ba_node, uint16_t *start,
int x_size, int found, int conn_type,
block_algo_t algo);
/* */
static int _remove_node(List results, uint16_t *mp_tar);
/* */
static int _find_next_free_using_port_2(ba_switch_t *curr_switch,
int source_port,
List nodes, int dim,
int count);
/* */
/* static int _find_passthrough(ba_switch_t *curr_switch, int source_port, */
/* List nodes, int dim, */
/* int count, int highest_phys_x); */
/* */
static int _finish_torus(List results,
ba_switch_t *curr_switch, int source_port,
int dim, int count, uint16_t *start);
/* */
static uint16_t *_set_best_path();
/* */
static int _set_one_dim(uint16_t *start, uint16_t *end, uint16_t *coord);
/* */
static void _destroy_geo(void *object);
extern void destroy_ba_node(void *ptr)
{
ba_mp_t *ba_node = (ba_mp_t *)ptr;
if (ba_node) {
xfree(ba_node->loc);
xfree(ba_node);
}
}
/*
* create a block request. Note that if the geometry is given,
* then size is ignored. If elongate is true, the algorithm will try
* to fit that a block of cubic shape and then it will try other
* elongated geometries. (ie, 2x2x2 -> 4x2x1 -> 8x1x1).
*
* IN/OUT - ba_request: structure to allocate and fill in.
*
* ALL below IN's need to be set within the ba_request before the call
* if you want them to be used.
* ALL below OUT's are set and returned within the ba_request.
* IN - avail_node_bitmap: bitmap of usable midplanes.
* IN - blrtsimage: BlrtsImage for this block if not default
* IN - conn_type: connection type of request (TORUS or MESH or SMALL)
* IN - elongate: if true, will try to fit different geometries of
* same size requests
* IN/OUT - geometry: requested/returned geometry of block
* IN - linuximage: LinuxImage for this block if not default
* IN - mloaderimage: MLoaderImage for this block if not default
* IN - nodecards: Number of nodecards in each block in request only
* used of small block allocations.
* OUT - passthroughs: if there were passthroughs used in the
* generation of the block.
* IN - procs: Number of real processors requested
* IN - quarters: Number of midplane quarters in each block in request only
* used of small block allocations.
* IN - RamDiskimage: RamDiskImage for this block if not default
* IN - rotate: if true, allows rotation of block during fit
* OUT - save_name: hostlist of midplanes used in block
* IN/OUT - size: requested/returned count of midplanes in block
* IN - start: geo location of where to start the allocation
* IN - start_req: if set use the start variable to start at
* return success of allocation/validation of params
*/
extern int new_ba_request(select_ba_request_t* ba_request)
{
int i=0;
float sz=1;
int i2, picked, total_sz=1, size2=0;
uint16_t *geo_ptr;
int messed_with = 0;
int checked[DIM_SIZE[X]];
uint16_t geo[cluster_dims];
memset(geo, 0, sizeof(geo));
ba_request->save_name= NULL;
ba_request->rotate_count= 0;
ba_request->elongate_count = 0;
ba_request->elongate_geos = list_create(_destroy_geo);
memcpy(geo, ba_request->geometry, sizeof(geo));
if (ba_request->deny_pass == (uint16_t)NO_VAL)
ba_request->deny_pass = ba_deny_pass;
if (!(cluster_flags & CLUSTER_FLAG_BG)) {
if (geo[X] != (uint16_t)NO_VAL) {
for (i=0; i<cluster_dims; i++) {
if ((geo[i] < 1) || (geo[i] > DIM_SIZE[i])) {
error("new_ba_request Error, "
"request geometry is invalid %d",
geo[i]);
return 0;
}
}
ba_request->size = ba_request->geometry[X];
} else if (ba_request->size) {
ba_request->geometry[X] = ba_request->size;
} else
return 0;
return 1;
}
if (geo[X] != (uint16_t)NO_VAL) {
for (i=0; i<cluster_dims; i++){
if ((geo[i] < 1) || (geo[i] > DIM_SIZE[i])) {
error("new_ba_request Error, "
"request geometry is invalid dim %d "
"can't be %c, largest is %c",
i,
alpha_num[geo[i]],
alpha_num[DIM_SIZE[i]]);
return 0;
}
}
_append_geo(geo, ba_request->elongate_geos, 0);
sz=1;
for (i=0; i<cluster_dims; i++)
sz *= ba_request->geometry[i];
ba_request->size = sz;
sz=0;
}
deny_pass = &ba_request->deny_pass;
if (ba_request->elongate || sz) {
sz=1;
/* decompose the size into a cubic geometry */
ba_request->rotate= 1;
ba_request->elongate = 1;
for (i=0; i<cluster_dims; i++) {
total_sz *= DIM_SIZE[i];
geo[i] = 1;
}
if (ba_request->size==1) {
_append_geo(geo,
ba_request->elongate_geos,
ba_request->rotate);
goto endit;
}
if (ba_request->size<=DIM_SIZE[Y]) {
geo[X] = 1;
geo[Y] = ba_request->size;
geo[Z] = 1;
sz=ba_request->size;
_append_geo(geo,
ba_request->elongate_geos,
ba_request->rotate);
}
i = ba_request->size/4;
if (!(ba_request->size%2)
&& i <= DIM_SIZE[Y]
&& i <= DIM_SIZE[Z]
&& i*i == ba_request->size) {
geo[X] = 1;
geo[Y] = i;
geo[Z] = i;
sz=ba_request->size;
_append_geo(geo,
ba_request->elongate_geos,
ba_request->rotate);
}
if (ba_request->size > total_sz || ba_request->size < 1) {
return 0;
}
sz = ba_request->size % (DIM_SIZE[Y] * DIM_SIZE[Z]);
if (!sz) {
i = ba_request->size / (DIM_SIZE[Y] * DIM_SIZE[Z]);
geo[X] = i;
geo[Y] = DIM_SIZE[Y];
geo[Z] = DIM_SIZE[Z];
sz=ba_request->size;
if ((geo[X]*geo[Y]*geo[Z]) == ba_request->size)
_append_geo(geo,
ba_request->elongate_geos,
ba_request->rotate);
else
error("%d I was just trying to add a "
"geo of %d%d%d "
"while I am trying to request "
"%d midplanes",
__LINE__, geo[X], geo[Y], geo[Z],
ba_request->size);
}
// startagain:
picked=0;
for(i=0; i<DIM_SIZE[X]; i++)
checked[i]=0;
for (i=0; i<cluster_dims; i++) {
total_sz *= DIM_SIZE[i];
geo[i] = 1;
}
sz = 1;
picked=0;
tryagain:
size2 = ba_request->size;
//messedup:
for (i=picked; i<cluster_dims; i++) {
if (size2 <= 1)
break;
sz = size2 % DIM_SIZE[i];
if (!sz) {
geo[i] = DIM_SIZE[i];
size2 /= DIM_SIZE[i];
} else if (size2 > DIM_SIZE[i]) {
for(i2=(DIM_SIZE[i]-1); i2 > 1; i2--) {
/* go through each number to see if
the size is divisable by a smaller
number that is
good in the other dims. */
if (!(size2%i2) && !checked[i2]) {
size2 /= i2;
if (i==0)
checked[i2]=1;
if (i2<DIM_SIZE[i]) {
geo[i] = i2;
} else {
goto tryagain;
}
if ((i2-1)!=1 &&
i!=(cluster_dims-1))
break;
}
}
/* This size can not be made into a
block return. If you want to try
until we find the next largest block
uncomment the code below and the goto
above. If a user specifies a max
node count the job will never
run.
*/
if (i2==1) {
if (!list_count(
ba_request->elongate_geos))
error("Can't make a block of "
"%d into a cube.",
ba_request->size);
goto endit;
/* ba_request->size +=1; */
/* goto startagain; */
}
} else {
geo[i] = sz;
break;
}
}
if ((geo[X]*geo[Y]) <= DIM_SIZE[Y]) {
ba_request->geometry[X] = 1;
ba_request->geometry[Y] = geo[X] * geo[Y];
ba_request->geometry[Z] = geo[Z];
_append_geo(ba_request->geometry,
ba_request->elongate_geos,
ba_request->rotate);
}
if ((geo[X]*geo[Z]) <= DIM_SIZE[Y]) {
ba_request->geometry[X] = 1;
ba_request->geometry[Y] = geo[Y];
ba_request->geometry[Z] = geo[X] * geo[Z];
_append_geo(ba_request->geometry,
ba_request->elongate_geos,
ba_request->rotate);
}
/* Make sure geo[X] is even and then see if we can get
it into the Y or Z dim. */
if (!(geo[X]%2) && ((geo[X]/2) <= DIM_SIZE[Y])) {
if (geo[Y] == 1) {
ba_request->geometry[Y] = geo[X]/2;
messed_with = 1;
} else
ba_request->geometry[Y] = geo[Y];
if (!messed_with && geo[Z] == 1) {
messed_with = 1;
ba_request->geometry[Z] = geo[X]/2;
} else
ba_request->geometry[Z] = geo[Z];
if (messed_with) {
messed_with = 0;
ba_request->geometry[X] = 2;
_append_geo(ba_request->geometry,
ba_request->elongate_geos,
ba_request->rotate);
}
}
if (geo[X] == DIM_SIZE[X]
&& (geo[Y] < DIM_SIZE[Y]
|| geo[Z] < DIM_SIZE[Z])) {
if (DIM_SIZE[Y]<DIM_SIZE[Z]) {
i = DIM_SIZE[Y];
DIM_SIZE[Y] = DIM_SIZE[Z];
DIM_SIZE[Z] = i;
}
ba_request->geometry[X] = geo[X];
ba_request->geometry[Y] = geo[Y];
ba_request->geometry[Z] = geo[Z];
if (ba_request->geometry[Y] < DIM_SIZE[Y]) {
i = (DIM_SIZE[Y] - ba_request->geometry[Y]);
ba_request->geometry[Y] +=i;
}
if (ba_request->geometry[Z] < DIM_SIZE[Z]) {
i = (DIM_SIZE[Z] - ba_request->geometry[Z]);
ba_request->geometry[Z] +=i;
}
for(i = DIM_SIZE[X]; i>0; i--) {
ba_request->geometry[X]--;
i2 = (ba_request->geometry[X]
* ba_request->geometry[Y]
* ba_request->geometry[Z]);
if (i2 < ba_request->size) {
ba_request->geometry[X]++;
messed_with = 1;
break;
}
}
if (messed_with) {
messed_with = 0;
_append_geo(ba_request->geometry,
ba_request->elongate_geos,
ba_request->rotate);
}
}
if ((geo[X]*geo[Y]*geo[Z]) == ba_request->size)
_append_geo(geo,
ba_request->elongate_geos,
ba_request->rotate);
else
error("%d I was just trying to add a geo of %d%d%d "
"while I am trying to request %d midplanes",
__LINE__, geo[X], geo[Y], geo[Z],
ba_request->size);
/* Having the functions pow and powf on an aix system doesn't seem to
* link well, so since this is only for aix and this doesn't really
* need to be there just don't allow this extra calculation.
*/
#ifndef HAVE_AIX
/* see if We can find a cube or square root of the
size to make an easy cube */
for(i=0; i<cluster_dims-1; i++) {
sz = powf((float)ba_request->size,
(float)1/(cluster_dims-i));
if (pow(sz,(cluster_dims-i)) == ba_request->size)
break;
}
if (i < (cluster_dims-1)) {
/* we found something that looks like a cube! */
int i3 = i;
for (i=0; i<i3; i++)
geo[i] = 1;
for (i=i3; i<cluster_dims; i++)
if (sz<=DIM_SIZE[i])
geo[i] = sz;
else
goto endit;
if ((geo[X]*geo[Y]*geo[Z]) == ba_request->size)
_append_geo(geo,
ba_request->elongate_geos,
ba_request->rotate);
else
error("%d I was just trying to add "
"a geo of %d%d%d "
"while I am trying to request "
"%d midplanes",
__LINE__, geo[X], geo[Y], geo[Z],
ba_request->size);
}
#endif //HAVE_AIX
}
endit:
if (!(geo_ptr = list_peek(ba_request->elongate_geos)))
return 0;
ba_request->elongate_count++;
ba_request->geometry[X] = geo_ptr[X];
ba_request->geometry[Y] = geo_ptr[Y];
ba_request->geometry[Z] = geo_ptr[Z];
sz=1;
for (i=0; i<cluster_dims; i++)
sz *= ba_request->geometry[i];
ba_request->size = sz;
return 1;
}
/**
* print a block request
*/
extern void print_ba_request(select_ba_request_t* ba_request)
{
int i;
if (ba_request == NULL){
error("print_ba_request Error, request is NULL");
return;
}
debug(" ba_request:");
debug(" geometry:\t");
for (i=0; i<cluster_dims; i++){
debug("%d", ba_request->geometry[i]);
}
debug(" size:\t%d", ba_request->size);
debug(" conn_type:\t%d", ba_request->conn_type[X]);
debug(" rotate:\t%d", ba_request->rotate);
debug(" elongate:\t%d", ba_request->elongate);
}
/* If emulating a system set up a known configuration for wires in a
* system of the size given.
* If a real bluegene system, query the system and get all wiring
* information of the system.
*/
extern void init_wires(void)
{
int x, y, z, i;
ba_mp_t *source = NULL;
if (_wires_initialized)
return;
for(x=0;x<DIM_SIZE[X];x++) {
for(y=0;y<DIM_SIZE[Y];y++) {
for(z=0;z<DIM_SIZE[Z];z++) {
source = &ba_main_grid[x][y][z];
for(i=0; i<NUM_PORTS_PER_NODE; i++) {
_switch_config(source, source,
X, i, i);
_switch_config(source, source,
Y, i, i);
_switch_config(source, source,
Z, i, i);
}
}
}
}
#ifdef HAVE_BG_FILES
_set_external_wires(0,0,NULL,NULL);
if (bridge_setup_system() == -1)
return;
#endif
_wires_initialized = true;
return;
}
/*
* copy the path of the nodes given
*
* IN nodes List of ba_mp_t *'s: nodes to be copied
* OUT dest_nodes List of ba_mp_t *'s: filled in list of nodes
* wiring.
* Return on success SLURM_SUCCESS, on error SLURM_ERROR
*/
extern int copy_node_path(List nodes, List *dest_nodes)
{
int rc = SLURM_ERROR;
#ifdef HAVE_BG_L_P
ListIterator itr = NULL;
ListIterator itr2 = NULL;
ba_mp_t *ba_node = NULL, *new_ba_node = NULL;
int dim;
ba_switch_t *curr_switch = NULL, *new_switch = NULL;
if (!nodes)
return SLURM_ERROR;
if (!*dest_nodes)
*dest_nodes = list_create(destroy_ba_node);
itr = list_iterator_create(nodes);
while ((ba_node = list_next(itr))) {
itr2 = list_iterator_create(*dest_nodes);
while ((new_ba_node = list_next(itr2))) {
if (ba_node->coord[X] == new_ba_node->coord[X] &&
ba_node->coord[Y] == new_ba_node->coord[Y] &&
ba_node->coord[Z] == new_ba_node->coord[Z])
break; /* we found it */
}
list_iterator_destroy(itr2);
if (!new_ba_node) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("adding %c%c%c as a new node",
alpha_num[ba_node->coord[X]],
alpha_num[ba_node->coord[Y]],
alpha_num[ba_node->coord[Z]]);
new_ba_node = ba_copy_mp(ba_node);
ba_setup_mp(new_ba_node, false, false);
list_push(*dest_nodes, new_ba_node);
}
new_ba_node->used = true;
for(dim=0;dim<cluster_dims;dim++) {
curr_switch = &ba_node->axis_switch[dim];
new_switch = &new_ba_node->axis_switch[dim];
if (curr_switch->int_wire[0].used) {
if (!_copy_the_path(*dest_nodes,
curr_switch, new_switch,
0, dim)) {
rc = SLURM_ERROR;
break;
}
}
}
}
list_iterator_destroy(itr);
rc = SLURM_SUCCESS;
#endif
return rc;
}
extern ba_mp_t *coord2ba_mp(const uint16_t *coord)
{
if ((coord[X] >= DIM_SIZE[X]) || (coord[Y] >= DIM_SIZE[Y]) ||
(coord[Z] >= DIM_SIZE[Z])) {
error("Invalid coordinate %d:%d:%d",
coord[X], coord[Y], coord[Z]);
return NULL;
}
return &ba_main_grid[coord[X]][coord[Y]][coord[Z]];
}
/*
* Try to allocate a block.
*
* IN - ba_request: allocation request
* OUT - results: List of results of the allocation request. Each
* list entry will be a coordinate. allocate_block will create the
* list, but the caller must destroy it.
*
* return: success or error of request
*/
extern int allocate_block(select_ba_request_t* ba_request, List results)
{
if (!ba_initialized){
error("Error, configuration not initialized, "
"calling ba_init(NULL, 1)");
ba_init(NULL, 1);
}
if (!ba_request){
error("allocate_block Error, request not initialized");
return 0;
}
// _backup_ba_system();
if (_find_match(ba_request, results)){
return 1;
} else {
return 0;
}
}
/*
* Admin wants to remove a previous allocation.
* will allow Admin to delete a previous allocation retrival by letter code.
*/
extern int remove_block(List nodes, bool is_small)
{
int dim;
ba_mp_t* curr_ba_node = NULL;
ba_mp_t* ba_node = NULL;
ba_switch_t *curr_switch = NULL;
ListIterator itr;
itr = list_iterator_create(nodes);
while ((curr_ba_node = (ba_mp_t*) list_next(itr))) {
/* since the list that comes in might not be pointers
to the main list we need to point to that main list */
ba_node = &ba_main_grid[curr_ba_node->coord[X]]
[curr_ba_node->coord[Y]]
[curr_ba_node->coord[Z]];
if (curr_ba_node->used)
ba_node->used &= (~BA_MP_USED_TRUE);
/* Small blocks don't use wires, and only have 1 node,
so just break. */
if (is_small)
break;
for(dim=0;dim<cluster_dims;dim++) {
curr_switch = &ba_node->axis_switch[dim];
if (curr_switch->int_wire[0].used) {
_reset_the_path(curr_switch, 0, 1, dim);
}
}
}
list_iterator_destroy(itr);
return 1;
}
/*
* Used to set a block into a virtual system. The system can be
* cleared first and this function sets all the wires and midplanes
* used in the nodelist given. The nodelist is a list of ba_mp_t's
* that are already set up. This is very handly to test if there are
* any passthroughs used by one block when adding another block that
* also uses those wires, and neither use any overlapping
* midplanes. Doing a simple bitmap & will not reveal this.
*
* Returns SLURM_SUCCESS if nodelist fits into system without
* conflict, and SLURM_ERROR if nodelist conflicts with something
* already in the system.
*/
extern int check_and_set_mp_list(List nodes)
{
int rc = SLURM_ERROR;
#ifdef HAVE_BG_L_P
int i, j;
ba_switch_t *ba_switch = NULL, *curr_ba_switch = NULL;
ba_mp_t *ba_node = NULL, *curr_ba_node = NULL;
ListIterator itr = NULL;
if (!nodes)
return rc;
itr = list_iterator_create(nodes);
while ((ba_node = list_next(itr))) {
/* info("checking %c%c%c", */
/* ba_node->coord[X], */
/* ba_node->coord[Y], */
/* ba_node->coord[Z]); */
curr_ba_node = &ba_main_grid[ba_node->coord[X]]
[ba_node->coord[Y]]
[ba_node->coord[Z]];
if (ba_node->used && curr_ba_node->used) {
/* Only error if the midplane isn't already
* marked down or in a error state outside of
* the bluegene block.
*/
uint16_t base_state, node_flags;
base_state = curr_ba_node->state & NODE_STATE_BASE;
node_flags = curr_ba_node->state & NODE_STATE_FLAGS;
if (!(node_flags & (NODE_STATE_DRAIN | NODE_STATE_FAIL))
&& (base_state != NODE_STATE_DOWN)) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("I have already been to "
"this node %c%c%c %s",
alpha_num[ba_node->coord[X]],
alpha_num[ba_node->coord[Y]],
alpha_num[ba_node->coord[Z]],
node_state_string(
curr_ba_node->state));
rc = SLURM_ERROR;
goto end_it;
}
}
if (ba_node->used)
curr_ba_node->used = ba_node->used;
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("check_and_set_mp_list: "
"%s is used ?= %d %d",
curr_ba_node->coord_str,
curr_ba_node->used, ba_node->used);
for(i=0; i<cluster_dims; i++) {
ba_switch = &ba_node->axis_switch[i];
curr_ba_switch = &curr_ba_node->axis_switch[i];
//info("checking dim %d", i);
for(j=0; j<NUM_PORTS_PER_NODE; j++) {
//info("checking port %d", j);
if (ba_switch->int_wire[j].used
&& curr_ba_switch->int_wire[j].used
&& j != curr_ba_switch->
int_wire[j].port_tar) {
if (ba_debug_flags
& DEBUG_FLAG_BG_ALGO_DEEP)
info("%c%c%c dim %d port %d "
"is already in use to %d",
alpha_num[ba_node->
coord[X]],
alpha_num[ba_node->
coord[Y]],
alpha_num[ba_node->
coord[Z]],
i,
j,
curr_ba_switch->
int_wire[j].port_tar);
rc = SLURM_ERROR;
goto end_it;
}
if (!ba_switch->int_wire[j].used)
continue;
/* info("setting %c%c%c dim %d port %d -> %d",*/
/* alpha_num[ba_node->coord[X]], */
/* alpha_num[ba_node->coord[Y]], */
/* alpha_num[ba_node->coord[Z]], */
/* i, */
/* j, */
/* ba_switch->int_wire[j].port_tar); */
curr_ba_switch->int_wire[j].used = 1;
curr_ba_switch->int_wire[j].port_tar
= ba_switch->int_wire[j].port_tar;
}
}
}
rc = SLURM_SUCCESS;
end_it:
list_iterator_destroy(itr);
#endif
return rc;
}
/*
* Used to find, and set up midplanes and the wires in the virtual
* system and return them in List results
*
* IN/OUT results - a list with a NULL destroyer filled in with
* midplanes and wires set to create the block with the api. If
* only interested in the hostlist NULL can be excepted also.
* IN ba_request - request for the block
*
* To be set in the ba_request
* start - where to start the allocation. (optional)
* geometry or size - the requested geometry of the block. (required)
* conn_type - mesh, torus, or small. (required)
*
* RET char * - hostlist of midplanes results represent must be
* xfreed. NULL on failure
*/
extern char *set_bg_block(List results, select_ba_request_t* ba_request)
{
char *name = NULL;
ba_mp_t* ba_node = NULL;
int send_results = 0;
int found = 0;
xassert(ba_request);
if (cluster_dims == 1) {
if (ba_request->start[X]>=DIM_SIZE[X])
return NULL;
ba_request->size = ba_request->geometry[X];
ba_node = &ba_main_grid[ba_request->start[X]][0][0];
} else {
int dim;
ba_request->size = 1;
for (dim=0; dim<cluster_dims; dim++) {
if (ba_request->start[dim] >= DIM_SIZE[dim])
return NULL;
if ((int16_t)ba_request->geometry[dim] <= 0) {
error("problem with geometry of %c in dim %d, "
"needs to be at least 1",
alpha_num[ba_request->geometry[dim]],
dim);
return NULL;
}
ba_request->size *= ba_request->geometry[dim];
}
ba_node = coord2ba_mp(ba_request->start);
}
if (!ba_node)
return NULL;
if (!results)
results = list_create(NULL);
else
send_results = 1;
/* This midplane should have already been checked if it was in
use or not */
list_append(results, ba_node);
if (ba_request->conn_type[0] >= SELECT_SMALL) {
/* adding the ba_node and ending */
ba_node->used |= BA_MP_USED_TRUE;
name = xstrdup_printf("%s", ba_node->coord_str);
goto end_it;
} else if (ba_request->conn_type[0] == SELECT_NAV)
ba_request->conn_type[0] = bg_conf->default_conn_type[0];
found = _find_x_path(results, ba_node,
ba_node->coord,
ba_request->geometry[X],
1,
ba_request->conn_type[0], BLOCK_ALGO_FIRST);
if (!found) {
bool is_small = 0;
if (ba_request->conn_type[0] == SELECT_SMALL)
is_small = 1;
debug2("trying less efficient code");
remove_block(results, is_small);
list_flush(results);
list_append(results, ba_node);
found = _find_x_path(results, ba_node,
ba_node->coord,
ba_request->geometry[X],
1,
ba_request->conn_type[0],
BLOCK_ALGO_SECOND);
}
if (found) {
if (cluster_flags & CLUSTER_FLAG_BG) {
List start_list = NULL;
ListIterator itr;
start_list = list_create(NULL);
itr = list_iterator_create(results);
while ((ba_node = (ba_mp_t*) list_next(itr))) {
list_append(start_list, ba_node);
}
list_iterator_destroy(itr);
if (!_fill_in_coords(results,
start_list,
ba_request->geometry,
ba_request->conn_type[0])) {
list_destroy(start_list);
goto end_it;
}
list_destroy(start_list);
}
} else {
goto end_it;
}
name = _set_internal_wires(results,
ba_request->size,
ba_request->conn_type[0]);
end_it:
if (!send_results && results) {
list_destroy(results);
results = NULL;
}
if (name!=NULL) {
debug2("name = %s", name);
} else {
debug2("can't allocate");
xfree(name);
}
return name;
}
/* Rotate a 3-D geometry array through its six permutations */
extern void ba_rotate_geo(uint16_t *req_geometry, int rot_cnt)
{
uint16_t tmp;
switch (rot_cnt) {
case 0: /* ABC -> ACB */
case 2: /* CAB -> CBA */
case 4: /* BCA -> BAC */
SWAP(req_geometry[Y], req_geometry[Z], tmp);
break;
case 1: /* ACB -> CAB */
case 3: /* CBA -> BCA */
case 5: /* BAC -> ABC */
SWAP(req_geometry[X], req_geometry[Y], tmp);
break;
}
}
/********************* Local Functions *********************/
/*
* This function is here to check options for rotating and elongating
* and set up the request based on the count of each option
*/
static int _check_for_options(select_ba_request_t* ba_request)
{
int temp;
int set=0;
uint16_t *geo = NULL;
ListIterator itr;
if (ba_request->rotate) {
rotate_again:
debug2("Rotating! %d",ba_request->rotate_count);
if (ba_request->rotate_count==(cluster_dims-1)) {
temp=ba_request->geometry[X];
ba_request->geometry[X]=ba_request->geometry[Z];
ba_request->geometry[Z]=temp;
ba_request->rotate_count++;
set=1;
} else if (ba_request->rotate_count<(cluster_dims*2)) {
temp=ba_request->geometry[X];
ba_request->geometry[X]=ba_request->geometry[Y];
ba_request->geometry[Y]=ba_request->geometry[Z];
ba_request->geometry[Z]=temp;
ba_request->rotate_count++;
set=1;
} else
ba_request->rotate = false;
if (set) {
if (ba_request->geometry[X]<=DIM_SIZE[X]
&& ba_request->geometry[Y]<=DIM_SIZE[Y]
&& ba_request->geometry[Z]<=DIM_SIZE[Z])
return 1;
else {
set = 0;
goto rotate_again;
}
}
}
if (ba_request->elongate) {
elongate_again:
debug2("Elongating! %d",ba_request->elongate_count);
ba_request->rotate_count=0;
ba_request->rotate = true;
set = 0;
itr = list_iterator_create(ba_request->elongate_geos);
for(set=0; set<=ba_request->elongate_count; set++)
geo = list_next(itr);
list_iterator_destroy(itr);
if (geo == NULL)
return 0;
ba_request->elongate_count++;
ba_request->geometry[X] = geo[X];
ba_request->geometry[Y] = geo[Y];
ba_request->geometry[Z] = geo[Z];
if (ba_request->geometry[X]<=DIM_SIZE[X]
&& ba_request->geometry[Y]<=DIM_SIZE[Y]
&& ba_request->geometry[Z]<=DIM_SIZE[Z]) {
return 1;
} else
goto elongate_again;
}
return 0;
}
/*
* grab all the geometries that we can get and append them to the list geos
*/
static int _append_geo(uint16_t *geometry, List geos, int rotate)
{
ListIterator itr;
uint16_t *geo_ptr = NULL;
uint16_t *geo = NULL;
int temp_geo;
int i, j;
if (rotate) {
for (i = (cluster_dims - 1); i >= 0; i--) {
for (j = 1; j <= i; j++) {
if ((geometry[j-1] > geometry[j])
&& (geometry[j] <= DIM_SIZE[j-i])
&& (geometry[j-1] <= DIM_SIZE[j])) {
temp_geo = geometry[j-1];
geometry[j-1] = geometry[j];
geometry[j] = temp_geo;
}
}
}
}
itr = list_iterator_create(geos);
while ((geo_ptr = list_next(itr)) != NULL) {
if (geometry[X] == geo_ptr[X]
&& geometry[Y] == geo_ptr[Y]
&& geometry[Z] == geo_ptr[Z])
break;
}
list_iterator_destroy(itr);
if (geo_ptr == NULL) {
geo = xmalloc(sizeof(int)*cluster_dims);
geo[X] = geometry[X];
geo[Y] = geometry[Y];
geo[Z] = geometry[Z];
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("adding geo %c%c%c",
alpha_num[geo[X]], alpha_num[geo[Y]],
alpha_num[geo[Z]]);
list_append(geos, geo);
}
return 1;
}
/*
* Fill in the paths and extra midplanes we need for the block.
* Basically copy the x path sent in with the start_list in each Y and
* Z dimension filling in every midplane for the block and then
* completing the Y and Z wiring, tying the whole block together.
*
* IN/OUT results - total list of midplanes after this function
* returns successfully. Should be
* an exact copy of the start_list at first.
* IN start_list - exact copy of results at first, This should only be
* a list of midplanes on the X dim. We will work off this and
* the geometry to fill in this wiring for the X dim in all the
* Y and Z coords.
* IN geometry - What the block looks like
* IN conn_type - Mesh or Torus
*
* RET: 0 on failure 1 on success
*/
static int _fill_in_coords(List results, List start_list,
uint16_t *geometry, int conn_type)
{
ba_mp_t *ba_node = NULL;
ba_mp_t *check_node = NULL;
int rc = 1;
ListIterator itr = NULL;
int y=0, z=0;
ba_switch_t *curr_switch = NULL;
ba_switch_t *next_switch = NULL;
if (!start_list || !results)
return 0;
/* go through the start_list and add all the midplanes */
itr = list_iterator_create(start_list);
while ((check_node = (ba_mp_t*) list_next(itr))) {
curr_switch = &check_node->axis_switch[X];
for(y=0; y<geometry[Y]; y++) {
if ((check_node->coord[Y]+y) >= DIM_SIZE[Y]) {
rc = 0;
goto failed;
}
for(z=0; z<geometry[Z]; z++) {
if ((check_node->coord[Z]+z) >= DIM_SIZE[Z]) {
rc = 0;
goto failed;
}
ba_node = &ba_main_grid
[check_node->coord[X]]
[check_node->coord[Y]+y]
[check_node->coord[Z]+z];
if ((ba_node->coord[Y] == check_node->coord[Y])
&& (ba_node->coord[Z]
== check_node->coord[Z]))
continue;
if (!_node_used(ba_node, geometry[X])) {
if (ba_debug_flags
& DEBUG_FLAG_BG_ALGO_DEEP)
info("here Adding %c%c%c",
alpha_num[ba_node->
coord[X]],
alpha_num[ba_node->
coord[Y]],
alpha_num[ba_node->
coord[Z]]);
list_append(results, ba_node);
next_switch = &ba_node->axis_switch[X];
/* since we are going off the
* main system we can send NULL
* here
*/
_copy_the_path(NULL, curr_switch,
next_switch,
0, X);
} else {
rc = 0;
goto failed;
}
}
}
}
list_iterator_destroy(itr);
itr = list_iterator_create(start_list);
check_node = (ba_mp_t*) list_next(itr);
list_iterator_destroy(itr);
itr = list_iterator_create(results);
while ((ba_node = (ba_mp_t*) list_next(itr))) {
if (!_find_yz_path(ba_node,
check_node->coord,
geometry,
conn_type)){
rc = 0;
goto failed;
}
}
if (deny_pass) {
if ((*deny_pass & PASS_DENY_Y)
&& (*deny_pass & PASS_FOUND_Y)) {
debug("We don't allow Y passthoughs");
rc = 0;
} else if ((*deny_pass & PASS_DENY_Z)
&& (*deny_pass & PASS_FOUND_Z)) {
debug("We don't allow Z passthoughs");
rc = 0;
}
}
failed:
list_iterator_destroy(itr);
return rc;
}
/*
* Copy a path through the wiring of a switch to another switch on a
* starting port on a dimension.
*
* IN/OUT: nodes - Local list of midplanes you are keeping track of. If
* you visit any new midplanes a copy from ba_main_grid
* will be added to the list. If NULL the path will be
* set in mark_switch of the main virtual system (ba_main_grid).
* IN: curr_switch - The switch you want to copy the path of
* IN/OUT: mark_switch - The switch you want to fill in. On success
* this switch will contain a complete path from the curr_switch
* starting from the source port.
* IN: source - source port number (If calling for the first time
* should be 0 since we are looking for 1 at the end)
* IN: dim - Dimension XYZ
*
* RET: on success 1, on error 0
*/
static int _copy_the_path(List nodes, ba_switch_t *curr_switch,
ba_switch_t *mark_switch,
int source, int dim)
{
uint16_t *mp_tar;
uint16_t *mark_mp_tar;
uint16_t *node_curr;
uint16_t port_tar, port_tar1;
ba_switch_t *next_switch = NULL;
ba_switch_t *next_mark_switch = NULL;
/* Copy the source used and port_tar */
mark_switch->int_wire[source].used =
curr_switch->int_wire[source].used;
mark_switch->int_wire[source].port_tar =
curr_switch->int_wire[source].port_tar;
port_tar = curr_switch->int_wire[source].port_tar;
/* Now to the same thing from the other end */
mark_switch->int_wire[port_tar].used =
curr_switch->int_wire[port_tar].used;
mark_switch->int_wire[port_tar].port_tar =
curr_switch->int_wire[port_tar].port_tar;
port_tar1 = port_tar;
/* follow the path */
node_curr = curr_switch->ext_wire[0].mp_tar;
mp_tar = curr_switch->ext_wire[port_tar].mp_tar;
if (mark_switch->int_wire[source].used)
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("setting dim %d %c%c%c %d-> %c%c%c %d",
dim,
alpha_num[node_curr[X]],
alpha_num[node_curr[Y]],
alpha_num[node_curr[Z]],
source,
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]],
port_tar);
if (port_tar == 1) {
/* found the end of the line */
mark_switch->int_wire[1].used =
curr_switch->int_wire[1].used;
mark_switch->int_wire[1].port_tar =
curr_switch->int_wire[1].port_tar;
return 1;
}
mark_mp_tar = mark_switch->ext_wire[port_tar].mp_tar;
port_tar = curr_switch->ext_wire[port_tar].port_tar;
if (node_curr[X] == mp_tar[X]
&& node_curr[Y] == mp_tar[Y]
&& node_curr[Z] == mp_tar[Z]) {
/* We are going to the same node! this should never
happen */
debug5("something bad happened!! "
"we are on %c%c%c and are going to it "
"from port %d - > %d",
alpha_num[node_curr[X]],
alpha_num[node_curr[Y]],
alpha_num[node_curr[Z]],
port_tar1, port_tar);
return 0;
}
/* see what the next switch is going to be */
next_switch = &ba_main_grid[mp_tar[X]][mp_tar[Y]][mp_tar[Z]].
axis_switch[dim];
if (!nodes) {
/* If no nodes then just get the next switch to fill
in from the main system */
next_mark_switch = &ba_main_grid[mark_mp_tar[X]]
[mark_mp_tar[Y]]
[mark_mp_tar[Z]]
.axis_switch[dim];
} else {
ba_mp_t *ba_node = NULL;
ListIterator itr = list_iterator_create(nodes);
/* see if we have already been to this node */
while ((ba_node = list_next(itr))) {
if (ba_node->coord[X] == mark_mp_tar[X] &&
ba_node->coord[Y] == mark_mp_tar[Y] &&
ba_node->coord[Z] == mark_mp_tar[Z])
break; /* we found it */
}
list_iterator_destroy(itr);
if (!ba_node) {
/* If node grab a copy and add it to the list */
ba_node = ba_copy_mp(&ba_main_grid[mark_mp_tar[X]]
[mark_mp_tar[Y]]
[mark_mp_tar[Z]]);
ba_setup_mp(ba_node, false, false);
list_push(nodes, ba_node);
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("haven't seen %c%c%c adding it",
alpha_num[ba_node->coord[X]],
alpha_num[ba_node->coord[Y]],
alpha_num[ba_node->coord[Z]]);
}
next_mark_switch = &ba_node->axis_switch[dim];
}
/* Keep going until we reach the end of the line */
return _copy_the_path(nodes, next_switch, next_mark_switch,
port_tar, dim);
}
static int _find_yz_path(ba_mp_t *ba_node, uint16_t *first,
uint16_t *geometry, int conn_type)
{
ba_mp_t *next_node = NULL;
uint16_t *mp_tar = NULL;
ba_switch_t *dim_curr_switch = NULL;
ba_switch_t *dim_next_switch = NULL;
int i2;
int count = 0;
for(i2=1;i2<=2;i2++) {
if (geometry[i2] > 1) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("%d node %c%c%c port 2 -> ",
i2,
alpha_num[ba_node->coord[X]],
alpha_num[ba_node->coord[Y]],
alpha_num[ba_node->coord[Z]]);
dim_curr_switch = &ba_node->axis_switch[i2];
if (dim_curr_switch->int_wire[2].used) {
debug5("returning here");
return 0;
}
mp_tar = dim_curr_switch->ext_wire[2].mp_tar;
next_node =
&ba_main_grid[mp_tar[X]][mp_tar[Y]][mp_tar[Z]];
dim_next_switch = &next_node->axis_switch[i2];
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("%c%c%c port 5",
alpha_num[next_node->coord[X]],
alpha_num[next_node->coord[Y]],
alpha_num[next_node->coord[Z]]);
if (dim_next_switch->int_wire[5].used) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("returning here 2");
return 0;
}
debug5("%d %d %d %d",i2, mp_tar[i2],
first[i2], geometry[i2]);
/* Here we need to see where we are in
* reference to the geo of this dimension. If
* we have not gotten the number we need in
* the direction we just go to the next node
* with 5 -> 1. If we have all the midplanes
* we need then we go through and finish the
* torus if needed
*/
if (mp_tar[i2] < first[i2])
count = mp_tar[i2]+(DIM_SIZE[i2]-first[i2]);
else
count = (mp_tar[i2]-first[i2]);
if (count == geometry[i2]) {
debug5("found end of me %c%c%c",
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]]);
if (conn_type == SELECT_TORUS) {
dim_curr_switch->int_wire[0].used = 1;
dim_curr_switch->int_wire[0].port_tar
= 2;
dim_curr_switch->int_wire[2].used = 1;
dim_curr_switch->int_wire[2].port_tar
= 0;
dim_curr_switch = dim_next_switch;
if (deny_pass
&& (mp_tar[i2] != first[i2])) {
if (i2 == 1)
*deny_pass |=
PASS_FOUND_Y;
else
*deny_pass |=
PASS_FOUND_Z;
}
while (mp_tar[i2] != first[i2]) {
if (ba_debug_flags
& DEBUG_FLAG_BG_ALGO_DEEP)
info("on dim %d at %d "
"looking for %d",
i2,
mp_tar[i2],
first[i2]);
if (dim_curr_switch->
int_wire[2].used) {
if (ba_debug_flags
& DEBUG_FLAG_BG_ALGO_DEEP)
info("returning"
" here 3");
return 0;
}
dim_curr_switch->
int_wire[2].used = 1;
dim_curr_switch->
int_wire[2].port_tar
= 5;
dim_curr_switch->
int_wire[5].used
= 1;
dim_curr_switch->
int_wire[5].
port_tar = 2;
mp_tar = dim_curr_switch->
ext_wire[2].mp_tar;
next_node = &ba_main_grid
[mp_tar[X]]
[mp_tar[Y]]
[mp_tar[Z]];
dim_curr_switch =
&next_node->
axis_switch[i2];
}
if (ba_debug_flags
& DEBUG_FLAG_BG_ALGO_DEEP)
info("back to first on dim %d "
"at %d looking for %d",
i2,
mp_tar[i2],
first[i2]);
dim_curr_switch->
int_wire[5].used = 1;
dim_curr_switch->
int_wire[5].port_tar
= 1;
dim_curr_switch->
int_wire[1].used
= 1;
dim_curr_switch->
int_wire[1].
port_tar = 5;
}
} else if (count < geometry[i2]) {
if (conn_type == SELECT_TORUS ||
(conn_type == SELECT_MESH &&
(mp_tar[i2] != first[i2]))) {
dim_curr_switch->
int_wire[0].used = 1;
dim_curr_switch->
int_wire[0].port_tar
= 2;
dim_curr_switch->
int_wire[2].used
= 1;
dim_curr_switch->
int_wire[2].
port_tar = 0;
dim_next_switch->int_wire[5].used
= 1;
dim_next_switch->
int_wire[5].port_tar
= 1;
dim_next_switch->
int_wire[1].used = 1;
dim_next_switch->
int_wire[1].port_tar
= 5;
}
} else {
error("We were only looking for %d "
"in the %d dim, but now we have %d",
geometry[i2], i2, count);
return 0;
}
} else if ((geometry[i2] == 1) && (conn_type == SELECT_TORUS)) {
/* FIX ME: This is put here because we got
into a state where the Y dim was not being
processed correctly. This will set up the
0 -> 1 port correctly. We should probably
find out why this was happening in the
first place though. A reproducer was to
have
MPs=[310x323] Type=TORUS
MPs=[200x233] Type=TORUS
MPs=[300x303] Type=TORUS
MPs=[100x133] Type=TORUS
MPs=[000x033] Type=TORUS
MPs=[400x433] Type=TORUS
and then add
MPs=[330x333] Type=TORUS
*/
dim_curr_switch = &ba_node->axis_switch[i2];
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("%d node %c%c%c port 0 -> 1",
i2,
alpha_num[ba_node->coord[X]],
alpha_num[ba_node->coord[Y]],
alpha_num[ba_node->coord[Z]]);
dim_curr_switch->int_wire[0].used = 1;
dim_curr_switch->int_wire[0].port_tar = 1;
dim_curr_switch->int_wire[1].used = 1;
dim_curr_switch->int_wire[1].port_tar = 0;
}
}
return 1;
}
#ifndef HAVE_BG_FILES
/** */
static int _emulate_ext_wiring(ba_mp_t ***grid)
{
int x;
ba_mp_t *source = NULL, *target = NULL;
if (cluster_dims == 1) {
for(x=0;x<DIM_SIZE[X];x++) {
source = &grid[x][0][0];
if (x<(DIM_SIZE[X]-1))
target = &grid[x+1][0][0];
else
target = &grid[0][0][0];
_set_external_wires(X, x, source, target);
}
} else {
int y,z;
for(x=0;x<DIM_SIZE[X];x++) {
for(y=0;y<DIM_SIZE[Y];y++) {
for(z=0;z<DIM_SIZE[Z];z++) {
source = &grid[x][y][z];
if (x<(DIM_SIZE[X]-1)) {
target = &grid[x+1][y][z];
} else
target = &grid[0][y][z];
_set_external_wires(X, x, source,
target);
if (y<(DIM_SIZE[Y]-1))
target = &grid[x][y+1][z];
else
target = &grid[x][0][z];
_set_external_wires(Y, y, source,
target);
if (z<(DIM_SIZE[Z]-1))
target = &grid[x][y][z+1];
else
target = &grid[x][y][0];
_set_external_wires(Z, z, source,
target);
}
}
}
}
return 1;
}
#endif
static int _reset_the_path(ba_switch_t *curr_switch, int source,
int target, int dim)
{
uint16_t *mp_tar;
uint16_t *node_curr;
int port_tar, port_tar1;
ba_switch_t *next_switch = NULL;
if (source < 0 || source >= NUM_PORTS_PER_NODE) {
fatal("source port was %d can only be 0->%d",
source, NUM_PORTS_PER_NODE);
}
if (target < 0 || target >= NUM_PORTS_PER_NODE) {
fatal("target port was %d can only be 0->%d",
target, NUM_PORTS_PER_NODE);
}
/*set the switch to not be used */
if (!curr_switch->int_wire[source].used) {
/* This means something overlapping the removing block
already cleared this, or the path just never was
complete in the first place. */
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("I reached the end, the source isn't used");
return 1;
}
curr_switch->int_wire[source].used = 0;
port_tar = curr_switch->int_wire[source].port_tar;
if (port_tar < 0 || port_tar >= NUM_PORTS_PER_NODE) {
fatal("port_tar port was %d can only be 0->%d",
source, NUM_PORTS_PER_NODE);
return 1;
}
port_tar1 = port_tar;
curr_switch->int_wire[source].port_tar = source;
curr_switch->int_wire[port_tar].used = 0;
curr_switch->int_wire[port_tar].port_tar = port_tar;
if (port_tar == target) {
return 1;
}
/* follow the path */
node_curr = curr_switch->ext_wire[0].mp_tar;
mp_tar = curr_switch->ext_wire[port_tar].mp_tar;
port_tar = curr_switch->ext_wire[port_tar].port_tar;
if (source == port_tar1) {
debug("got this bad one %c%c%c %d %d -> %c%c%c %d",
alpha_num[node_curr[X]],
alpha_num[node_curr[Y]],
alpha_num[node_curr[Z]],
source,
port_tar1,
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]],
port_tar);
return 0;
}
debug5("from %c%c%c %d %d -> %c%c%c %d",
alpha_num[node_curr[X]],
alpha_num[node_curr[Y]],
alpha_num[node_curr[Z]],
source,
port_tar1,
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]],
port_tar);
if (node_curr[X] == mp_tar[X]
&& node_curr[Y] == mp_tar[Y]
&& node_curr[Z] == mp_tar[Z]) {
debug5("%d something bad happened!!", dim);
return 0;
}
next_switch =
&ba_main_grid[mp_tar[X]][mp_tar[Y]][mp_tar[Z]].axis_switch[dim];
return _reset_the_path(next_switch, port_tar, target, dim);
// return 1;
}
extern void ba_create_system()
{
int x,y,z, i = 0;
if (ba_main_grid)
ba_destroy_system();
best_count=BEST_COUNT_INIT;
ba_main_grid = (ba_mp_t***)
xmalloc(sizeof(ba_mp_t**) * DIM_SIZE[X]);
for (x=0; x<DIM_SIZE[X]; x++) {
ba_main_grid[x] = (ba_mp_t**)
xmalloc(sizeof(ba_mp_t*) * DIM_SIZE[Y]);
for (y=0; y<DIM_SIZE[Y]; y++) {
ba_main_grid[x][y] = (ba_mp_t*)
xmalloc(sizeof(ba_mp_t)
* DIM_SIZE[Z]);
for (z=0; z<DIM_SIZE[Z]; z++){
ba_mp_t *ba_mp = &ba_main_grid[x][y][z];
ba_mp->coord[X] = x;
ba_mp->coord[Y] = y;
ba_mp->coord[Z] = z;
snprintf(ba_mp->coord_str,
sizeof(ba_mp->coord_str),
"%c%c%c",
alpha_num[ba_mp->coord[X]],
alpha_num[ba_mp->coord[Y]],
alpha_num[ba_mp->coord[Z]]);
ba_setup_mp(ba_mp, true, false);
ba_mp->state = NODE_STATE_IDLE;
/* This might get changed
later, but just incase set
it up here.
*/
ba_mp->index = i++;
}
}
}
if ((cluster_flags & CLUSTER_FLAG_BGL) ||
(cluster_flags & CLUSTER_FLAG_BGP)) {
init_wires();
#ifndef HAVE_BG_FILES
_emulate_ext_wiring(ba_main_grid);
#endif
}
path = list_create(_delete_path_list);
best_path = list_create(_delete_path_list);
}
/** */
extern void ba_destroy_system(void)
{
int x, y;
if (path) {
list_destroy(path);
path = NULL;
}
if (best_path) {
list_destroy(best_path);
best_path = NULL;
}
#ifdef HAVE_BG_FILES
if (bg)
bridge_free_bg(bg);
#endif
_mp_map_initialized = false;
_wires_initialized = true;
if (ba_main_grid) {
for (x=0; x<DIM_SIZE[X]; x++) {
for (y=0; y<DIM_SIZE[Y]; y++)
xfree(ba_main_grid[x][y]);
xfree(ba_main_grid[x]);
}
xfree(ba_main_grid);
ba_main_grid = NULL;
}
}
extern bool ba_sub_block_in_bitmap(select_jobinfo_t *jobinfo,
bitstr_t *usable_bitmap, bool step)
{
/* This shouldn't be called. */
xassert(0);
return false;
}
extern int ba_sub_block_in_bitmap_clear(select_jobinfo_t *jobinfo,
bitstr_t *usable_bitmap)
{
/* this doesn't do anything since above doesn't. */
return SLURM_SUCCESS;
}
extern ba_mp_t *ba_sub_block_in_record(
bg_record_t *bg_record, uint32_t *node_count,
select_jobinfo_t *jobinfo)
{
/* This shouldn't be called. */
xassert(0);
return false;
}
extern int ba_sub_block_in_record_clear(
bg_record_t *bg_record, struct step_record *step_ptr)
{
/* this doesn't do anything since above doesn't. */
return SLURM_SUCCESS;
}
extern void ba_sync_job_to_block(bg_record_t *bg_record,
struct job_record *job_ptr)
{
xassert(bg_record);
xassert(job_ptr);
bg_record->job_running = job_ptr->job_id;
bg_record->job_ptr = job_ptr;
}
extern bitstr_t *ba_create_ba_mp_cnode_bitmap(bg_record_t *bg_record)
{
return NULL;
}
extern void ba_set_ionode_str(bg_record_t *bg_record)
{
char bitstring[BITSIZE];
if (!bg_record->ionode_bitmap)
return;
bit_fmt(bitstring, BITSIZE, bg_record->ionode_bitmap);
bg_record->ionode_str = xstrdup(bitstring);
}
extern struct job_record *ba_remove_job_in_block_job_list(
bg_record_t *bg_record, struct job_record *in_job_ptr)
{
return NULL;
}
static void _delete_path_list(void *object)
{
ba_path_switch_t *path_switch = (ba_path_switch_t *)object;
if (path_switch) {
xfree(path_switch);
}
return;
}
/**
* algorithm for finding match
*/
static int _find_match(select_ba_request_t *ba_request, List results)
{
int x=0;
ba_mp_t *ba_node = NULL;
char *name=NULL;
int startx = DIM_SIZE[X]-1;
uint16_t *geo_ptr;
if (!(cluster_flags & CLUSTER_FLAG_BG))
return 0;
/* set up the geo here */
if (!(geo_ptr = list_peek(ba_request->elongate_geos)))
return 0;
ba_request->rotate_count=0;
ba_request->elongate_count=1;
ba_request->geometry[X] = geo_ptr[X];
ba_request->geometry[Y] = geo_ptr[Y];
ba_request->geometry[Z] = geo_ptr[Z];
if (ba_request->geometry[X]>DIM_SIZE[X]
|| ba_request->geometry[Y]>DIM_SIZE[Y]
|| ba_request->geometry[Z]>DIM_SIZE[Z])
if (!_check_for_options(ba_request))
return 0;
start_again:
x=0;
if (x == startx)
x = startx-1;
while (x!=startx) {
x++;
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("finding %c%c%c try %d",
alpha_num[ba_request->geometry[X]],
alpha_num[ba_request->geometry[Y]],
alpha_num[ba_request->geometry[Z]],
x);
new_node:
ba_node = coord2ba_mp(ba_request->start);
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("starting at %s", ba_node->coord_str);
if (!_node_used(ba_node, ba_request->geometry[X])) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("trying this node %s %c%c%c %d",
ba_node->coord_str,
alpha_num[ba_request->geometry[X]],
alpha_num[ba_request->geometry[Y]],
alpha_num[ba_request->geometry[Z]],
ba_request->conn_type[X]);
name = set_bg_block(results, ba_request);
if (name) {
ba_request->save_name = xstrdup(name);
xfree(name);
return 1;
}
if (results) {
bool is_small = 0;
if (ba_request->conn_type[0] == SELECT_SMALL)
is_small = 1;
remove_block(results, is_small);
list_flush(results);
}
if (ba_request->start_req)
goto requested_end;
//exit(0);
debug2("trying something else");
}
if ((DIM_SIZE[Z] - ba_request->start[Z]-1)
>= ba_request->geometry[Z])
ba_request->start[Z]++;
else {
ba_request->start[Z] = 0;
if ((DIM_SIZE[Y] - ba_request->start[Y]-1)
>= ba_request->geometry[Y])
ba_request->start[Y]++;
else {
ba_request->start[Y] = 0;
if ((DIM_SIZE[X] - ba_request->start[X]-1)
>= ba_request->geometry[X])
ba_request->start[X]++;
else {
if (ba_request->size == 1)
goto requested_end;
if (!_check_for_options(ba_request))
return 0;
else {
memset(ba_request->start, 0,
sizeof(ba_request->
start));
goto start_again;
}
}
}
}
goto new_node;
}
requested_end:
debug2("1 can't allocate");
return 0;
}
/*
* Used to check if midplane is usable in the block we are creating
*
* IN: ba_node - node to check if is used
* IN: x_size - How big is the block in the X dim used to see if the
* wires are full hence making this midplane unusable.
*/
static bool _node_used(ba_mp_t* ba_node, int x_size)
{
ba_switch_t* ba_switch = NULL;
/* if we've used this node in another block already */
if (!ba_node || ba_node->used) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("node %s used", ba_node->coord_str);
return true;
}
/* Check If we've used this node's switches completely in another
block already. Right now we are only needing to look at
the X dim since it is the only one with extra wires. This
can be set up to do all the dim's if in the future if it is
needed. We only need to check this if we are planning on
using more than 1 midplane in the block creation */
if (x_size > 1) {
/* get the switch of the X Dimension */
ba_switch = &ba_node->axis_switch[X];
/* If both of these ports are used then the node
is in use since there are no more wires we
can use since these can not connect to each
other they must be connected to the other ports.
*/
if (ba_switch->int_wire[3].used
&& ba_switch->int_wire[5].used) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("switch full in the X dim on node %s!",
ba_node->coord_str);
return true;
}
}
return false;
}
static void _switch_config(ba_mp_t* source, ba_mp_t* target, int dim,
int port_src, int port_tar)
{
ba_switch_t* config = NULL, *config_tar = NULL;
int i;
if (!source || !target)
return;
config = &source->axis_switch[dim];
config_tar = &target->axis_switch[dim];
for(i=0;i<cluster_dims;i++) {
/* Set the coord of the source target node to the target */
config->ext_wire[port_src].mp_tar[i] = target->coord[i];
/* Set the coord of the target back to the source */
config_tar->ext_wire[port_tar].mp_tar[i] = source->coord[i];
}
/* Set the port of the source target node to the target */
config->ext_wire[port_src].port_tar = port_tar;
/* Set the port of the target back to the source */
config_tar->ext_wire[port_tar].port_tar = port_src;
}
static int _set_external_wires(int dim, int count, ba_mp_t* source,
ba_mp_t* target)
{
#ifdef HAVE_BG_FILES
#ifdef HAVE_BGL
#define UNDER_POS 7
#define NODE_LEN 5
#define VAL_NAME_LEN 12
#else
#define UNDER_POS 9
#define NODE_LEN 7
#define VAL_NAME_LEN 16
#endif
int rc;
int i;
rm_wire_t *my_wire = NULL;
rm_port_t *my_port = NULL;
char *wire_id = NULL;
int from_port, to_port;
int wire_num;
char from_node[NODE_LEN];
char to_node[NODE_LEN];
if (working_cluster_rec) {
error("Can't do this cross-cluster");
return -1;
}
if (!have_db2) {
error("Can't access DB2 library, run from service node");
return -1;
}
if (!bg) {
if ((rc = bridge_get_bg(&bg)) != SLURM_SUCCESS) {
error("bridge_get_BG(): %d", rc);
return -1;
}
}
if (bg == NULL)
return -1;
if ((rc = bridge_get_data(bg, RM_WireNum, &wire_num))
!= SLURM_SUCCESS) {
error("bridge_get_data(RM_BPNum): %d", rc);
wire_num = 0;
}
/* find out system wires on each mp */
for (i=0; i<wire_num; i++) {
if (i) {
if ((rc = bridge_get_data(bg, RM_NextWire, &my_wire))
!= SLURM_SUCCESS) {
error("bridge_get_data(RM_NextWire): %d", rc);
break;
}
} else {
if ((rc = bridge_get_data(bg, RM_FirstWire, &my_wire))
!= SLURM_SUCCESS) {
error("bridge_get_data(RM_FirstWire): %d", rc);
break;
}
}
if ((rc = bridge_get_data(my_wire, RM_WireID, &wire_id))
!= SLURM_SUCCESS) {
error("bridge_get_data(RM_FirstWire): %d", rc);
break;
}
if (!wire_id) {
error("No Wire ID was returned from database");
continue;
}
if (wire_id[UNDER_POS] != '_')
continue;
switch(wire_id[0]) {
case 'X':
dim = X;
break;
case 'Y':
dim = Y;
break;
case 'Z':
dim = Z;
break;
}
if (strlen(wire_id) < VAL_NAME_LEN) {
error("Wire_id isn't correct %s",wire_id);
continue;
}
memset(&from_node, 0, sizeof(from_node));
memset(&to_node, 0, sizeof(to_node));
strncpy(from_node, wire_id+2, NODE_LEN-1);
strncpy(to_node, wire_id+UNDER_POS+1, NODE_LEN-1);
free(wire_id);
if ((rc = bridge_get_data(my_wire, RM_WireFromPort, &my_port))
!= SLURM_SUCCESS) {
error("bridge_get_data(RM_FirstWire): %d", rc);
break;
}
if ((rc = bridge_get_data(my_port, RM_PortID, &from_port))
!= SLURM_SUCCESS) {
error("bridge_get_data(RM_PortID): %d", rc);
break;
}
if ((rc = bridge_get_data(my_wire, RM_WireToPort, &my_port))
!= SLURM_SUCCESS) {
error("bridge_get_data(RM_WireToPort): %d", rc);
break;
}
if ((rc = bridge_get_data(my_port, RM_PortID, &to_port))
!= SLURM_SUCCESS) {
error("bridge_get_data(RM_PortID): %d", rc);
break;
}
source = loc2ba_mp(from_node);
if (!source) {
error("1 loc2ba_mp: mpid %s not known", from_node);
continue;
}
if (!validate_coord(source->coord))
continue;
target = loc2ba_mp(to_node);
if (!target) {
error("2 loc2ba_mp: mpid %s not known", to_node);
continue;
}
if (!validate_coord(target->coord))
continue;
_switch_config(source, target, dim, from_port, to_port);
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("dim %d from %s %d -> %s %d",
dim,
source->coord_str,
from_port,
target->coord_str,
to_port);
}
#else
_switch_config(source, source, dim, 0, 0);
_switch_config(source, source, dim, 1, 1);
if (dim!=X) {
_switch_config(source, target, dim, 2, 5);
_switch_config(source, source, dim, 3, 3);
_switch_config(source, source, dim, 4, 4);
return 1;
}
if (cluster_dims == 1) {
if (count == 0)
_switch_config(source, source, dim, 5, 5);
else if (count < DIM_SIZE[X]-1)
_switch_config(source, target, dim, 2, 5);
else
_switch_config(source, source, dim, 2, 2);
_switch_config(source, source, dim, 3, 3);
_switch_config(source, source, dim, 4, 4);
return 1;
}
/* set up x */
/* always 2->5 of next. If it is the last it will go to the first.*/
_switch_config(source, target, dim, 2, 5);
/* set up split x */
if (DIM_SIZE[X] == 1) {
} else if (DIM_SIZE[X] == 4) {
switch(count) {
case 0:
case 3:
/* 0 and 3rd Node */
/* nothing */
break;
case 1:
/* 1st Node */
target = &ba_main_grid[0]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 0th */
_switch_config(source, target, dim, 4, 3);
break;
case 2:
/* 2nd Node */
target = &ba_main_grid[3]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 3rd and back */
_switch_config(source, target, dim, 4, 3);
_switch_config(source, target, dim, 3, 4);
break;
default:
fatal("got %d for a count on a %d X-dim system",
count, DIM_SIZE[X]);
break;
}
} else if (DIM_SIZE[X] == 5) {
/* 4 X dim fixes for wires */
switch(count) {
case 0:
case 2:
/* 0th and 2nd node */
/* Only the 2-5 is used here
so nothing else */
break;
case 1:
/* 1st node */
/* change target to 4th node */
target = &ba_main_grid[4]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 4th */
_switch_config(source, target, dim, 4, 3);
break;
case 3:
/* 3rd node */
/* change target to 2th node */
target = &ba_main_grid[2]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 2nd */
_switch_config(source, target, dim, 4, 3);
break;
case 4:
/* 4th node */
/* change target to 1st node */
target = &ba_main_grid[1]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 1st */
_switch_config(source, target, dim, 4, 3);
break;
default:
fatal("got %d for a count on a %d X-dim system",
count, DIM_SIZE[X]);
break;
}
} else if (DIM_SIZE[X] == 8) {
switch(count) {
case 0:
case 4:
/* 0 and 4th Node */
/* nothing */
break;
case 1:
case 5:
/* 1st Node */
target = &ba_main_grid[count-1]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of previous */
_switch_config(source, target, dim, 4, 3);
break;
case 2:
/* 2nd Node */
target = &ba_main_grid[7]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of last */
_switch_config(source, target, dim, 4, 3);
break;
case 3:
/* 3rd Node */
target = &ba_main_grid[6]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 6th */
_switch_config(source, target, dim, 4, 3);
break;
case 6:
/* 6th Node */
target = &ba_main_grid[3]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 3rd */
_switch_config(source, target, dim, 4, 3);
break;
case 7:
/* 7th Node */
target = &ba_main_grid[2]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 2nd */
_switch_config(source, target, dim, 4, 3);
break;
default:
fatal("got %d for a count on a %d X-dim system",
count, DIM_SIZE[X]);
break;
}
} else if (DIM_SIZE[X] == 9) {
switch(count) {
case 0:
case 4:
/* 0 and 4th Node */
/* nothing */
case 5:
case 6:
case 7:
/*already handled below */
break;
case 1:
/* 1st Node */
target = &ba_main_grid[7]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 7th and back */
_switch_config(source, target, dim, 4, 3);
_switch_config(target, source, dim, 4, 3);
break;
case 2:
/* 2nd Node */
target = &ba_main_grid[6]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 6th and back */
_switch_config(source, target, dim, 4, 3);
_switch_config(target, source, dim, 4, 3);
break;
case 3:
/* 3rd Node */
target = &ba_main_grid[5]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 5th and back */
_switch_config(source, target, dim, 4, 3);
_switch_config(target, source, dim, 4, 3);
break;
case 8:
/* 8th Node */
target = &ba_main_grid[0]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of 0th */
_switch_config(source, target, dim, 4, 3);
break;
default:
fatal("got %d for a count on a %d X-dim system",
count, DIM_SIZE[X]);
break;
}
} else if (DIM_SIZE[X] == 13) {
int temp_num = 0;
switch(count) {
case 0:
case 6:
/* 0 and 6th Node no split */
case 8:
case 9:
case 10:
case 11:
case 12:
/* already taken care of in the next case so
* do nothing
*/
break;
case 1:
case 2:
case 3:
case 4:
case 5:
/* get the node count - 1 then subtract it
* from 12 to get the new target and then go
* from 4->3 and back again
*/
temp_num = 12 - (count - 1);
if (temp_num < 5)
fatal("node %d shouldn't go to %d",
count, temp_num);
target = &ba_main_grid[temp_num]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 */
_switch_config(source, target, dim, 4, 3);
/* and back 4->3 */
_switch_config(target, source, dim, 4, 3);
break;
case 7:
/* 7th Node */
target = &ba_main_grid[count-1]
[source->coord[Y]]
[source->coord[Z]];
/* 4->3 of previous */
_switch_config(source, target, dim, 4, 3);
break;
default:
fatal("got %d for a count on a %d X-dim system",
count, DIM_SIZE[X]);
break;
}
} else {
fatal("We don't have a config to do a BG system with %d "
"in the X-dim.", DIM_SIZE[X]);
}
#endif
return 1;
}
static char *_set_internal_wires(List nodes, int size, int conn_type)
{
ba_mp_t* ba_node[size+1];
int count=0, i;
uint16_t *start = NULL;
uint16_t *end = NULL;
char *name = NULL;
ListIterator itr;
hostlist_t hostlist;
if (!nodes)
return NULL;
hostlist = hostlist_create(NULL);
itr = list_iterator_create(nodes);
while ((ba_node[count] = list_next(itr))) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("name = %s", ba_node[count]->coord_str);
hostlist_push(hostlist, ba_node[count]->coord_str);
count++;
}
list_iterator_destroy(itr);
start = ba_node[0]->coord;
end = ba_node[count-1]->coord;
name = hostlist_ranged_string_xmalloc(hostlist);
hostlist_destroy(hostlist);
for (i=0;i<count;i++) {
if (!ba_node[i]->used) {
ba_node[i]->used |= BA_MP_USED_TRUE;
} else {
debug("No network connection to create "
"bgblock containing %s", name);
debug("Use smap to define bgblocks in "
"bluegene.conf");
xfree(name);
return NULL;
}
}
if (conn_type == SELECT_TORUS)
for (i=0;i<count;i++) {
_set_one_dim(start, end, ba_node[i]->coord);
}
return name;
}
/*
* Used to find a complete path based on the conn_type for an x dim.
* When starting to wire a block together this should be called first.
*
* IN/OUT: results - contains the number of midplanes we are
* potentially going to use in the X dim.
* IN: ba_node - current node we are looking at and have already added
* to results.
* IN: start - coordinates of the first midplane (so we know when when
* to end with a torus)
* IN: x_size - How many midplanes are we looking for in the X dim
* IN: found - count of how many midplanes we have found in the x dim
* IN: conn_type - MESH or TORUS
* IN: algo - algorythm to try an allocation by
*
* RET: 0 on failure, 1 on success
*/
static int _find_x_path(List results, ba_mp_t *ba_node,
uint16_t *start, int x_size,
int found, int conn_type, block_algo_t algo)
{
ba_switch_t *curr_switch = NULL;
ba_switch_t *next_switch = NULL;
int port_tar = 0;
int source_port=0;
int target_port=1;
int broke = 0, not_first = 0;
int ports_to_try[2] = {4, 2};
uint16_t *mp_tar = NULL;
int i = 0;
ba_mp_t *next_node = NULL;
ba_mp_t *check_node = NULL;
/* int highest_phys_x = x_size - start[X]; */
/* info("highest_phys_x is %d", highest_phys_x); */
ListIterator itr = NULL;
if (!ba_node || !results || !start)
return 0;
curr_switch = &ba_node->axis_switch[X];
/* we don't need to go any further */
if (x_size == 1) {
/* Only set this if Torus since mesh doesn't have any
* connections in this path */
if (conn_type == SELECT_TORUS) {
curr_switch->int_wire[source_port].used = 1;
curr_switch->int_wire[source_port].port_tar =
target_port;
curr_switch->int_wire[target_port].used = 1;
curr_switch->int_wire[target_port].port_tar =
source_port;
}
return 1;
}
if (algo == BLOCK_ALGO_FIRST) {
ports_to_try[0] = 4;
ports_to_try[1] = 2;
} else if (algo == BLOCK_ALGO_SECOND) {
ports_to_try[0] = 2;
ports_to_try[1] = 4;
} else {
error("Unknown algo %d", algo);
return 0;
}
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("Algo(%d) found - %d", algo, found);
/* Check the 2 ports we can leave though in ports_to_try */
for(i=0;i<2;i++) {
/* info("trying port %d", ports_to_try[i]); */
/* check to make sure it isn't used */
if (!curr_switch->int_wire[ports_to_try[i]].used) {
/* looking at the next node on the switch
and it's port we are going to */
mp_tar = curr_switch->
ext_wire[ports_to_try[i]].mp_tar;
port_tar = curr_switch->
ext_wire[ports_to_try[i]].port_tar;
/* info("%c%c%c port %d goes to %c%c%c port %d", */
/* alpha_num[ba_node->coord[X]], */
/* alpha_num[ba_node->coord[Y]], */
/* alpha_num[ba_node->coord[Z]], */
/* ports_to_try[i], */
/* alpha_num[mp_tar[X]], */
/* alpha_num[mp_tar[Y]], */
/* alpha_num[mp_tar[Z]], */
/* port_tar); */
/* check to see if we are back at the start of the
block */
if ((mp_tar[X] == start[X]
&& mp_tar[Y] == start[Y]
&& mp_tar[Z] == start[Z])) {
broke = 1;
goto broke_it;
}
/* check to see if the port points to itself */
if ((mp_tar[X] == ba_node->coord[X]
&& mp_tar[Y] == ba_node->coord[Y]
&& mp_tar[Z] == ba_node->coord[Z])) {
continue;
}
/* check to see if I am going to a place I have
already been before */
itr = list_iterator_create(results);
while ((next_node = list_next(itr))) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("Algo(%d) looking at %c%c%c "
"and %c%c%c",
algo,
alpha_num[next_node->coord[X]],
alpha_num[next_node->coord[Y]],
alpha_num[next_node->coord[Z]],
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]]);
if ((mp_tar[X] == next_node->coord[X]
&& mp_tar[Y] == next_node->coord[Y]
&& mp_tar[Z] == next_node->coord[Z])) {
not_first = 1;
break;
}
}
list_iterator_destroy(itr);
if (not_first && found < DIM_SIZE[X]) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) already been there "
"before", algo);
not_first = 0;
continue;
}
not_first = 0;
broke_it:
next_node = &ba_main_grid[mp_tar[X]]
[mp_tar[Y]]
[mp_tar[Z]];
next_switch = &next_node->axis_switch[X];
if ((conn_type == SELECT_MESH) && (found == (x_size))) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) we found the end of "
"the mesh", algo);
return 1;
}
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("Algo(%d) Broke = %d Found = %d "
"x_size = %d",
algo, broke, found, x_size);
if (broke && (found == x_size)) {
goto found_path;
} else if (found == x_size) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) finishing the torus!",
algo);
if (deny_pass && (*deny_pass & PASS_DENY_X)) {
info("we don't allow passthroughs 1");
return 0;
}
if (best_path)
list_flush(best_path);
else
best_path =
list_create(_delete_path_list);
if (path)
list_flush(path);
else
path = list_create(_delete_path_list);
_finish_torus(results,
curr_switch, 0, X, 0, start);
if (best_count < BEST_COUNT_INIT) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) Found a best "
"path with %d steps.",
algo, best_count);
_set_best_path();
return 1;
} else {
return 0;
}
} else if (broke) {
broke = 0;
continue;
}
if (!_node_used(next_node, x_size)) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) found %d looking at "
"%c%c%c %d going to %c%c%c %d",
algo,
found,
alpha_num[ba_node->coord[X]],
alpha_num[ba_node->coord[Y]],
alpha_num[ba_node->coord[Z]],
ports_to_try[i],
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]],
port_tar);
itr = list_iterator_create(results);
while ((check_node = list_next(itr))) {
if ((mp_tar[X] == check_node->coord[X]
&& mp_tar[Y] ==
check_node->coord[Y]
&& mp_tar[Z] ==
check_node->coord[Z])) {
break;
}
}
list_iterator_destroy(itr);
if (!check_node) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) add %c%c%c",
algo,
alpha_num[next_node->
coord[X]],
alpha_num[next_node->
coord[Y]],
alpha_num[next_node->
coord[Z]]);
list_append(results, next_node);
} else {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) Hey this is "
"already added %c%c%c",
algo,
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]]);
continue;
}
found++;
/* look for the next closest midplane */
if (!_find_x_path(results, next_node,
start, x_size,
found, conn_type, algo)) {
_remove_node(results, next_node->coord);
found--;
continue;
} else {
found_path:
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) added node "
"%c%c%c %d %d -> "
"%c%c%c %d %d",
algo,
alpha_num[ba_node->
coord[X]],
alpha_num[ba_node->
coord[Y]],
alpha_num[ba_node->
coord[Z]],
source_port,
ports_to_try[i],
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]],
port_tar,
target_port);
curr_switch->int_wire[source_port].used
= 1;
curr_switch->int_wire
[source_port].port_tar
= ports_to_try[i];
curr_switch->int_wire
[ports_to_try[i]].used = 1;
curr_switch->int_wire
[ports_to_try[i]].port_tar
= source_port;
next_switch->int_wire[port_tar].used
= 1;
next_switch->int_wire[port_tar].port_tar
= target_port;
next_switch->int_wire[target_port].used
= 1;
next_switch->int_wire
[target_port].port_tar
= port_tar;
return 1;
}
}
}
}
if (algo == BLOCK_ALGO_FIRST) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) couldn't find path", algo);
return 0;
} else if (algo == BLOCK_ALGO_SECOND) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) looking for the next free node "
"starting at %c%c%c",
algo,
alpha_num[ba_node->coord[X]],
alpha_num[ba_node->coord[Y]],
alpha_num[ba_node->coord[Z]]);
if (best_path)
list_flush(best_path);
else
best_path = list_create(_delete_path_list);
if (path)
list_flush(path);
else
path = list_create(_delete_path_list);
_find_next_free_using_port_2(curr_switch, 0, results, X, 0);
if (best_count < BEST_COUNT_INIT) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) yes found next free %d", algo,
best_count);
mp_tar = _set_best_path();
if (deny_pass && (*deny_pass & PASS_DENY_X)
&& (*deny_pass & PASS_FOUND_X)) {
debug("We don't allow X passthoughs.");
return 0;
}
/* info("got here with %c%c%c", */
/* alpha_num[mp_tar[X]], */
/* alpha_num[mp_tar[Y]], */
/* alpha_num[mp_tar[Z]]); */
next_node = &ba_main_grid[mp_tar[X]]
[mp_tar[Y]]
[mp_tar[Z]];
next_switch = &next_node->axis_switch[X];
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) found %d looking at %c%c%c "
"going to %c%c%c %d",
algo, found,
alpha_num[ba_node->coord[X]],
alpha_num[ba_node->coord[Y]],
alpha_num[ba_node->coord[Z]],
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]],
port_tar);
list_append(results, next_node);
found++;
if (_find_x_path(results, next_node,
start, x_size, found,
conn_type, algo)) {
return 1;
} else {
found--;
_reset_the_path(curr_switch, 0, 1, X);
_remove_node(results, next_node->coord);
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) couldn't finish "
"the path off this one", algo);
}
}
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("Algo(%d) couldn't find path", algo);
return 0;
}
error("We got here meaning there is a bad algo, "
"but this should never happen algo(%d)", algo);
return 0;
}
static int _remove_node(List results, uint16_t *mp_tar)
{
ListIterator itr;
ba_mp_t *ba_node = NULL;
itr = list_iterator_create(results);
while ((ba_node = (ba_mp_t*) list_next(itr))) {
#ifdef HAVE_BG_L_P
if (mp_tar[X] == ba_node->coord[X]
&& mp_tar[Y] == ba_node->coord[Y]
&& mp_tar[Z] == ba_node->coord[Z]) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("removing %c%c%c from list",
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]]);
list_remove (itr);
break;
}
#else
if (mp_tar[X] == ba_node->coord[X]) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("removing %d from list",
mp_tar[X]);
list_remove (itr);
break;
}
#endif
}
list_iterator_destroy(itr);
return 1;
}
static int _find_next_free_using_port_2(ba_switch_t *curr_switch,
int source_port,
List nodes,
int dim,
int count)
{
ba_switch_t *next_switch = NULL;
ba_path_switch_t *path_add =
(ba_path_switch_t *) xmalloc(sizeof(ba_path_switch_t));
ba_path_switch_t *path_switch = NULL;
ba_path_switch_t *temp_switch = NULL;
uint16_t port_tar;
int target_port = 0;
int port_to_try = 2;
uint16_t *mp_tar= curr_switch->ext_wire[0].mp_tar;
uint16_t *node_src = curr_switch->ext_wire[0].mp_tar;
int used = 0;
int broke = 0;
ba_mp_t *ba_node = NULL;
ListIterator itr;
path_add->geometry[X] = node_src[X];
#ifdef HAVE_3D
path_add->geometry[Y] = node_src[Y];
path_add->geometry[Z] = node_src[Z];
#endif
path_add->dim = dim;
path_add->in = source_port;
if (count>=best_count)
goto return_0;
itr = list_iterator_create(nodes);
while ((ba_node = (ba_mp_t*) list_next(itr))) {
if (mp_tar[X] == ba_node->coord[X]
&& mp_tar[Y] == ba_node->coord[Y]
&& mp_tar[Z] == ba_node->coord[Z]) {
broke = 1;
break;
}
}
list_iterator_destroy(itr);
if (!broke && count>0 &&
!ba_main_grid[mp_tar[X]][mp_tar[Y]][mp_tar[Z]].used) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("this one not found %c%c%c",
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]]);
broke = 0;
if ((source_port%2))
target_port=1;
list_flush(best_path);
path_add->out = target_port;
list_push(path, path_add);
itr = list_iterator_create(path);
while ((path_switch = (ba_path_switch_t*) list_next(itr))){
temp_switch = (ba_path_switch_t *)
xmalloc(sizeof(ba_path_switch_t));
temp_switch->geometry[X] = path_switch->geometry[X];
temp_switch->geometry[Y] = path_switch->geometry[Y];
temp_switch->geometry[Z] = path_switch->geometry[Z];
temp_switch->dim = path_switch->dim;
temp_switch->in = path_switch->in;
temp_switch->out = path_switch->out;
list_append(best_path, temp_switch);
}
list_iterator_destroy(itr);
best_count = count;
return 1;
}
used=0;
if (!curr_switch->int_wire[port_to_try].used) {
itr = list_iterator_create(path);
while ((path_switch =
(ba_path_switch_t*) list_next(itr))){
if (((path_switch->geometry[X] == node_src[X])
&& (path_switch->geometry[Y] == node_src[Y])
&& (path_switch->geometry[Z] == mp_tar[Z]))) {
if ( path_switch->out
== port_to_try) {
used = 1;
break;
}
}
}
list_iterator_destroy(itr);
/* check to see if wire 0 is used with this port */
if (curr_switch->
ext_wire[port_to_try].mp_tar[X]
== curr_switch->ext_wire[0].mp_tar[X]
&& curr_switch->ext_wire[port_to_try].mp_tar[Y]
== curr_switch->ext_wire[0].mp_tar[Y]
&& curr_switch->ext_wire[port_to_try].mp_tar[Z]
== curr_switch->ext_wire[0].mp_tar[Z]) {
used = 1;
}
if (!used) {
port_tar = curr_switch->
ext_wire[port_to_try].port_tar;
mp_tar = curr_switch->
ext_wire[port_to_try].mp_tar;
next_switch = &ba_main_grid
[mp_tar[X]][mp_tar[Y]][mp_tar[Z]]
.axis_switch[X];
count++;
path_add->out = port_to_try;
list_push(path, path_add);
_find_next_free_using_port_2(next_switch,
port_tar, nodes,
dim, count);
while ((temp_switch = list_pop(path)) != path_add){
xfree(temp_switch);
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("something here 1");
}
}
}
return_0:
xfree(path_add);
return 0;
}
/*
* Used to tie the end of the block to the start. best_path and path
* should both be set up before calling this function.
*
* IN: curr_switch -
* IN: source_port -
* IN: dim -
* IN: count -
* IN: start -
*
* RET: 0 on failure, 1 on success
*
* Sets up global variable best_path, and best_count. On success
* best_count will be >= BEST_COUNT_INIT you can call _set_best_path
* to apply this path to the main system (ba_main_grid)
*/
static int _finish_torus(List results,
ba_switch_t *curr_switch, int source_port,
int dim, int count, uint16_t *start)
{
ba_switch_t *next_switch = NULL;
ba_path_switch_t *path_add = xmalloc(sizeof(ba_path_switch_t));
ba_path_switch_t *path_switch = NULL;
ba_path_switch_t *temp_switch = NULL;
uint16_t port_tar;
int target_port=0;
int ports_to_try[2] = {3,5};
uint16_t *mp_tar= curr_switch->ext_wire[0].mp_tar;
uint16_t *node_src = curr_switch->ext_wire[0].mp_tar;
int i;
int used=0;
ListIterator itr;
path_add->geometry[X] = node_src[X];
path_add->geometry[Y] = node_src[Y];
path_add->geometry[Z] = node_src[Z];
path_add->dim = dim;
path_add->in = source_port;
if (count>=best_count) {
xfree(path_add);
return 0;
}
if (mp_tar[X] == start[X]
&& mp_tar[Y] == start[Y]
&& mp_tar[Z] == start[Z]) {
if ((source_port%2))
target_port=1;
if (!curr_switch->int_wire[target_port].used) {
list_flush(best_path);
path_add->out = target_port;
list_push(path, path_add);
itr = list_iterator_create(path);
while ((path_switch = list_next(itr))) {
temp_switch = xmalloc(sizeof(ba_path_switch_t));
temp_switch->geometry[X] =
path_switch->geometry[X];
temp_switch->geometry[Y] =
path_switch->geometry[Y];
temp_switch->geometry[Z] =
path_switch->geometry[Z];
temp_switch->dim = path_switch->dim;
temp_switch->in = path_switch->in;
temp_switch->out = path_switch->out;
list_append(best_path,temp_switch);
}
list_iterator_destroy(itr);
best_count = count;
return 1;
}
}
if (source_port==0 || source_port==3 || source_port==5) {
ports_to_try[0] = 4;
ports_to_try[1] = 2;
}
for(i=0;i<2;i++) {
used=0;
if (!curr_switch->int_wire[ports_to_try[i]].used) {
itr = list_iterator_create(path);
while ((path_switch = list_next(itr))){
if (((path_switch->geometry[X] == node_src[X])
&& (path_switch->geometry[Y]
== node_src[Y])
&& (path_switch->geometry[Z]
== mp_tar[Z]))) {
if ( path_switch->out
== ports_to_try[i]) {
used = 1;
break;
}
}
}
list_iterator_destroy(itr);
/* check to see if wire 0 is used with this port */
if ((curr_switch->
ext_wire[ports_to_try[i]].mp_tar[X] ==
curr_switch->ext_wire[0].mp_tar[X] &&
curr_switch->
ext_wire[ports_to_try[i]].mp_tar[Y] ==
curr_switch->ext_wire[0].mp_tar[Y] &&
curr_switch->
ext_wire[ports_to_try[i]].mp_tar[Z] ==
curr_switch->ext_wire[0].mp_tar[Z])) {
continue;
}
if (!used) {
ba_mp_t *next_node = NULL;
port_tar = curr_switch->
ext_wire[ports_to_try[i]].port_tar;
mp_tar = curr_switch->
ext_wire[ports_to_try[i]].mp_tar;
/* Check to see if I am going to a place I have
already been before, because even
though we may be able to do this
electrically this doesn't mean the
under lying infrastructure will
allow it. */
itr = list_iterator_create(results);
while ((next_node = list_next(itr))) {
if (ba_debug_flags
& DEBUG_FLAG_BG_ALGO_DEEP)
info("finishing_torus: "
"looking at %c%c%c "
"and %c%c%c",
alpha_num[next_node->
coord[X]],
alpha_num[next_node->
coord[Y]],
alpha_num[next_node->
coord[Z]],
alpha_num[mp_tar[X]],
alpha_num[mp_tar[Y]],
alpha_num[mp_tar[Z]]);
if ((mp_tar[X] == next_node->coord[X])
&& (mp_tar[Y]
== next_node->coord[Y])
&& (mp_tar[Z]
== next_node->coord[Z])) {
break;
}
}
list_iterator_destroy(itr);
if (next_node) {
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO)
info("finishing_torus: "
"Can't finish torus with "
"%c%c%c we already were "
"there.",
alpha_num[next_node->
coord[X]],
alpha_num[next_node->
coord[Y]],
alpha_num[next_node->
coord[Z]]);
continue;
}
next_switch = &ba_main_grid
[mp_tar[X]][mp_tar[Y]][mp_tar[Z]]
.axis_switch[dim];
count++;
path_add->out = ports_to_try[i];
list_push(path, path_add);
_finish_torus(results, next_switch, port_tar,
dim, count, start);
while ((temp_switch = list_pop(path))
!= path_add){
xfree(temp_switch);
if (ba_debug_flags
& DEBUG_FLAG_BG_ALGO_DEEP)
info("something here 3");
}
}
}
}
xfree(path_add);
return 0;
}
/*
* using best_path set up previously from _finish_torus or
* _find_next_free_using_port_2. Will set up the path contained there
* into the main virtual system. With will also set the passthrough
* flag if there was a passthrough used.
*/
static uint16_t *_set_best_path()
{
ListIterator itr;
ba_path_switch_t *path_switch = NULL;
ba_switch_t *curr_switch = NULL;
uint16_t *geo = NULL;
if (!best_path)
return NULL;
itr = list_iterator_create(best_path);
while ((path_switch = (ba_path_switch_t*) list_next(itr))) {
if (deny_pass && path_switch->in > 1 && path_switch->out > 1) {
*deny_pass |= PASS_FOUND_X;
debug2("got a passthrough in X");
}
if (ba_debug_flags & DEBUG_FLAG_BG_ALGO_DEEP)
info("mapping %c%c%c %d->%d",
alpha_num[path_switch->geometry[X]],
alpha_num[path_switch->geometry[Y]],
alpha_num[path_switch->geometry[Z]],
path_switch->in, path_switch->out);
if (!geo)
geo = path_switch->geometry;
curr_switch = &ba_main_grid
[path_switch->geometry[X]]
[path_switch->geometry[Y]]
[path_switch->geometry[Z]].
axis_switch[path_switch->dim];
curr_switch->int_wire[path_switch->in].used = 1;
curr_switch->int_wire[path_switch->in].port_tar =
path_switch->out;
curr_switch->int_wire[path_switch->out].used = 1;
curr_switch->int_wire[path_switch->out].port_tar =
path_switch->in;
}
list_iterator_destroy(itr);
best_count=BEST_COUNT_INIT;
return geo;
}
static int _set_one_dim(uint16_t *start, uint16_t *end, uint16_t *coord)
{
int dim;
ba_switch_t *curr_switch = NULL;
for(dim=0;dim<cluster_dims;dim++) {
if (start[dim]==end[dim]) {
curr_switch = &ba_main_grid
[coord[X]][coord[Y]][coord[Z]].axis_switch[dim];
if (!curr_switch->int_wire[0].used
&& !curr_switch->int_wire[1].used) {
curr_switch->int_wire[0].used = 1;
curr_switch->int_wire[0].port_tar = 1;
curr_switch->int_wire[1].used = 1;
curr_switch->int_wire[1].port_tar = 0;
}
}
}
return 1;
}
static void _destroy_geo(void *object)
{
uint16_t *geo_ptr = (uint16_t *)object;
xfree(geo_ptr);
}