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
|
self.num_cpu_slots_per_server = 2
|
||||||
if re.match('dell-poweredge-r9.*', uid):
|
if re.match('dell-poweredge-r9.*', uid):
|
||||||
self.num_cpu_slots_per_server = 4
|
self.num_cpu_slots_per_server = 4
|
||||||
|
self.num_dimm_slots_per_channel = 2
|
||||||
|
|
||||||
class Dimm(Item):
|
class Dimm(Item):
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ class Cpu(Item):
|
||||||
super().__init__(proc_id)
|
super().__init__(proc_id)
|
||||||
cpuTable = numpy.genfromtxt('cpu_table.dat', dtype=("|U32", float, int, float, float, float), names=True, delimiter='\t')
|
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']):
|
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:
|
if cpu_id == proc_id:
|
||||||
# print('found '+procId)
|
# print('found '+procId)
|
||||||
break
|
break
|
||||||
|
@ -174,6 +175,15 @@ def get_simd_id(proc_arch):
|
||||||
'coffeelake':'avx2'
|
'coffeelake':'avx2'
|
||||||
}[proc_arch]
|
}[proc_arch]
|
||||||
|
|
||||||
|
class MemChannel():
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.dimms = []
|
||||||
|
|
||||||
|
class CpuSlotMem():
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.mem_channels = []
|
||||||
|
|
||||||
class Config():
|
class Config():
|
||||||
|
|
||||||
|
@ -182,7 +192,8 @@ class Config():
|
||||||
self.num_servers = 0
|
self.num_servers = 0
|
||||||
self.num_cpu_per_server = 0
|
self.num_cpu_per_server = 0
|
||||||
self.cpu = None
|
self.cpu = None
|
||||||
self.dimms_per_channel = []
|
self.cpu_slots_mem = []
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def chassis(self):
|
def chassis(self):
|
||||||
|
@ -236,16 +247,39 @@ class Config():
|
||||||
# dimm_capacity = 16
|
# dimm_capacity = 16
|
||||||
dimm = self.configurator.get_dimm(dimm_capacity)
|
dimm = self.configurator.get_dimm(dimm_capacity)
|
||||||
assert dimm
|
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):
|
def get_price(self):
|
||||||
price = self.configurator.chassis.price
|
price = self.configurator.chassis.price
|
||||||
price += self.num_servers * self.num_cpu_per_server * self.configurator.get_item_price(self.cpu.uid)
|
price += self.num_servers * self.num_cpu_per_server * self.configurator.get_item_price(self.cpu.uid) + self.ram_price
|
||||||
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))
|
|
||||||
assert price > 0.0
|
assert price > 0.0
|
||||||
return price
|
return price
|
||||||
|
|
||||||
|
@ -261,7 +295,21 @@ class Config():
|
||||||
|
|
||||||
def set_cpu(self, cpu):
|
def set_cpu(self, cpu):
|
||||||
self.cpu = 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():
|
class Option():
|
||||||
|
|
||||||
|
@ -305,6 +353,11 @@ class Configurator():
|
||||||
return dimm
|
return dimm
|
||||||
assert False, 'failed to find an option for a dimm of capacity %d gb' % dimm_capacity
|
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):
|
def get_item_price(self, item_uid):
|
||||||
for module in self.modules.values():
|
for module in self.modules.values():
|
||||||
if item_uid in module.options:
|
if item_uid in module.options:
|
||||||
|
|
|
@ -487,11 +487,9 @@ class DellConfiguratorParser():
|
||||||
assert False, 'unhandled label : %s' % label
|
assert False, 'unhandled label : %s' % label
|
||||||
return ram_options
|
return ram_options
|
||||||
|
|
||||||
def _parse_base_config(self, html_root, configurator):
|
@classmethod
|
||||||
base_config = Config(configurator)
|
def _get_module_default_item(cls, module_label, html_root):
|
||||||
base_config.num_servers = configurator.chassis.item.max_num_servers
|
module_root_element = DellConfiguratorParser._get_module(html_root, module_label)
|
||||||
base_config.num_cpu_per_server = 1
|
|
||||||
module_root_element = DellConfiguratorParser._get_module(html_root, 'Processeurs (Passage)')
|
|
||||||
assert module_root_element is not None
|
assert module_root_element is not None
|
||||||
for option_root_element in module_root_element.xpath(".//div[@class='row']"):
|
for option_root_element in module_root_element.xpath(".//div[@class='row']"):
|
||||||
label_elements = option_root_element.xpath(".//div[@class='option-selected ']")
|
label_elements = option_root_element.xpath(".//div[@class='option-selected ']")
|
||||||
|
@ -499,15 +497,37 @@ class DellConfiguratorParser():
|
||||||
if len(label_elements) > 0:
|
if len(label_elements) > 0:
|
||||||
label = label_elements[0].text_content().replace('\n', '')
|
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())
|
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
|
assert price == 0.0, 'default items are expected to have a price of 0.0 € (%s s price is %f)' % (label, price)
|
||||||
# print(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
|
# 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)
|
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' % label
|
assert match, 'unhandled label : %s' % item_label
|
||||||
# print(match['cpu_class'], match['cpu_number'])
|
# print(match['cpu_class'], match['cpu_number'])
|
||||||
cpu_id = "intel-xeon-%s-%s" % (match['cpu_class'].lower(), match['cpu_number'].lower())
|
cpu_id = "intel-xeon-%s-%s" % (match['cpu_class'].lower(), match['cpu_number'].lower())
|
||||||
base_config.set_cpu(Cpu(cpu_id))
|
base_config.set_cpu(Cpu(cpu_id))
|
||||||
assert base_config.cpu is not None
|
|
||||||
|
# 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
|
return base_config
|
||||||
|
|
||||||
|
|
||||||
|
@ -570,7 +590,8 @@ class DellConfiguratorParser():
|
||||||
assert price_value_element is not None
|
assert price_value_element is not None
|
||||||
base_price = DellConfiguratorParser.price_str_as_float(price_value_element.text_content())
|
base_price = DellConfiguratorParser.price_str_as_float(price_value_element.text_content())
|
||||||
assert base_price is not None
|
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):
|
class DellMatinfoConfigurator(Configurator):
|
||||||
|
|
||||||
|
@ -583,5 +604,12 @@ class DellMatinfoConfigurator(Configurator):
|
||||||
|
|
||||||
|
|
||||||
def create_config(self):
|
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):
|
def getColorCodeFromItemLabel(label):
|
||||||
generation=label[-1]
|
generation=label[-1]
|
||||||
(model, proc_id) = re.split('_', label)
|
(model, proc_id, ram_size) = re.split('_', label)
|
||||||
saturation = {
|
saturation = {
|
||||||
'sandy bridge':0.0,
|
'sandy bridge':0.0,
|
||||||
'ivy bridge':0.2,
|
'ivy bridge':0.2,
|
||||||
|
@ -113,7 +113,7 @@ def plot_system_efficiency():
|
||||||
return matplotlib.colors.hsv_to_rgb((hue, saturation, value))
|
return matplotlib.colors.hsv_to_rgb((hue, saturation, value))
|
||||||
|
|
||||||
def get_marker_from_label(label):
|
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)
|
return get_marker(proc_id)
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,14 +125,14 @@ def plot_system_efficiency():
|
||||||
dell.DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html')]
|
dell.DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html')]
|
||||||
# dell.DellPowerEdgeR940()]
|
# dell.DellPowerEdgeR940()]
|
||||||
for configurator in configurators:
|
for configurator in configurators:
|
||||||
config = configurator.create_config()
|
|
||||||
for cpu in configurator.get_cpu_options():
|
for cpu in configurator.get_cpu_options():
|
||||||
if not cpu.architecture in ['coffeelake', 'skylake','cascadelake']:
|
if not cpu.architecture in ['coffeelake', 'skylake','cascadelake']:
|
||||||
continue
|
continue
|
||||||
item_label = numpy.append( item_label, config.chassis.uid + '_' + cpu.uid )
|
config = configurator.create_config()
|
||||||
config.set_cpu(cpu)
|
config.set_cpu(cpu)
|
||||||
config.set_ram(ram_per_core=4.0e9)
|
config.set_ram(ram_per_core=4.0e9)
|
||||||
config.num_cpu_per_server = config.configurator.chassis.item.num_cpu_slots_per_server
|
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)
|
# print('procOptionPrice', procOptionPrice)
|
||||||
# config_price = procOptionPrice
|
# config_price = procOptionPrice
|
||||||
# config_price += config.get_empty_price()
|
# 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))
|
# print('config.config.get_guarantee_price(5)', config.get_guarantee_price(5))
|
||||||
# config_price += config.get_disk_upgrade_price(2.0e12)
|
# 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('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_price = numpy.append( item_price, config.get_price() )
|
||||||
item_power_consumption = numpy.append( item_power_consumption, config.get_power_consumption())
|
item_power_consumption = numpy.append( item_power_consumption, config.get_power_consumption())
|
||||||
# # print(hostTypeId, procId, item_power_consumption[-1])
|
# # print(hostTypeId, procId, item_power_consumption[-1])
|
||||||
|
|
Loading…
Reference in New Issue