now concho computes the price of the memory as well
- the empty machine price is now correct (the base memory is substracted) - also displays the mem size on the graph now that all machines don't have the same amount of memory nb : work involved for Bug 2886 - Devis pour l'achat d'un nouveau noeud pour le cluster (crédits TS 2020)
This commit is contained in:
parent
93a8b77231
commit
053d0f17ac
|
@ -17,6 +17,7 @@ class Chassis(Item):
|
|||
self.num_cpu_slots_per_server = 2
|
||||
if re.match('dell-poweredge-r9.*', uid):
|
||||
self.num_cpu_slots_per_server = 4
|
||||
self.num_dimm_slots_per_channel = 2
|
||||
|
||||
class Dimm(Item):
|
||||
|
||||
|
@ -34,7 +35,7 @@ class Cpu(Item):
|
|||
super().__init__(proc_id)
|
||||
cpuTable = numpy.genfromtxt('cpu_table.dat', dtype=("|U32", float, int, float, float, float), names=True, delimiter='\t')
|
||||
for cpu_id, clock, num_cores, tdp, cpumark in zip(cpuTable['id'], cpuTable['clock'], cpuTable['num_cores'], cpuTable['tdp'], cpuTable['cpumark_1_cpu']):
|
||||
print(cpu_id)
|
||||
# print(cpu_id)
|
||||
if cpu_id == proc_id:
|
||||
# print('found '+procId)
|
||||
break
|
||||
|
@ -174,6 +175,15 @@ def get_simd_id(proc_arch):
|
|||
'coffeelake':'avx2'
|
||||
}[proc_arch]
|
||||
|
||||
class MemChannel():
|
||||
|
||||
def __init__(self):
|
||||
self.dimms = []
|
||||
|
||||
class CpuSlotMem():
|
||||
|
||||
def __init__(self):
|
||||
self.mem_channels = []
|
||||
|
||||
class Config():
|
||||
|
||||
|
@ -182,7 +192,8 @@ class Config():
|
|||
self.num_servers = 0
|
||||
self.num_cpu_per_server = 0
|
||||
self.cpu = None
|
||||
self.dimms_per_channel = []
|
||||
self.cpu_slots_mem = []
|
||||
|
||||
|
||||
@property
|
||||
def chassis(self):
|
||||
|
@ -236,16 +247,39 @@ class Config():
|
|||
# dimm_capacity = 16
|
||||
dimm = self.configurator.get_dimm(dimm_capacity)
|
||||
assert dimm
|
||||
self.dimms_per_channel = [ dimm ]
|
||||
print(cpu.uid, cpu.num_cores, ram_per_channel)
|
||||
for cpu_slot_mem in self.cpu_slots_mem:
|
||||
for mem_channel in cpu_slot_mem.mem_channels:
|
||||
for dimm_slot_index in range(self.configurator.chassis.item.num_dimm_slots_per_channel):
|
||||
mem_channel.dimms[dimm_slot_index] = dimm
|
||||
|
||||
@property
|
||||
def ram_size(self):
|
||||
ram_size = 0
|
||||
for cpu_slot_mem in self.cpu_slots_mem:
|
||||
for mem_channel in cpu_slot_mem.mem_channels:
|
||||
for dimm_slot_index in range(self.configurator.chassis.item.num_dimm_slots_per_channel):
|
||||
dimm = mem_channel.dimms[dimm_slot_index]
|
||||
if dimm is not None:
|
||||
dimm = self.configurator.get_item(dimm.uid)
|
||||
ram_size += self.num_servers * dimm.num_gb
|
||||
return ram_size
|
||||
|
||||
@property
|
||||
def ram_price(self):
|
||||
ram_price = 0.0
|
||||
for cpu_slot_mem in self.cpu_slots_mem:
|
||||
for mem_channel in cpu_slot_mem.mem_channels:
|
||||
for dimm_slot_index in range(self.configurator.chassis.item.num_dimm_slots_per_channel):
|
||||
dimm = mem_channel.dimms[dimm_slot_index]
|
||||
if dimm is not None:
|
||||
dimm_price = self.configurator.get_item_price(dimm.uid)
|
||||
ram_price += self.num_servers * dimm_price
|
||||
return ram_price
|
||||
|
||||
|
||||
def get_price(self):
|
||||
price = self.configurator.chassis.price
|
||||
price += self.num_servers * self.num_cpu_per_server * self.configurator.get_item_price(self.cpu.uid)
|
||||
for dimm in self.dimms_per_channel:
|
||||
dimm_price = self.configurator.get_item_price(dimm.uid)
|
||||
price += self.num_servers * self.num_cpu_per_server * self.cpu.num_ram_channels * dimm_price
|
||||
# print("ram_price : %f € for %d dimms of %d Gb" % (ram_price, self.num_servers * self.num_cpu_per_server * cpu.num_ram_channels, dimm_capacity))
|
||||
price += self.num_servers * self.num_cpu_per_server * self.configurator.get_item_price(self.cpu.uid) + self.ram_price
|
||||
assert price > 0.0
|
||||
return price
|
||||
|
||||
|
@ -261,7 +295,21 @@ class Config():
|
|||
|
||||
def set_cpu(self, cpu):
|
||||
self.cpu = cpu
|
||||
# create the dimm slots
|
||||
self.cpu_slots_mem = []
|
||||
for cpu_index in range(self.num_cpu_per_server):
|
||||
cpu_slot_mem = CpuSlotMem()
|
||||
|
||||
for channel_index in range(cpu.num_ram_channels):
|
||||
mem_channel = MemChannel()
|
||||
for dimm_slot_index in range(self.configurator.chassis.item.num_dimm_slots_per_channel):
|
||||
mem_channel.dimms.append(None) # dimm slots are empty
|
||||
cpu_slot_mem.mem_channels.append(mem_channel)
|
||||
self.cpu_slots_mem.append(cpu_slot_mem)
|
||||
|
||||
@property
|
||||
def num_cpus(self):
|
||||
return self.num_cpu_per_server * self.num_servers
|
||||
|
||||
class Option():
|
||||
|
||||
|
@ -305,6 +353,11 @@ class Configurator():
|
|||
return dimm
|
||||
assert False, 'failed to find an option for a dimm of capacity %d gb' % dimm_capacity
|
||||
|
||||
def get_item(self, item_uid):
|
||||
for module in self.modules.values():
|
||||
if item_uid in module.options:
|
||||
return module.options[item_uid].item
|
||||
|
||||
def get_item_price(self, item_uid):
|
||||
for module in self.modules.values():
|
||||
if item_uid in module.options:
|
||||
|
|
|
@ -487,11 +487,9 @@ class DellConfiguratorParser():
|
|||
assert False, 'unhandled label : %s' % label
|
||||
return ram_options
|
||||
|
||||
def _parse_base_config(self, html_root, configurator):
|
||||
base_config = Config(configurator)
|
||||
base_config.num_servers = configurator.chassis.item.max_num_servers
|
||||
base_config.num_cpu_per_server = 1
|
||||
module_root_element = DellConfiguratorParser._get_module(html_root, 'Processeurs (Passage)')
|
||||
@classmethod
|
||||
def _get_module_default_item(cls, module_label, html_root):
|
||||
module_root_element = DellConfiguratorParser._get_module(html_root, module_label)
|
||||
assert module_root_element is not None
|
||||
for option_root_element in module_root_element.xpath(".//div[@class='row']"):
|
||||
label_elements = option_root_element.xpath(".//div[@class='option-selected ']")
|
||||
|
@ -499,15 +497,37 @@ class DellConfiguratorParser():
|
|||
if len(label_elements) > 0:
|
||||
label = label_elements[0].text_content().replace('\n', '')
|
||||
price = DellConfiguratorParser.price_str_as_float(option_root_element.xpath(".//div[@class='col-md-3 text-right option-price option-price-selected']")[0].text_content())
|
||||
assert price == 0.0
|
||||
# print(label, price)
|
||||
# Processeur Intel Xeon Silver 4208 2.1GHz,11M Cache,9.60GT/s, 2UPI,No Turbo, HT,8C/16T (85W) - DDR4-2400
|
||||
match = re.match(r'^Processeur Intel Xeon (?P<cpu_class>Silver|Gold|Platinium) (?P<cpu_number>[0-9][0-9][0-9][0-9][RLYU]?).*', label)
|
||||
assert match, 'unhandled label : %s' % label
|
||||
# print(match['cpu_class'], match['cpu_number'])
|
||||
cpu_id = "intel-xeon-%s-%s" % (match['cpu_class'].lower(), match['cpu_number'].lower())
|
||||
base_config.set_cpu(Cpu(cpu_id))
|
||||
assert base_config.cpu is not None
|
||||
assert price == 0.0, 'default items are expected to have a price of 0.0 € (%s s price is %f)' % (label, price)
|
||||
return label
|
||||
assert False, 'failed to find the default item of module %s' % module_label
|
||||
|
||||
def _parse_base_config(self, html_root, configurator):
|
||||
base_config = Config(configurator)
|
||||
base_config.num_servers = configurator.chassis.item.max_num_servers
|
||||
base_config.num_cpu_per_server = 1
|
||||
|
||||
# initialize cpu
|
||||
item_label = DellConfiguratorParser._get_module_default_item('Processeurs (Passage)', html_root)
|
||||
# Processeur Intel Xeon Silver 4208 2.1GHz,11M Cache,9.60GT/s, 2UPI,No Turbo, HT,8C/16T (85W) - DDR4-2400
|
||||
match = re.match(r'^Processeur Intel Xeon (?P<cpu_class>Silver|Gold|Platinium) (?P<cpu_number>[0-9][0-9][0-9][0-9][RLYU]?).*', item_label)
|
||||
assert match, 'unhandled label : %s' % item_label
|
||||
# print(match['cpu_class'], match['cpu_number'])
|
||||
cpu_id = "intel-xeon-%s-%s" % (match['cpu_class'].lower(), match['cpu_number'].lower())
|
||||
base_config.set_cpu(Cpu(cpu_id))
|
||||
|
||||
# initialize the default ram dimms
|
||||
item_label = DellConfiguratorParser._get_module_default_item('Mémoires (Passage)', html_root)
|
||||
# Mémoire 16 Go DDR4 à 2933MHz (1x16Go)
|
||||
match = re.match(r'^Mémoire (?P<num_gb>[0-9]+) Go DDR4 à (?P<num_mhz>[0-9]+)MHz \((?P<num_dimms>[0-9]+)x(?P<num_gb2>[0-9]+)Go\)', item_label)
|
||||
assert match, 'unhandled label : %s' % item_label
|
||||
assert int(match['num_dimms']) == 1
|
||||
assert match['num_gb'] == match['num_gb2']
|
||||
# print(match['cpu_class'], match['cpu_number'])
|
||||
cpu_slot_index = 0
|
||||
mem_channel_index = 0
|
||||
dimm_slot = 0
|
||||
base_config.cpu_slots_mem[cpu_slot_index].mem_channels[mem_channel_index].dimms[dimm_slot] = Dimm(num_gb=int(match['num_gb']), num_mhz=int(match['num_mhz']), mem_type='rdimm')
|
||||
|
||||
return base_config
|
||||
|
||||
|
||||
|
@ -570,7 +590,8 @@ class DellConfiguratorParser():
|
|||
assert price_value_element is not None
|
||||
base_price = DellConfiguratorParser.price_str_as_float(price_value_element.text_content())
|
||||
assert base_price is not None
|
||||
configurator.chassis.price = base_price - configurator.get_item_price(configurator.base_config.cpu.uid)
|
||||
|
||||
configurator.chassis.price = base_price - configurator.base_config.num_cpus * configurator.get_item_price(configurator.base_config.cpu.uid) - configurator.base_config.ram_price
|
||||
|
||||
class DellMatinfoConfigurator(Configurator):
|
||||
|
||||
|
@ -583,5 +604,12 @@ class DellMatinfoConfigurator(Configurator):
|
|||
|
||||
|
||||
def create_config(self):
|
||||
return copy.copy(self.base_config)
|
||||
# config = copy.deepcopy(self.base_config)
|
||||
config = Config(self)
|
||||
config.num_servers = self.base_config.num_servers
|
||||
config.num_cpu_per_server = self.base_config.num_cpu_per_server
|
||||
config.set_cpu(self.base_config.cpu)
|
||||
config.cpu_slots_mem = copy.deepcopy(self.base_config.cpu_slots_mem)
|
||||
|
||||
return config
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ def plot_system_efficiency():
|
|||
|
||||
def getColorCodeFromItemLabel(label):
|
||||
generation=label[-1]
|
||||
(model, proc_id) = re.split('_', label)
|
||||
(model, proc_id, ram_size) = re.split('_', label)
|
||||
saturation = {
|
||||
'sandy bridge':0.0,
|
||||
'ivy bridge':0.2,
|
||||
|
@ -113,7 +113,7 @@ def plot_system_efficiency():
|
|||
return matplotlib.colors.hsv_to_rgb((hue, saturation, value))
|
||||
|
||||
def get_marker_from_label(label):
|
||||
(model, proc_id) = re.split('_', label)
|
||||
(model, proc_id, ram_size) = re.split('_', label)
|
||||
return get_marker(proc_id)
|
||||
|
||||
|
||||
|
@ -125,14 +125,14 @@ def plot_system_efficiency():
|
|||
dell.DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html')]
|
||||
# dell.DellPowerEdgeR940()]
|
||||
for configurator in configurators:
|
||||
config = configurator.create_config()
|
||||
for cpu in configurator.get_cpu_options():
|
||||
if not cpu.architecture in ['coffeelake', 'skylake','cascadelake']:
|
||||
continue
|
||||
item_label = numpy.append( item_label, config.chassis.uid + '_' + cpu.uid )
|
||||
config = configurator.create_config()
|
||||
config.set_cpu(cpu)
|
||||
config.set_ram(ram_per_core=4.0e9)
|
||||
config.num_cpu_per_server = config.configurator.chassis.item.num_cpu_slots_per_server
|
||||
item_label = numpy.append( item_label, config.chassis.uid + '_' + cpu.uid + '_' + str(config.ram_size) + 'gb' )
|
||||
# print('procOptionPrice', procOptionPrice)
|
||||
# config_price = procOptionPrice
|
||||
# config_price += config.get_empty_price()
|
||||
|
@ -146,6 +146,7 @@ def plot_system_efficiency():
|
|||
# print('config.config.get_guarantee_price(5)', config.get_guarantee_price(5))
|
||||
# config_price += config.get_disk_upgrade_price(2.0e12)
|
||||
# print('config.get_disk_upgrade_price(2.0e12)', config.get_disk_upgrade_price(2.0e12))
|
||||
# print(item_label, config.get_price(), config.get_power_consumption())
|
||||
item_price = numpy.append( item_price, config.get_price() )
|
||||
item_power_consumption = numpy.append( item_power_consumption, config.get_power_consumption())
|
||||
# # print(hostTypeId, procId, item_power_consumption[-1])
|
||||
|
|
Loading…
Reference in New Issue