CpuAttributes* buildSlot( MachAttributes *m_attr, int slot_id, StringList* list, int type, bool except ) { typedef CpuAttributes::slotres_map_t slotres_map_t; int cpus = UNSET_SHARE; int ram = UNSET_SHARE; float disk = UNSET_SHARE; float swap = UNSET_SHARE; float share; slotres_map_t slotres; float default_share = AUTO_SHARE; MyString execute_dir, partition_id; GetConfigExecuteDir( slot_id, &execute_dir, &partition_id ); if ( list == NULL) { // give everything the default share and return cpus = compute_cpus( m_attr->num_cpus(), default_share ); ram = compute_phys_mem( m_attr, default_share ); swap = default_share; disk = default_share; for (slotres_map_t::const_iterator j(m_attr->machres().begin()); j != m_attr->machres().end(); ++j) { slotres[j->first] = default_share; } return new CpuAttributes( m_attr, type, cpus, ram, swap, disk, slotres, execute_dir, partition_id ); } // For this parsing code, deal with the following example // string list: // "c=1, r=25%, d=1/4, s=25%" // There may be a bare number (no equals sign) that specifies // the default share for any items not explicitly defined. Example: // "c=1, 25%" for (slotres_map_t::const_iterator j(m_attr->machres().begin()); j != m_attr->machres().end(); ++j) { slotres[j->first] = AUTO_RES; } list->rewind(); while (char* attrp = list->next()) { string attr_expr = attrp; string::size_type eqpos = attr_expr.find('='); if (string::npos == eqpos) { // There's no = in this description, it must be one // percentage or fraction for all attributes. // For example "1/4" or "25%". So, we can just parse // it as a percentage and use that for everything. default_share = parse_value(attr_expr.c_str(), type, except); if( default_share <= 0 && !IS_AUTO_SHARE(default_share) ) { dprintf( D_ALWAYS, "ERROR: Bad description of slot type %d: ", type ); dprintf( D_ALWAYS | D_NOHEADER, "\"%s\" is invalid.\n", attr_expr.c_str() ); dprintf( D_ALWAYS | D_NOHEADER, "\tYou must specify a percentage (like \"25%%\"), " ); dprintf( D_ALWAYS | D_NOHEADER, "a fraction (like \"1/4\"),\n" ); dprintf( D_ALWAYS | D_NOHEADER, "\tor list all attributes (like \"c=1, r=25%%, s=25%%, d=25%%\").\n" ); dprintf( D_ALWAYS | D_NOHEADER, "\tSee the manual for details.\n" ); if( except ) { DC_Exit( 4 ); } else { return NULL; } } continue; } // If we're still here, this is part of a string that // lists out seperate attributes and the share for each one. // Get the value for this attribute. It'll either be a // percentage, or it'll be a distinct value (in which // case, parse_value() will return negative. string val = attr_expr.substr(1+eqpos); if (val.empty()) { dprintf(D_ALWAYS, "Can't parse attribute \"%s\" in description of slot type %d\n", attr_expr.c_str(), type); if( except ) { DC_Exit( 4 ); } else { return NULL; } } share = parse_value(val.c_str(), type, except); // Figure out what attribute we're dealing with. string attr = attr_expr.substr(0, eqpos); slotres_map_t::const_iterator f(m_attr->machres().find(attr)); if (f != m_attr->machres().end()) { slotres[f->first] = compute_local_resource(share, attr, m_attr->machres()); continue; } switch( tolower(attr[0]) ) { case 'c': cpus = compute_cpus( m_attr->num_cpus(), share ); break; case 'r': case 'm': ram = compute_phys_mem( m_attr, share ); break; case 's': case 'v': if( share >= 0 || IS_AUTO_SHARE(share) ) { swap = share; } else { dprintf( D_ALWAYS, "You must specify a percent or fraction for swap in slot type %d\n", type ); if( except ) { DC_Exit( 4 ); } else { return NULL; } } break; case 'd': if( share >= 0 || IS_AUTO_SHARE(share) ) { disk = share; } else { dprintf( D_ALWAYS, "You must specify a percent or fraction for disk in slot type %d\n", type ); if( except ) { DC_Exit( 4 ); } else { return NULL; } } break; default: dprintf( D_ALWAYS, "Unknown attribute \"%s\" in slot type %d\n", attr.c_str(), type ); if( except ) { DC_Exit( 4 ); } else { return NULL; } break; } } // We're all done parsing the string. Any attribute not // listed will get the default share. if (IS_UNSET_SHARE(cpus)) { cpus = compute_cpus( m_attr->num_cpus(), default_share ); } if (IS_UNSET_SHARE(ram)) { ram = compute_phys_mem( m_attr, default_share ); } if (IS_UNSET_SHARE(swap)) { swap = default_share; } if (IS_UNSET_SHARE(disk)) { disk = default_share; } for (slotres_map_t::iterator j(slotres.begin()); j != slotres.end(); ++j) { if (int(j->second) == AUTO_RES) { j->second = compute_local_resource(default_share, j->first, m_attr->machres()); } } // Now create the object. return new CpuAttributes( m_attr, type, cpus, ram, swap, disk, slotres, execute_dir, partition_id ); }
CpuAttributes* buildSlot( MachAttributes *m_attr, int slot_id, StringList* list, int type, bool except ) { typedef CpuAttributes::slotres_map_t slotres_map_t; double cpus = UNSET_SHARE; int ram = UNSET_SHARE; // this is in MB so an int is enough double disk_fraction = UNSET_SHARE; double swap_fraction = UNSET_SHARE; slotres_map_t slotres; special_share_t default_share_special = SPECIAL_SHARE_AUTO; double default_share = AUTO_SHARE; bool allow_fractional_cpu = false; MyString execute_dir, partition_id; GetConfigExecuteDir( slot_id, &execute_dir, &partition_id ); if ( list == NULL) { // give everything the default share and return cpus = compute_local_resource(m_attr->num_cpus(), default_share, 1.0); ram = compute_local_resource(m_attr->phys_mem(), default_share, 1); for (slotres_map_t::const_iterator j(m_attr->machres().begin()); j != m_attr->machres().end(); ++j) { slotres[j->first] = default_share; } return new CpuAttributes( m_attr, type, cpus, ram, AUTO_SHARE, AUTO_SHARE, slotres, execute_dir, partition_id ); } // For this parsing code, deal with the following example // string list: // "c=1, r=25%, d=1/4, s=25%" // There may be a bare number (no equals sign) that specifies // the default share for any items not explicitly defined. Example: // "c=1, 25%" for (slotres_map_t::const_iterator j(m_attr->machres().begin()); j != m_attr->machres().end(); ++j) { slotres[j->first] = UNSET_SHARE; } list->rewind(); while (char* attrp = list->next()) { string attr_expr = attrp; string::size_type eqpos = attr_expr.find('='); if (string::npos == eqpos) { // There's no = in this description, it must be one // percentage or fraction for all attributes. // For example "1/4" or "25%". So, we can just parse // it as a percentage and use that for everything. default_share = parse_share_value(attr_expr.c_str(), type, except, default_share_special); if (default_share_special == SPECIAL_SHARE_NONE && (default_share < -1 || default_share > 0)) { dprintf( D_ALWAYS, "ERROR: Bad description of slot type %d: " "\"%s\" is invalid.\n" "\tYou must specify a percentage (like \"25%%\"), " "a fraction (like \"1/4\"),\n" "\tor list all attributes (like \"c=1, r=25%%, s=25%%, d=25%%\").\n" "\tSee the manual for details.\n", type, attr_expr.c_str()); if( except ) { DC_Exit( 4 ); } else { return NULL; } } if (default_share_special == SPECIAL_SHARE_MINIMAL) allow_fractional_cpu = true; continue; } // If we're still here, this is part of a string that // lists out seperate attributes and the share for each one. // Get the value for this attribute. It'll either be a // percentage, or it'll be a distinct value (in which // case, parse_share_value() will return negative. string val = attr_expr.substr(1+eqpos); if (val.empty()) { dprintf(D_ALWAYS, "Can't parse attribute \"%s\" in description of slot type %d\n", attr_expr.c_str(), type); if( except ) { DC_Exit( 4 ); } else { return NULL; } } special_share_t share_special = SPECIAL_SHARE_NONE; double share = parse_share_value(val.c_str(), type, except, share_special); // Figure out what attribute we're dealing with. string attr = attr_expr.substr(0, eqpos); trim(attr); slotres_map_t::const_iterator f(m_attr->machres().find(attr)); if (f != m_attr->machres().end()) { slotres[f->first] = compute_local_resource(f->second, share); continue; } // before 8.1.4, only the first character of standard resource types // was looked at (case insensitively). This prevented us from detecting // typos in resource type names that start with c,r,m,s,v or d. // This code now compares the whole resource type name // But to preserve (most) of the pre 8.1.4 we will tolerate // any case-insensitive substring match of cpus, ram, memory, swap, virtualmemory, or disk int cattr = int(attr.length()); if (MATCH == strncasecmp(attr.c_str(), "cpus", cattr)) { double lower_bound = (allow_fractional_cpu) ? 0.0 : 1.0; cpus = compute_local_resource(m_attr->num_cpus(), share, lower_bound); } else if ( MATCH == strncasecmp(attr.c_str(), "ram", cattr) || MATCH == strncasecmp(attr.c_str(), "memory", cattr)) { ram = compute_local_resource(m_attr->phys_mem(), share, 1); } else if ( MATCH == strncasecmp(attr.c_str(), "swap", cattr) || MATCH == strncasecmp(attr.c_str(), "virtualmemory", cattr)) { // for now, we can only tolerate swap expressed a 'auto' or a proportion // because we don't know how much disk is available until later. if (share <= 0 || IS_AUTO_SHARE(share)) { swap_fraction = compute_local_resource(1.0, share); } else { dprintf( D_ALWAYS, "You must specify a percent or fraction for swap in slot type %d\n", type ); if( except ) { DC_Exit( 4 ); } else { return NULL; } } } else if ( MATCH == strncasecmp(attr.c_str(), "disk", cattr)) { // for now, we can only tolerate swap expressed a 'auto' or a proportion // because we don't know how much disk is available until later. if (share <= 0 || IS_AUTO_SHARE(share)) { disk_fraction = compute_local_resource(1.0, share); } else { dprintf( D_ALWAYS, "You must specify a percent or fraction for disk in slot type %d\n", type ); if( except ) { DC_Exit( 4 ); } else { return NULL; } } } else { // at this point in the code a non-zero amount of the resource is requested only if share > 0. // requesting non-zero amounts of *unknown* resources is a fatal error // but requesting 0 or a share of the remainder isn't. this makes it possible // to have a common config between machines that can be used to express things // like - "if this machine has GPUs, I don't want this slot to get any".. if (share > 0) { dprintf( D_ALWAYS, "Unknown attribute \"%s\" in slot type %d\n", attr.c_str(), type); if( except ) { DC_Exit( 4 ); } else { return NULL; } } else { dprintf( D_ALWAYS | D_FULLDEBUG, "Unknown attribute \"%s\" in slot type %d, no resources will be allocated\n", attr.c_str(), type); } } } int std_resource_lower_bound = (allow_fractional_cpu) ? 0 : 1; // We're all done parsing the string. Any attribute not // listed will get the default share. if (IS_UNSET_SHARE(cpus)) { cpus = compute_local_resource(m_attr->num_cpus(), default_share, (double)std_resource_lower_bound); } if (IS_UNSET_SHARE(ram)) { ram = compute_local_resource(m_attr->phys_mem(), default_share, std_resource_lower_bound); } if (IS_UNSET_SHARE(swap_fraction)) { swap_fraction = compute_local_resource(1.0, default_share); } if (IS_UNSET_SHARE(disk_fraction)) { disk_fraction = compute_local_resource(1.0, default_share); } for (slotres_map_t::iterator j(slotres.begin()); j != slotres.end(); ++j) { if (IS_UNSET_SHARE(j->second)) { slotres_map_t::const_iterator f(m_attr->machres().find(j->first)); // it shouldn't be possible to get here with keys in slotres that aren't in machres // but if it should happen it's a benign error, just allocate 0 of the unknown resource. double avail = (f != m_attr->machres().end()) ? f->second : 0; j->second = compute_local_resource(avail, default_share); } } // Now create the object. return new CpuAttributes( m_attr, type, cpus, ram, swap_fraction, disk_fraction, slotres, execute_dir, partition_id ); }