added support for r940 (obtained from dell matinfo web page)

This commit is contained in:
Guillaume Raffy 2020-09-30 11:53:17 +02:00
parent 1340c1b980
commit c588821707
3 changed files with 688 additions and 16 deletions

View File

@ -425,15 +425,20 @@ class DellConfiguratorParser():
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 ']")[0].text_content()) price = DellConfiguratorParser.price_str_as_float(option_root_element.xpath(".//div[@class='col-md-3 text-right option-price ']")[0].text_content())
# print(label, price) # print(label, price)
num_cpus = 1
# Passage à processeur Intel Xeon Gold 6240L 2.6GHz, 24.75M Cache,10.40GT/s, 2UPI, Turbo, HT,18C/36T (150W) - DDR4-2933 # Passage à processeur Intel Xeon Gold 6240L 2.6GHz, 24.75M Cache,10.40GT/s, 2UPI, Turbo, HT,18C/36T (150W) - DDR4-2933
match = re.match(r'^Passage à 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'^Passage à processeur Intel Xeon (?P<cpu_class>Silver|Gold|Platinium) (?P<cpu_number>[0-9][0-9][0-9][0-9][RLYU]?).*', label)
if match is None:
# Passage à 2 Processeurs Intel Xeon Gold 6240L 2.6GHz, 24.75M Cache,10.40GT/s, 2UPI, Turbo, HT,18C/36T (150W) - DDR4-2933
match = re.match(r'^passage à 2 processeurs intel xeon (?P<cpu_class>silver|gold|platinium) (?P<cpu_number>[0-9][0-9][0-9][0-9][rly]?).*', label.lower())
assert match, 'unhandled label : %s' % label assert match, 'unhandled label : %s' % label
num_cpus = 2
# print(match['cpu_class'], match['cpu_number']) # print(match['cpu_class'], match['cpu_number'])
cpu_class = match['cpu_class'].lower() cpu_class = match['cpu_class'].lower()
if cpu_class == 'platinium': if cpu_class == 'platinium':
cpu_class = 'platinum' cpu_class = 'platinum'
cpu_id = "intel-xeon-%s-%s" % (cpu_class, match['cpu_number'].lower()) cpu_id = "intel-xeon-%s-%s" % (cpu_class, match['cpu_number'].lower())
option = Option(Cpu(cpu_id), price) option = Option(Cpu(cpu_id), price / num_cpus)
proc_options.add_option(option) proc_options.add_option(option)
return proc_options return proc_options
@ -447,15 +452,21 @@ class DellConfiguratorParser():
label = label_elements[0].text_content() label = label_elements[0].text_content()
price = DellConfiguratorParser.price_str_as_float(option_root_element.xpath(".//div[@class='col-md-3 text-right option-price ']")[0].text_content()) price = DellConfiguratorParser.price_str_as_float(option_root_element.xpath(".//div[@class='col-md-3 text-right option-price ']")[0].text_content())
# print(label, price) # print(label, price)
num_additional_cpus = 1
match = re.match(r'^Processeur additionnel Intel Xeon (?P<cpu_class>Silver|Gold|Platinium) (?P<cpu_number>[0-9][0-9][0-9][0-9][RLY]?).*', label) match = re.match(r'^Processeur additionnel Intel Xeon (?P<cpu_class>Silver|Gold|Platinium) (?P<cpu_number>[0-9][0-9][0-9][0-9][RLY]?).*', label)
assert match if match is None:
# Ajout de 2 Processeurs Intel Xeon Gold 6240L 2.6GHz, 24.75M Cache,10.40GT/s, 2UPI, Turbo, HT,18C/36T (150W) - DDR4-2933
match = re.match(r'^ajout de 2 processeurs intel xeon (?P<cpu_class>silver|gold|platinium) (?P<cpu_number>[0-9][0-9][0-9][0-9][rly]?).*', label.lower())
assert match, 'unhandled label : %s' % label
num_additional_cpus = 2
# print(match['cpu_class'], match['cpu_number']) # print(match['cpu_class'], match['cpu_number'])
cpu_class = match['cpu_class'].lower() cpu_class = match['cpu_class'].lower()
if cpu_class == 'platinium': if cpu_class == 'platinium':
cpu_class = 'platinum' cpu_class = 'platinum'
cpu_id = "intel-xeon-%s-%s" % (cpu_class, match['cpu_number'].lower()) cpu_id = "intel-xeon-%s-%s" % (cpu_class, match['cpu_number'].lower())
option = Option(Cpu(cpu_id), price) option = Option(Cpu(cpu_id), price / num_additional_cpus)
proc_options.add_option(option) proc_options.add_option(option)
assert len(proc_options.options) > 0
return proc_options return proc_options
def _parse_ram_options(self, html_root): def _parse_ram_options(self, html_root):
@ -471,8 +482,14 @@ class DellConfiguratorParser():
# Ajout d'une barette de 128Go 2667 Mhz LRDIMM # Ajout d'une barette de 128Go 2667 Mhz LRDIMM
match = re.match(r'^Ajout d\'une barette de (?P<num_gb>[0-9]+)Go (?P<num_mhz>[0-9][0-9][0-9][0-9]) Mhz (?P<mem_type>LRDIMM|RDIMM)$', label) match = re.match(r'^Ajout d\'une barette de (?P<num_gb>[0-9]+)Go (?P<num_mhz>[0-9][0-9][0-9][0-9]) Mhz (?P<mem_type>LRDIMM|RDIMM)$', label)
if match: if match:
# print(match['num_gb'], match['num_mhz']) # print(match['num_gb'], match['num_mhz'])
dimm = Dimm(num_gb=int(match['num_gb']), num_mhz=int(match['num_mhz']), mem_type=match['mem_type'].lower()) num_gb = int(match['num_gb'])
num_mhz = int(match['num_mhz'])
mem_type = match['mem_type'].lower()
if num_gb == 8 and num_mhz == 2667 and mem_type == 'rdimm':
num_mhz = 2933 # error in r940 configurator : incoherence between 'Mémoire 32 Go DDR4 à 2933MHz (4x8Go)' and 'Ajout d'une barette de 8Go 2667 Mhz RDIMM'
dimm = Dimm(num_gb=num_gb, num_mhz=num_mhz, mem_type=mem_type)
option = Option(dimm, price) option = Option(dimm, price)
ram_options.add_option(option) ram_options.add_option(option)
else: else:
@ -485,6 +502,7 @@ class DellConfiguratorParser():
ram_options.add_option(option) ram_options.add_option(option)
else: else:
assert False, 'unhandled label : %s' % label assert False, 'unhandled label : %s' % label
assert len(ram_options.options) > 0
return ram_options return ram_options
@classmethod @classmethod
@ -510,7 +528,10 @@ class DellConfiguratorParser():
item_label = DellConfiguratorParser._get_module_default_item('Processeurs (Passage)', html_root) 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]?).*', item_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)
if match is None:
match = re.match(r'^2 processeurs 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 assert match, 'unhandled label : %s' % item_label
base_config.num_cpu_per_server = 2
# 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))
@ -518,18 +539,59 @@ class DellConfiguratorParser():
# initialize the default ram dimms # initialize the default ram dimms
item_label = DellConfiguratorParser._get_module_default_item('Mémoires (Passage)', html_root) item_label = DellConfiguratorParser._get_module_default_item('Mémoires (Passage)', html_root)
# Mémoire 16 Go DDR4 à 2933MHz (1x16Go) # 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) 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_gb_per_dimm>[0-9]+)Go\)', item_label)
assert match, 'unhandled label : %s' % item_label assert match, 'unhandled label : %s' % item_label
assert int(match['num_dimms']) == 1 dimm = Dimm(num_gb=int(match['num_gb_per_dimm']), num_mhz=int(match['num_mhz']), mem_type='rdimm')
assert match['num_gb'] == match['num_gb2'] num_dimms = int(match['num_dimms'])
if num_dimms == 1:
assert match['num_gb'] == match['num_gb_per_dimm']
# print(match['cpu_class'], match['cpu_number']) # print(match['cpu_class'], match['cpu_number'])
cpu_slot_index = 0 cpu_slot_index = 0
mem_channel_index = 0 mem_channel_index = 0
dimm_slot = 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') base_config.cpu_slots_mem[cpu_slot_index].mem_channels[mem_channel_index].dimms[dimm_slot] = dimm
else:
# evenly split dimms on channels
assert (num_dimms % base_config.num_cpu_per_server) == 0
num_dimms_per_cpu = num_dimms // base_config.num_cpu_per_server
for cpu_slot_index in range(base_config.num_cpu_per_server):
cpu_slots_mem = base_config.cpu_slots_mem[cpu_slot_index]
assert len(cpu_slots_mem.mem_channels) >= num_dimms_per_cpu
for channel_index in range(num_dimms_per_cpu):
mem_channel = cpu_slots_mem.mem_channels[channel_index]
dimm_slot = 0
mem_channel.dimms[dimm_slot] = dimm
return base_config return base_config
@staticmethod
def _deduce_base_cpu_price(base_cpu, cpu_options, additional_cpu_options):
'''
The price of the base config processor is not always available directly in the section 'additional processors' : as an example, r940's default processors are 2 xeon gold 5215 but it's not possible to add 2 other 5215 (probably because 5215 can only talk to another cpu, not 3). In this case the price of this base cpu can be deduced from the price for other cpus (difference between cpu upgrade and additional cpu)
Args:
base_cpu (Cpu): the cpu of the base configuration
cpu_options (Module): the available cpu options
additional_cpu_options (Module): the available additional cpu options
returns:
float: the estimated price of base_cpu
'''
base_cpu_price = None
for cpu_option in additional_cpu_options.options.values():
cpu = cpu_option.item
# assert cpu.uid in cpu_options.options, "unexpected case : %s is available in additional cpus but not in cpu upgrade options" % cpu.uid
if cpu.uid in cpu_options.options:
cpu_upgrade_option = cpu_options.options[cpu.uid]
deduced_base_cpu_price = cpu_option.price - cpu_upgrade_option.price
print('price of %s estimated from %s : %f (%f-%f)' % (base_cpu.uid, cpu.uid, deduced_base_cpu_price, cpu_option.price, cpu_upgrade_option.price))
if base_cpu_price is None:
base_cpu_price = deduced_base_cpu_price
else:
assert abs(base_cpu_price-deduced_base_cpu_price) <= 0.01
return base_cpu_price
def parse(self, dell_configurator_html_file_path, configurator): def parse(self, dell_configurator_html_file_path, configurator):
@ -563,10 +625,17 @@ class DellConfiguratorParser():
configurator.base_config = self._parse_base_config(html_root, configurator) configurator.base_config = self._parse_base_config(html_root, configurator)
# configurator.add_module(self._parse_proc_change_options(html_root)) proc_change_module = self._parse_proc_change_options(html_root)
configurator.add_module(self._parse_proc_options(html_root)) configurator.add_module(self._parse_proc_options(html_root))
configurator.add_module(self._parse_ram_options(html_root)) configurator.add_module(self._parse_ram_options(html_root))
# compute the price of the base config cpu because for example in r940 configurator, the xeon gold 5215 appears in the basic config but not in additional cpus
base_cpu = configurator.base_config.cpu
if configurator.get_item_price(base_cpu.uid) is None:
base_cpu_price = DellConfiguratorParser._deduce_base_cpu_price(base_cpu, proc_change_module, configurator.modules['processor'])
configurator.modules['processor'].add_option(Option(base_cpu, base_cpu_price))
assert configurator.get_item_price(base_cpu.uid) is not None
# compute the price of the chassis # compute the price of the chassis
base_price = None base_price = None
price_preview_element = html_root.xpath(".//div[@class='price-preview']")[0] price_preview_element = html_root.xpath(".//div[@class='price-preview']")[0]
@ -591,7 +660,9 @@ class DellConfiguratorParser():
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.base_config.num_cpus * configurator.get_item_price(configurator.base_config.cpu.uid) - configurator.base_config.ram_price one_cpu_price = configurator.get_item_price(configurator.base_config.cpu.uid)
ram_price = configurator.base_config.ram_price
configurator.chassis.price = base_price - configurator.base_config.num_cpus * one_cpu_price - ram_price
class DellMatinfoConfigurator(Configurator): class DellMatinfoConfigurator(Configurator):
''' '''

View File

@ -137,6 +137,7 @@ def plot_system_efficiency():
configurators = [ configurators = [
dell.DellMatinfoCsvConfigurator('c6420-20200716-price.tsv'), dell.DellMatinfoCsvConfigurator('c6420-20200716-price.tsv'),
dell.DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html'), dell.DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html'),
dell.DellMatinfoConfigurator('rcrc1406676-4824727 - Cat 2 Conf 7 PowerEdge R940 - Dell.html'),
# dell.DellPowerEdgeR940(), # dell.DellPowerEdgeR940(),
] ]
for configurator in configurators: for configurator in configurators:

File diff suppressed because one or more lines are too long