made code style compliant with pep8 conventions
This commit is contained in:
parent
9de8a22cd0
commit
f1f8686373
122
concho/config.py
122
concho/config.py
|
@ -1,9 +1,10 @@
|
||||||
import re
|
import re
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import abstractmethod
|
||||||
import numpy
|
import numpy
|
||||||
from concho import dell
|
# from concho import dell
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
|
||||||
class Item():
|
class Item():
|
||||||
|
|
||||||
def __init__(self, uid):
|
def __init__(self, uid):
|
||||||
|
@ -22,6 +23,7 @@ class Chassis(Item):
|
||||||
self.max_num_servers = 4
|
self.max_num_servers = 4
|
||||||
self.num_dimm_slots_per_channel = 2
|
self.num_dimm_slots_per_channel = 2
|
||||||
|
|
||||||
|
|
||||||
class Dimm(Item):
|
class Dimm(Item):
|
||||||
|
|
||||||
def __init__(self, num_gb, num_mhz, mem_type):
|
def __init__(self, num_gb, num_mhz, mem_type):
|
||||||
|
@ -88,7 +90,7 @@ class Cpu(Item):
|
||||||
return 'milan'
|
return 'milan'
|
||||||
else:
|
else:
|
||||||
assert False, 'unhandled processor id : %s' % proc_id
|
assert False, 'unhandled processor id : %s' % proc_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def num_dp_flop_per_cycle(self):
|
def num_dp_flop_per_cycle(self):
|
||||||
proc_arch = self.architecture
|
proc_arch = self.architecture
|
||||||
|
@ -102,7 +104,7 @@ class Cpu(Item):
|
||||||
# https://en.wikichip.org/wiki/intel/xeon_gold/5222 : 'Note that this is the only processor in the Xeon Gold 52xx series with two 512b FMA units.'
|
# https://en.wikichip.org/wiki/intel/xeon_gold/5222 : 'Note that this is the only processor in the Xeon Gold 52xx series with two 512b FMA units.'
|
||||||
if re.match('intel-xeon-gold-5222', self.uid):
|
if re.match('intel-xeon-gold-5222', self.uid):
|
||||||
num_simd_per_core = 2
|
num_simd_per_core = 2
|
||||||
|
|
||||||
if re.match('intel-xeon-gold-61[0-9][0-9]', self.uid):
|
if re.match('intel-xeon-gold-61[0-9][0-9]', self.uid):
|
||||||
num_simd_per_core = 2
|
num_simd_per_core = 2
|
||||||
if re.match('intel-xeon-gold-62[0-9][0-9]', self.uid):
|
if re.match('intel-xeon-gold-62[0-9][0-9]', self.uid):
|
||||||
|
@ -134,80 +136,83 @@ class Cpu(Item):
|
||||||
'rome': 8
|
'rome': 8
|
||||||
}[self.architecture]
|
}[self.architecture]
|
||||||
|
|
||||||
|
|
||||||
def get_proc_architecture(proc_id):
|
def get_proc_architecture(proc_id):
|
||||||
return Cpu(proc_id).architecture
|
return Cpu(proc_id).architecture
|
||||||
|
|
||||||
def get_proc_arch_transistor_size(proc_id):
|
|
||||||
|
def get_proc_arch_transistor_size(proc_id):
|
||||||
return {
|
return {
|
||||||
'woodcrest':65,
|
'woodcrest': 65,
|
||||||
'harpertown':45,
|
'harpertown': 45,
|
||||||
'gainestown':45,
|
'gainestown': 45,
|
||||||
'gulftown':32,
|
'gulftown': 32,
|
||||||
'sandy bridge':32,
|
'sandy bridge': 32,
|
||||||
'ivy bridge':22,
|
'ivy bridge': 22,
|
||||||
'haswell':22,
|
'haswell': 22,
|
||||||
'broadwell':14,
|
'broadwell': 14,
|
||||||
'skylake':14,
|
'skylake': 14,
|
||||||
'coffeelake':14,
|
'coffeelake': 14,
|
||||||
'cascadelake':14
|
'cascadelake': 14
|
||||||
}[get_proc_architecture(proc_id)]
|
}[get_proc_architecture(proc_id)]
|
||||||
|
|
||||||
|
|
||||||
def simd_id_to_dp_flops_per_cycle(simd_id):
|
def simd_id_to_dp_flops_per_cycle(simd_id):
|
||||||
"""
|
"""
|
||||||
:param str simd_id: eg 'avx2'
|
:param str simd_id: eg 'avx2'
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# from https://stackoverflow.com/questions/15655835/flops-per-cycle-for-sandy-bridge-and-haswell-sse2-avx-avx2
|
# from https://stackoverflow.com/questions/15655835/flops-per-cycle-for-sandy-bridge-and-haswell-sse2-avx-avx2
|
||||||
# Intel Core 2 and Nehalem:
|
# Intel Core 2 and Nehalem:
|
||||||
#
|
#
|
||||||
# 4 DP FLOPs/cycle: 2-wide SSE2 addition + 2-wide SSE2 multiplication
|
# 4 DP FLOPs/cycle: 2-wide SSE2 addition + 2-wide SSE2 multiplication
|
||||||
# 8 SP FLOPs/cycle: 4-wide SSE addition + 4-wide SSE multiplication
|
# 8 SP FLOPs/cycle: 4-wide SSE addition + 4-wide SSE multiplication
|
||||||
#
|
#
|
||||||
# Intel Sandy Bridge/Ivy Bridge:
|
# Intel Sandy Bridge/Ivy Bridge:
|
||||||
#
|
#
|
||||||
# 8 DP FLOPs/cycle: 4-wide AVX addition + 4-wide AVX multiplication
|
# 8 DP FLOPs/cycle: 4-wide AVX addition + 4-wide AVX multiplication
|
||||||
# 16 SP FLOPs/cycle: 8-wide AVX addition + 8-wide AVX multiplication
|
# 16 SP FLOPs/cycle: 8-wide AVX addition + 8-wide AVX multiplication
|
||||||
#
|
#
|
||||||
# Intel Haswell/Broadwell/Skylake/Kaby Lake:
|
# Intel Haswell/Broadwell/Skylake/Kaby Lake:
|
||||||
#
|
#
|
||||||
# 16 DP FLOPs/cycle: two 4-wide FMA (fused multiply-add) instructions
|
# 16 DP FLOPs/cycle: two 4-wide FMA (fused multiply-add) instructions
|
||||||
# 32 SP FLOPs/cycle: two 8-wide FMA (fused multiply-add) instructions
|
# 32 SP FLOPs/cycle: two 8-wide FMA (fused multiply-add) instructions
|
||||||
|
|
||||||
# https://www.dell.com/support/kbdoc/fr-fr/000137696/amd-rome-is-it-for-real-architecture-and-initial-hpc-performance
|
# https://www.dell.com/support/kbdoc/fr-fr/000137696/amd-rome-is-it-for-real-architecture-and-initial-hpc-performance
|
||||||
# The Rome micro-architecture can retire 16 DP FLOP/cycle, double that of Naples which was 8 FLOPS/cycle
|
# The Rome micro-architecture can retire 16 DP FLOP/cycle, double that of Naples which was 8 FLOPS/cycle
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'sse4.1':4,
|
'sse4.1': 4,
|
||||||
'sse4.2':4,
|
'sse4.2': 4,
|
||||||
'avx':8,
|
'avx': 8,
|
||||||
'avx2':16,
|
'avx2': 16,
|
||||||
'avx-512':16,
|
'avx-512': 16,
|
||||||
}[simd_id]
|
}[simd_id]
|
||||||
|
|
||||||
|
|
||||||
def get_simd_id(proc_arch):
|
def get_simd_id(proc_arch):
|
||||||
"""
|
"""
|
||||||
:param str proc_arch: eg 'broadwell'
|
:param str proc_arch: eg 'broadwell'
|
||||||
:return str: eg 'sse4'
|
:return str: eg 'sse4'
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'woodcrest':'sse4.1',
|
'woodcrest': 'sse4.1',
|
||||||
'harpertown':'sse4.1',
|
'harpertown': 'sse4.1',
|
||||||
'gainestown':'sse4.2',
|
'gainestown': 'sse4.2',
|
||||||
'gulftown':'sse4.2',
|
'gulftown': 'sse4.2',
|
||||||
'sandy bridge':'avx',
|
'sandy bridge': 'avx',
|
||||||
'ivy bridge':'avx',
|
'ivy bridge': 'avx',
|
||||||
'haswell':'avx2',
|
'haswell': 'avx2',
|
||||||
'broadwell':'avx2',
|
'broadwell': 'avx2',
|
||||||
'skylake':'avx-512',
|
'skylake': 'avx-512',
|
||||||
'cascadelake':'avx-512',
|
'cascadelake': 'avx-512',
|
||||||
'coffeelake':'avx2',
|
'coffeelake': 'avx2',
|
||||||
# from https://www.microway.com/knowledge-center-articles/detailed-specifications-of-the-amd-epyc-rome-cpus/:
|
# from https://www.microway.com/knowledge-center-articles/detailed-specifications-of-the-amd-epyc-rome-cpus/:
|
||||||
# - Full support for 256-bit AVX2 instructions with two 256-bit FMA units per CPU core. The previous “Naples” architecture split 256-bit instructions into two separate 128-bit operations
|
# - Full support for 256-bit AVX2 instructions with two 256-bit FMA units per CPU core. The previous “Naples” architecture split 256-bit instructions into two separate 128-bit operations
|
||||||
# - Up to 16 double-precision FLOPS per cycle per core
|
# - Up to 16 double-precision FLOPS per cycle per core
|
||||||
# - Double-precision floating point multiplies complete in 3 cycles (down from 4)
|
# - Double-precision floating point multiplies complete in 3 cycles (down from 4)
|
||||||
'rome': 'avx2',
|
'rome': 'avx2',
|
||||||
}[proc_arch]
|
}[proc_arch]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MemChannel():
|
class MemChannel():
|
||||||
|
@ -215,11 +220,13 @@ class MemChannel():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.dimms = []
|
self.dimms = []
|
||||||
|
|
||||||
|
|
||||||
class CpuSlotMem():
|
class CpuSlotMem():
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.mem_channels = []
|
self.mem_channels = []
|
||||||
|
|
||||||
|
|
||||||
class Config():
|
class Config():
|
||||||
|
|
||||||
def __init__(self, configurator):
|
def __init__(self, configurator):
|
||||||
|
@ -229,14 +236,13 @@ class Config():
|
||||||
self.cpu = None
|
self.cpu = None
|
||||||
self.cpu_slots_mem = []
|
self.cpu_slots_mem = []
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def chassis(self):
|
def chassis(self):
|
||||||
return self.configurator.chassis.item
|
return self.configurator.chassis.item
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _find_dimm_combination(num_dimm_slots_per_channel, min_ram_per_channel, available_dimms):
|
def _find_dimm_combination(num_dimm_slots_per_channel, min_ram_per_channel, available_dimms):
|
||||||
available_dimms.append(Option(Dimm(0,0,'dummy'), 0.0)) # fake dimm to represent empty slot
|
available_dimms.append(Option(Dimm(0, 0, 'dummy'), 0.0)) # fake dimm to represent empty slot
|
||||||
slot_options = []
|
slot_options = []
|
||||||
|
|
||||||
# try all combinations of dimms
|
# try all combinations of dimms
|
||||||
|
@ -245,7 +251,7 @@ class Config():
|
||||||
for slot_index in range(num_dimm_slots_per_channel):
|
for slot_index in range(num_dimm_slots_per_channel):
|
||||||
slot_options.append(0)
|
slot_options.append(0)
|
||||||
no_more_configs = False
|
no_more_configs = False
|
||||||
while no_more_configs == False:
|
while no_more_configs is False:
|
||||||
config_capacity = 0
|
config_capacity = 0
|
||||||
config_price = 0
|
config_price = 0
|
||||||
for slot_index in range(num_dimm_slots_per_channel):
|
for slot_index in range(num_dimm_slots_per_channel):
|
||||||
|
@ -263,7 +269,7 @@ class Config():
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if slot_index == num_dimm_slots_per_channel - 1:
|
if slot_index == num_dimm_slots_per_channel - 1:
|
||||||
no_more_configs = True # all combinations of dimm in the slots have been covered
|
no_more_configs = True # all combinations of dimm in the slots have been covered
|
||||||
else:
|
else:
|
||||||
slot_options[slot_index] = 0
|
slot_options[slot_index] = 0
|
||||||
|
|
||||||
|
@ -280,7 +286,7 @@ class Config():
|
||||||
|
|
||||||
# ramUpgradePrice128Gb = {
|
# ramUpgradePrice128Gb = {
|
||||||
# 'c6220':3520.0,
|
# 'c6220':3520.0,
|
||||||
# 'r620':2010.0,
|
# 'r620':2010.0,
|
||||||
# 'r630':1778.0,
|
# 'r630':1778.0,
|
||||||
# 'r640':1780.0,
|
# 'r640':1780.0,
|
||||||
# 'r730':1778.0,
|
# 'r730':1778.0,
|
||||||
|
@ -337,13 +343,13 @@ class Config():
|
||||||
|
|
||||||
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) + self.ram_price
|
price += self.num_servers * self.num_cpu_per_server * self.configurator.get_item_price(self.cpu.uid) + self.ram_price
|
||||||
assert price > 0.0
|
assert price > 0.0
|
||||||
return price
|
return price
|
||||||
|
|
||||||
def get_power_consumption(self):
|
def get_power_consumption(self):
|
||||||
server_base_power_consumption = 100.0 # rough estimation in watts
|
server_base_power_consumption = 100.0 # rough estimation in watts
|
||||||
power_consumption = (self.cpu.tdp * self.num_cpu_per_server + server_base_power_consumption) * self.num_servers
|
power_consumption = (self.cpu.tdp * self.num_cpu_per_server + server_base_power_consumption) * self.num_servers
|
||||||
return power_consumption
|
return power_consumption
|
||||||
|
|
||||||
|
@ -351,7 +357,6 @@ class Config():
|
||||||
flops = self.cpu.num_dp_flop_per_cycle * self.cpu.clock * 1.e9 * self.cpu.num_cores * self.num_cpu_per_server * self.num_servers
|
flops = self.cpu.num_dp_flop_per_cycle * self.cpu.clock * 1.e9 * self.cpu.num_cores * self.num_cpu_per_server * self.num_servers
|
||||||
return flops
|
return flops
|
||||||
|
|
||||||
|
|
||||||
def _init_dimm_slots(self):
|
def _init_dimm_slots(self):
|
||||||
# create the dimm slots
|
# create the dimm slots
|
||||||
self.cpu_slots_mem = []
|
self.cpu_slots_mem = []
|
||||||
|
@ -361,7 +366,7 @@ class Config():
|
||||||
|
|
||||||
for cpu_index in range(self.num_cpu_per_server):
|
for cpu_index in range(self.num_cpu_per_server):
|
||||||
cpu_slot_mem = CpuSlotMem()
|
cpu_slot_mem = CpuSlotMem()
|
||||||
|
|
||||||
for channel_index in range(self.cpu.num_ram_channels):
|
for channel_index in range(self.cpu.num_ram_channels):
|
||||||
mem_channel = MemChannel()
|
mem_channel = MemChannel()
|
||||||
for dimm_slot_index in range(self.configurator.chassis.item.num_dimm_slots_per_channel):
|
for dimm_slot_index in range(self.configurator.chassis.item.num_dimm_slots_per_channel):
|
||||||
|
@ -388,12 +393,14 @@ class Config():
|
||||||
def num_cpus(self):
|
def num_cpus(self):
|
||||||
return self.num_cpu_per_server * self.num_servers
|
return self.num_cpu_per_server * self.num_servers
|
||||||
|
|
||||||
|
|
||||||
class Option():
|
class Option():
|
||||||
|
|
||||||
def __init__(self, item, price):
|
def __init__(self, item, price):
|
||||||
self.item = item
|
self.item = item
|
||||||
self.price = price
|
self.price = price
|
||||||
|
|
||||||
|
|
||||||
class Module():
|
class Module():
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
|
@ -443,6 +450,7 @@ class Configurator():
|
||||||
if item_uid in module.options:
|
if item_uid in module.options:
|
||||||
return module.options[item_uid].price
|
return module.options[item_uid].price
|
||||||
|
|
||||||
|
|
||||||
class TableBasedConfigurator(Configurator):
|
class TableBasedConfigurator(Configurator):
|
||||||
|
|
||||||
def __init__(self, host_type_id, num_cpu_per_server, num_servers=1):
|
def __init__(self, host_type_id, num_cpu_per_server, num_servers=1):
|
||||||
|
@ -453,7 +461,7 @@ class TableBasedConfigurator(Configurator):
|
||||||
self.base_config = Config(self)
|
self.base_config = Config(self)
|
||||||
self.base_config.num_servers = self.num_servers
|
self.base_config.num_servers = self.num_servers
|
||||||
self.base_config.num_cpu_per_server = self.num_cpu_per_server
|
self.base_config.num_cpu_per_server = self.num_cpu_per_server
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_empty_price(self):
|
def get_empty_price(self):
|
||||||
pass
|
pass
|
||||||
|
@ -469,7 +477,7 @@ class TableBasedConfigurator(Configurator):
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_disk_upgrade_price(self, disk_capacity):
|
def get_disk_upgrade_price(self, disk_capacity):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_cpu_options(self):
|
def get_cpu_options(self):
|
||||||
supported_cpus = []
|
supported_cpus = []
|
||||||
for host_type_id, proc_id, proc_option_price in zip(self.dell_price_table['host_type_id'], self.dell_price_table['proc_id'], self.dell_price_table['proc_option_price']):
|
for host_type_id, proc_id, proc_option_price in zip(self.dell_price_table['host_type_id'], self.dell_price_table['proc_id'], self.dell_price_table['proc_option_price']):
|
||||||
|
@ -497,8 +505,4 @@ class TableBasedConfigurator(Configurator):
|
||||||
# return dell.DellPrecision3630(host_type_id)
|
# return dell.DellPrecision3630(host_type_id)
|
||||||
# assert False
|
# assert False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# dom = parse(dell_configurator_html_file_path)
|
# dom = parse(dell_configurator_html_file_path)
|
||||||
|
|
|
@ -6,8 +6,8 @@ from concho.config import Config
|
||||||
from concho.config import Chassis
|
from concho.config import Chassis
|
||||||
from concho.config import Cpu, Dimm
|
from concho.config import Cpu, Dimm
|
||||||
|
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import abstractmethod
|
||||||
from xml.dom.minidom import parse
|
# from xml.dom.minidom import parse
|
||||||
from lxml.html import parse
|
from lxml.html import parse
|
||||||
import re
|
import re
|
||||||
import copy
|
import copy
|
||||||
|
@ -79,12 +79,12 @@ class DellPowerEdgeR630(TableBasedConfigurator):
|
||||||
assert 1.9e12 < asked_disk_capacity < 2.1e12, 'only 2To upgrades are handled for %s' % self.host_type_id
|
assert 1.9e12 < asked_disk_capacity < 2.1e12, 'only 2To upgrades are handled for %s' % self.host_type_id
|
||||||
return 0.0 * self.num_servers
|
return 0.0 * self.num_servers
|
||||||
|
|
||||||
|
|
||||||
class DellPowerEdgeR730(TableBasedConfigurator):
|
class DellPowerEdgeR730(TableBasedConfigurator):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__('r730', num_cpu_per_server=2, num_servers=1)
|
super().__init__('r730', num_cpu_per_server=2, num_servers=1)
|
||||||
|
|
||||||
|
|
||||||
def get_empty_price(self):
|
def get_empty_price(self):
|
||||||
# for r730 on 06/10/2016
|
# for r730 on 06/10/2016
|
||||||
# (x: price without procs, p1 : price of e5-2603v4, p2: price of e5-2609v4)
|
# (x: price without procs, p1 : price of e5-2603v4, p2: price of e5-2609v4)
|
||||||
|
@ -106,6 +106,7 @@ class DellPowerEdgeR730(TableBasedConfigurator):
|
||||||
assert 1.9e12 < asked_disk_capacity < 2.1e12, 'only 2To upgrades are handled for %s' % self.host_type_id
|
assert 1.9e12 < asked_disk_capacity < 2.1e12, 'only 2To upgrades are handled for %s' % self.host_type_id
|
||||||
return 0.0 * self.num_servers
|
return 0.0 * self.num_servers
|
||||||
|
|
||||||
|
|
||||||
class DellPowerEdgeC4130(TableBasedConfigurator):
|
class DellPowerEdgeC4130(TableBasedConfigurator):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -302,6 +303,7 @@ class DellPrecision3630(TableBasedConfigurator):
|
||||||
assert 1.9e12 < asked_disk_capacity < 2.1e12, 'only 2To upgrades are handled for %s' % self.host_type_id
|
assert 1.9e12 < asked_disk_capacity < 2.1e12, 'only 2To upgrades are handled for %s' % self.host_type_id
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
class DellPowerEdgeC6420(TableBasedConfigurator):
|
class DellPowerEdgeC6420(TableBasedConfigurator):
|
||||||
|
|
||||||
def __init__(self, host_type_id):
|
def __init__(self, host_type_id):
|
||||||
|
@ -309,15 +311,15 @@ class DellPowerEdgeC6420(TableBasedConfigurator):
|
||||||
|
|
||||||
def get_empty_price(self):
|
def get_empty_price(self):
|
||||||
# for 4xc6420 on 19/06/2020 (from excel quotation)
|
# for 4xc6420 on 19/06/2020 (from excel quotation)
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# (x: price without procs, p2630: price of xeon gold 6230)
|
# (x: price without procs, p2630: price of xeon gold 6230)
|
||||||
# x + 4 x (2 x p4210r + p48g) = 5368 € HT
|
# x + 4 x (2 x p4210r + p48g) = 5368 € HT
|
||||||
# x + 4 x (2 x p6230r + p192g) = 27213 € HT
|
# x + 4 x (2 x p6230r + p192g) = 27213 € HT
|
||||||
#
|
#
|
||||||
# p48g = 3 * 160.0 # the price of a 16G ram is 160.0 €
|
# p48g = 3 * 160.0 # the price of a 16G ram is 160.0 €
|
||||||
# p4210r = p4210r=978./2 # from r640 prices
|
# p4210r = p4210r=978./2 # from r640 prices
|
||||||
#
|
#
|
||||||
|
|
||||||
# >>> p4210r=978./2
|
# >>> p4210r=978./2
|
||||||
# >>> p6230r_upgrade = 13408.0
|
# >>> p6230r_upgrade = 13408.0
|
||||||
|
@ -329,7 +331,7 @@ class DellPowerEdgeC6420(TableBasedConfigurator):
|
||||||
# 2165.0
|
# 2165.0
|
||||||
|
|
||||||
# => p4210r seems to be the same on r640 and c6420
|
# => p4210r seems to be the same on r640 and c6420
|
||||||
#
|
#
|
||||||
# pc6000 = 5368 - (p4210r * num_cpu_per_server + p48g) * num_servers_per_c6000
|
# pc6000 = 5368 - (p4210r * num_cpu_per_server + p48g) * num_servers_per_c6000
|
||||||
# >>> p16g = 160.0
|
# >>> p16g = 160.0
|
||||||
# >>> p48g = p16g * 3
|
# >>> p48g = p16g * 3
|
||||||
|
@ -349,8 +351,8 @@ class DellPowerEdgeC6420(TableBasedConfigurator):
|
||||||
# 27213.0
|
# 27213.0
|
||||||
num_servers_per_c6000 = 4
|
num_servers_per_c6000 = 4
|
||||||
num_cpu_per_server = 2
|
num_cpu_per_server = 2
|
||||||
ram_price_per_gigabyte = 160.0 / 16 # 16G ram price : 160.0 €
|
ram_price_per_gigabyte = 160.0 / 16 # 16G ram price : 160.0 €
|
||||||
xeon_silver_4210r_price = 978.0 / 2 # from r640 prices
|
xeon_silver_4210r_price = 978.0 / 2 # from r640 prices
|
||||||
basic_config_price = 5368.0
|
basic_config_price = 5368.0
|
||||||
poweredge_c6000_price = basic_config_price - (xeon_silver_4210r_price * num_cpu_per_server + ram_price_per_gigabyte * 48) * num_servers_per_c6000
|
poweredge_c6000_price = basic_config_price - (xeon_silver_4210r_price * num_cpu_per_server + ram_price_per_gigabyte * 48) * num_servers_per_c6000
|
||||||
return poweredge_c6000_price
|
return poweredge_c6000_price
|
||||||
|
@ -379,8 +381,6 @@ class DellPowerEdgeC6420(TableBasedConfigurator):
|
||||||
return 361.0
|
return 361.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DellConfiguratorParser():
|
class DellConfiguratorParser():
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -414,7 +414,7 @@ class DellConfiguratorParser():
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def price_str_as_float(self, price_as_str):
|
def price_str_as_float(self, price_as_str):
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_module_label(self, module_id):
|
def get_module_label(self, module_id):
|
||||||
assert False
|
assert False
|
||||||
|
@ -429,7 +429,7 @@ class DellConfiguratorParser():
|
||||||
|
|
||||||
def _parse_proc_change_options(self, html_root):
|
def _parse_proc_change_options(self, html_root):
|
||||||
proc_options = Module('processor-change')
|
proc_options = Module('processor-change')
|
||||||
#module_root_element = self._get_module(html_root, 'Processeurs (Passage)')
|
# module_root_element = self._get_module(html_root, 'Processeurs (Passage)')
|
||||||
module_root_element = self._get_module(html_root, self.get_module_label('cpu_change'))
|
module_root_element = self._get_module(html_root, self.get_module_label('cpu_change'))
|
||||||
for option_root_element in module_root_element.xpath(self.get_xpath_filter('module_to_options')):
|
for option_root_element in module_root_element.xpath(self.get_xpath_filter('module_to_options')):
|
||||||
label_elements = option_root_element.xpath(self.get_xpath_filter('option_to_label'))
|
label_elements = option_root_element.xpath(self.get_xpath_filter('option_to_label'))
|
||||||
|
@ -469,7 +469,7 @@ class DellConfiguratorParser():
|
||||||
|
|
||||||
def _parse_proc_options(self, html_root):
|
def _parse_proc_options(self, html_root):
|
||||||
proc_options = Module('processor')
|
proc_options = Module('processor')
|
||||||
#module_root_element = self._get_module(html_root, 'Processeurs (Passage)')
|
# module_root_element = self._get_module(html_root, 'Processeurs (Passage)')
|
||||||
module_root_element = self._get_module(html_root, self.get_module_label('additional_cpus'))
|
module_root_element = self._get_module(html_root, self.get_module_label('additional_cpus'))
|
||||||
if module_root_element is not None:
|
if module_root_element is not None:
|
||||||
for option_root_element in module_root_element.xpath(self.get_xpath_filter('module_to_options')):
|
for option_root_element in module_root_element.xpath(self.get_xpath_filter('module_to_options')):
|
||||||
|
@ -498,7 +498,7 @@ class DellConfiguratorParser():
|
||||||
|
|
||||||
def _parse_ram_options(self, html_root):
|
def _parse_ram_options(self, html_root):
|
||||||
ram_options = Module('ram')
|
ram_options = Module('ram')
|
||||||
#module_root_element = self._get_module(html_root, 'Processeurs (Passage)')
|
# module_root_element = self._get_module(html_root, 'Processeurs (Passage)')
|
||||||
module_root_element = self._get_module(html_root, self.get_module_label('ram_additions'))
|
module_root_element = self._get_module(html_root, self.get_module_label('ram_additions'))
|
||||||
for option_root_element in module_root_element.xpath(self.get_xpath_filter('module_to_options')):
|
for option_root_element in module_root_element.xpath(self.get_xpath_filter('module_to_options')):
|
||||||
label_elements = option_root_element.xpath(self.get_xpath_filter('option_to_label'))
|
label_elements = option_root_element.xpath(self.get_xpath_filter('option_to_label'))
|
||||||
|
@ -554,10 +554,10 @@ class DellConfiguratorParser():
|
||||||
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())
|
||||||
if match is None:
|
if match is None:
|
||||||
print('item_label=%s' % item_label)
|
print('item_label=%s' % item_label)
|
||||||
|
|
||||||
#match = re.match(r'^2 Processeurs AMD EPYC (?P<cpu_number>[0-9][0-9][0-9][0-9]).*', item_label)
|
# match = re.match(r'^2 Processeurs AMD EPYC (?P<cpu_number>[0-9][0-9][0-9][0-9]).*', item_label)
|
||||||
match = re.match(r'^2 Processeurs AMD EPYC (?P<cpu_number>[0-9][0-9][0-9][0-9]).*', clean_string(item_label))
|
match = re.match(r'^2 Processeurs AMD EPYC (?P<cpu_number>[0-9][0-9][0-9][0-9]).*', clean_string(item_label))
|
||||||
|
|
||||||
if match:
|
if match:
|
||||||
base_config.num_cpu_per_server = 2
|
base_config.num_cpu_per_server = 2
|
||||||
cpu_id = "amd-epyc-%s" % (match['cpu_number'].lower())
|
cpu_id = "amd-epyc-%s" % (match['cpu_number'].lower())
|
||||||
|
@ -618,7 +618,7 @@ class DellConfiguratorParser():
|
||||||
if base_cpu_price is None:
|
if base_cpu_price is None:
|
||||||
base_cpu_price = deduced_base_cpu_price
|
base_cpu_price = deduced_base_cpu_price
|
||||||
else:
|
else:
|
||||||
assert abs(base_cpu_price-deduced_base_cpu_price) <= 0.01
|
assert abs(base_cpu_price - deduced_base_cpu_price) <= 0.01
|
||||||
|
|
||||||
return base_cpu_price
|
return base_cpu_price
|
||||||
|
|
||||||
|
@ -635,14 +635,13 @@ class DellConfiguratorParser():
|
||||||
# div = body.find('div')
|
# div = body.find('div')
|
||||||
# for e in div:
|
# for e in div:
|
||||||
# print(e.tag, e.attrib)
|
# print(e.tag, e.attrib)
|
||||||
|
|
||||||
# modules_element = body.xpath("//div[@class='col-md-10']")
|
|
||||||
|
|
||||||
|
# modules_element = body.xpath("//div[@class='col-md-10']")
|
||||||
|
|
||||||
module_root_element = self._get_module(html_root, 'Base')
|
module_root_element = self._get_module(html_root, 'Base')
|
||||||
assert module_root_element is not None
|
assert module_root_element is not None
|
||||||
#option_root_elements = module_root_element.xpath(".//div[@class='row']")
|
# option_root_elements = module_root_element.xpath(".//div[@class='row']")
|
||||||
#assert len(option_root_elements) > 0
|
# assert len(option_root_elements) > 0
|
||||||
|
|
||||||
# option_root_element = option_root_elements[0]
|
# option_root_element = option_root_elements[0]
|
||||||
label_elements = module_root_element.xpath(self.get_xpath_filter('base_module_to_label'))
|
label_elements = module_root_element.xpath(self.get_xpath_filter('base_module_to_label'))
|
||||||
|
@ -671,7 +670,7 @@ class DellConfiguratorParser():
|
||||||
# so we fallback to an hardcoded estimated price from wikipedia
|
# so we fallback to an hardcoded estimated price from wikipedia
|
||||||
base_cpu_price = {
|
base_cpu_price = {
|
||||||
'amd-epyc-7262': 550.0,
|
'amd-epyc-7262': 550.0,
|
||||||
}[base_cpu.uid]
|
}[base_cpu.uid]
|
||||||
configurator.modules['processor'].add_option(Option(base_cpu, base_cpu_price))
|
configurator.modules['processor'].add_option(Option(base_cpu, base_cpu_price))
|
||||||
assert configurator.get_item_price(base_cpu.uid) is not None, 'failed to find the price of base cpu %s' % base_cpu.uid
|
assert configurator.get_item_price(base_cpu.uid) is not None, 'failed to find the price of base cpu %s' % base_cpu.uid
|
||||||
|
|
||||||
|
@ -693,7 +692,7 @@ class DellConfiguratorParser():
|
||||||
configurator.modules['processor'].add_option(Option(Cpu(proc_change_option.item.uid), cpu_price))
|
configurator.modules['processor'].add_option(Option(Cpu(proc_change_option.item.uid), cpu_price))
|
||||||
# delete the 'processor-change' module as its items ids are the same as the ones in the 'processor' modules but their prices are 'wrong' (upgrade prices rather than item price).
|
# delete the 'processor-change' module as its items ids are the same as the ones in the 'processor' modules but their prices are 'wrong' (upgrade prices rather than item price).
|
||||||
# in a configuration, no item should be found more than once
|
# in a configuration, no item should be found more than once
|
||||||
del configurator.modules['processor-change']
|
del configurator.modules['processor-change']
|
||||||
|
|
||||||
one_cpu_price = configurator.get_item_price(configurator.base_config.cpu.uid)
|
one_cpu_price = configurator.get_item_price(configurator.base_config.cpu.uid)
|
||||||
ram_price = configurator.base_config.ram_price
|
ram_price = configurator.base_config.ram_price
|
||||||
|
@ -711,7 +710,7 @@ class DellConfiguratorParser2020(DellConfiguratorParser):
|
||||||
'additional_cpus': 'Processeurs additionnels',
|
'additional_cpus': 'Processeurs additionnels',
|
||||||
'ram_change': 'Mémoires (Passage)',
|
'ram_change': 'Mémoires (Passage)',
|
||||||
'ram_additions': 'Mémoire: Ajout de barettes additionnelles',
|
'ram_additions': 'Mémoire: Ajout de barettes additionnelles',
|
||||||
}[module_id]
|
}[module_id]
|
||||||
|
|
||||||
def get_xpath_filter(self, filter_id):
|
def get_xpath_filter(self, filter_id):
|
||||||
return {
|
return {
|
||||||
|
@ -723,11 +722,11 @@ class DellConfiguratorParser2020(DellConfiguratorParser):
|
||||||
'option_to_label': ".//div[@class='option-not-selected ']",
|
'option_to_label': ".//div[@class='option-not-selected ']",
|
||||||
'option_to_price': ".//div[@class='col-md-3 text-right option-price ']",
|
'option_to_price': ".//div[@class='col-md-3 text-right option-price ']",
|
||||||
'base_module_to_label': ".//div[@class='option-selected ']",
|
'base_module_to_label': ".//div[@class='option-selected ']",
|
||||||
}[filter_id]
|
}[filter_id]
|
||||||
|
|
||||||
def price_str_as_float(self, price_as_str):
|
def price_str_as_float(self, price_as_str):
|
||||||
# eg '+ 2,255.00 €'
|
# eg '+ 2,255.00 €'
|
||||||
match = re.match(r'^\s*(?P<sign>[-+]?)\s*(?P<numbers>[0-9.]*)\s*€\s*$', price_as_str.replace(',',''))
|
match = re.match(r'^\s*(?P<sign>[-+]?)\s*(?P<numbers>[0-9.]*)\s*€\s*$', price_as_str.replace(',', ''))
|
||||||
assert match, 'unexpected price string (%s)' % price_as_str
|
assert match, 'unexpected price string (%s)' % price_as_str
|
||||||
# print(match['sign'], match['numbers'])
|
# print(match['sign'], match['numbers'])
|
||||||
price_as_float = float("%s%s" % (match['sign'], match['numbers']))
|
price_as_float = float("%s%s" % (match['sign'], match['numbers']))
|
||||||
|
@ -771,6 +770,7 @@ class DellConfiguratorParser2020(DellConfiguratorParser):
|
||||||
assert base_price is not None
|
assert base_price is not None
|
||||||
return base_price
|
return base_price
|
||||||
|
|
||||||
|
|
||||||
class DellConfiguratorParser2021(DellConfiguratorParser):
|
class DellConfiguratorParser2021(DellConfiguratorParser):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -782,7 +782,7 @@ class DellConfiguratorParser2021(DellConfiguratorParser):
|
||||||
'additional_cpus': 'Processeurs additionnels',
|
'additional_cpus': 'Processeurs additionnels',
|
||||||
'ram_change': 'Mémoires (Passage)',
|
'ram_change': 'Mémoires (Passage)',
|
||||||
'ram_additions': 'Mémoire: Ajout de barettes additionnelles',
|
'ram_additions': 'Mémoire: Ajout de barettes additionnelles',
|
||||||
}[module_id]
|
}[module_id]
|
||||||
|
|
||||||
def get_xpath_filter(self, filter_id):
|
def get_xpath_filter(self, filter_id):
|
||||||
return {
|
return {
|
||||||
|
@ -794,12 +794,12 @@ class DellConfiguratorParser2021(DellConfiguratorParser):
|
||||||
'option_to_label': ".//div[@class='option-info']",
|
'option_to_label': ".//div[@class='option-info']",
|
||||||
'option_to_price': ".//div[@class='option-price']",
|
'option_to_price': ".//div[@class='option-price']",
|
||||||
'base_module_to_label': ".//div[@class='product-options-configuration-block option-selected']",
|
'base_module_to_label': ".//div[@class='product-options-configuration-block option-selected']",
|
||||||
}[filter_id]
|
}[filter_id]
|
||||||
|
|
||||||
def price_str_as_float(self, price_as_str):
|
def price_str_as_float(self, price_as_str):
|
||||||
# eg '+ 2 255,00 €' # contains a Narrow No-Break Space (NNBSP) https://www.compart.com/en/unicode/U+202F
|
# eg '+ 2 255,00 €' # contains a Narrow No-Break Space (NNBSP) https://www.compart.com/en/unicode/U+202F
|
||||||
nnbsp = ' '
|
nnbsp = ' '
|
||||||
match = re.match(r'^\s*(?P<sign>[-+]?)\s*(?P<numbers>[0-9.]*)\s*€\s*$', price_as_str.replace(',','.').replace(nnbsp, ''))
|
match = re.match(r'^\s*(?P<sign>[-+]?)\s*(?P<numbers>[0-9.]*)\s*€\s*$', price_as_str.replace(',', '.').replace(nnbsp, ''))
|
||||||
assert match, 'unexpected price string (%s)' % price_as_str
|
assert match, 'unexpected price string (%s)' % price_as_str
|
||||||
# print(match['sign'], match['numbers'])
|
# print(match['sign'], match['numbers'])
|
||||||
price_as_float = float("%s%s" % (match['sign'], match['numbers']))
|
price_as_float = float("%s%s" % (match['sign'], match['numbers']))
|
||||||
|
@ -854,7 +854,7 @@ class DellConfiguratorParser2021(DellConfiguratorParser):
|
||||||
if label == 'Prix de base':
|
if label == 'Prix de base':
|
||||||
price_value_element = price_element.xpath(".//span[@class='info-value strong']")[0]
|
price_value_element = price_element.xpath(".//span[@class='info-value strong']")[0]
|
||||||
assert price_value_element is not None
|
assert price_value_element is not None
|
||||||
base_price = self.price_str_as_float(price_value_element.text_content().replace(' HT',''))
|
base_price = self.price_str_as_float(price_value_element.text_content().replace(' HT', ''))
|
||||||
assert base_price is not None
|
assert base_price is not None
|
||||||
return base_price
|
return base_price
|
||||||
|
|
||||||
|
@ -870,7 +870,6 @@ class DellMatinfoConfigurator(Configurator):
|
||||||
self.chassis = None
|
self.chassis = None
|
||||||
html_parser.parse(dell_configurator_html_file_path, self)
|
html_parser.parse(dell_configurator_html_file_path, self)
|
||||||
|
|
||||||
|
|
||||||
def create_config(self):
|
def create_config(self):
|
||||||
# config = copy.deepcopy(self.base_config)
|
# config = copy.deepcopy(self.base_config)
|
||||||
config = Config(self)
|
config = Config(self)
|
||||||
|
@ -889,13 +888,11 @@ class DellMatinfoCsvConfigurator(Configurator):
|
||||||
eg the excel sheet sent to guillaume.raffy@univ-rennes1.fr on 16/07/2020
|
eg the excel sheet sent to guillaume.raffy@univ-rennes1.fr on 16/07/2020
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, dell_csv_file_path):
|
def __init__(self, dell_csv_file_path):
|
||||||
super().__init__(self)
|
super().__init__(self)
|
||||||
self.base_config = None
|
self.base_config = None
|
||||||
self.chassis = None
|
self.chassis = None
|
||||||
self.parse_csv_configurator(dell_csv_file_path)
|
self.parse_csv_configurator(dell_csv_file_path)
|
||||||
|
|
||||||
|
|
||||||
def parse_csv_configurator(self, dell_csv_file_path):
|
def parse_csv_configurator(self, dell_csv_file_path):
|
||||||
COLUMN_LABEL = 0
|
COLUMN_LABEL = 0
|
||||||
|
@ -903,7 +900,6 @@ class DellMatinfoCsvConfigurator(Configurator):
|
||||||
COLUMN_PRICE = 4
|
COLUMN_PRICE = 4
|
||||||
|
|
||||||
with open(dell_csv_file_path, 'rt') as csv_file:
|
with open(dell_csv_file_path, 'rt') as csv_file:
|
||||||
|
|
||||||
self.base_config = Config(self)
|
self.base_config = Config(self)
|
||||||
|
|
||||||
proc_options = Module('processor')
|
proc_options = Module('processor')
|
||||||
|
@ -939,7 +935,7 @@ class DellMatinfoCsvConfigurator(Configurator):
|
||||||
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/self.chassis.item.max_num_servers/self.chassis.item.num_cpu_slots_per_server)
|
option = Option(Cpu(cpu_id), price / self.chassis.item.max_num_servers / self.chassis.item.num_cpu_slots_per_server)
|
||||||
proc_options.add_option(option)
|
proc_options.add_option(option)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -948,7 +944,7 @@ class DellMatinfoCsvConfigurator(Configurator):
|
||||||
if match:
|
if match:
|
||||||
price_for_four = self.price_str_as_float(line_cells[COLUMN_PRICE])
|
price_for_four = self.price_str_as_float(line_cells[COLUMN_PRICE])
|
||||||
dimm = Dimm(mem_type='rdimm', num_gb=int(match['num_gb']), num_mhz=int(match['num_mhz']))
|
dimm = Dimm(mem_type='rdimm', num_gb=int(match['num_gb']), num_mhz=int(match['num_mhz']))
|
||||||
option = Option(dimm, price_for_four/4.0)
|
option = Option(dimm, price_for_four / 4.0)
|
||||||
ram_options.add_option(option)
|
ram_options.add_option(option)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,35 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import abstractmethod
|
||||||
import numpy
|
import numpy
|
||||||
import pylab
|
# import pylab
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import matplotlib.colors
|
import matplotlib.colors
|
||||||
import itertools
|
import itertools
|
||||||
import re
|
import re
|
||||||
import hashlib
|
import hashlib
|
||||||
from string import ascii_lowercase
|
# from string import ascii_lowercase
|
||||||
from concho.config import Configurator
|
# from concho.config import Configurator
|
||||||
from concho.config import Config
|
# from concho.config import Config
|
||||||
from concho.config import Cpu
|
from concho.config import Cpu
|
||||||
from concho import dell
|
# from concho import dell
|
||||||
|
|
||||||
markerTypes=[',', '+', '.', '^', 'v', '<', '>', 'o', '*', '1', '2', '3', '4', '8', 's', 'p', 'h', 'H', 'x', 'X', 'D', 'd', '|', '_']
|
markerTypes = [',', '+', '.', '^', 'v', '<', '>', 'o', '*', '1', '2', '3', '4', '8', 's', 'p', 'h', 'H', 'x', 'X', 'D', 'd', '|', '_']
|
||||||
#for c in ascii_lowercase:
|
# for c in ascii_lowercase:
|
||||||
# markerTypes.append('$%s$' % c)
|
# markerTypes.append('$%s$' % c)
|
||||||
#markerColors=('r', 'g', 'b')
|
# markerColors=('r', 'g', 'b')
|
||||||
markerColors=('r')
|
markerColors = ('r')
|
||||||
|
|
||||||
|
|
||||||
def get_marker(proc_id):
|
def get_marker(proc_id):
|
||||||
hash_object = hashlib.md5(proc_id.encode('utf-8'))
|
hash_object = hashlib.md5(proc_id.encode('utf-8'))
|
||||||
hash = int(hash_object.hexdigest(), 16)
|
hash = int(hash_object.hexdigest(), 16)
|
||||||
return markerTypes[ hash % len(markerTypes) ]
|
return markerTypes[hash % len(markerTypes)]
|
||||||
|
|
||||||
|
|
||||||
def plotCpuPassmark():
|
def plotCpuPassmark():
|
||||||
cpuTable = numpy.genfromtxt('cpu_table.tsv', dtype=("|U10", float, int, float, float), names=True, delimiter='\t')
|
cpuTable = numpy.genfromtxt('cpu_table.tsv', dtype=("|U10", float, int, float, float), names=True, delimiter='\t')
|
||||||
plt.subplot(1,1,0)
|
plt.subplot(1, 1, 0)
|
||||||
plt.subplots_adjust(bottom = 0.1)
|
plt.subplots_adjust(bottom=0.1)
|
||||||
markersCycler = itertools.cycle(itertools.product(markerTypes, markerColors))
|
markersCycler = itertools.cycle(itertools.product(markerTypes, markerColors))
|
||||||
labels = cpuTable['id']
|
labels = cpuTable['id']
|
||||||
x = cpuTable['clock'] * cpuTable['num_cores']
|
x = cpuTable['clock'] * cpuTable['num_cores']
|
||||||
|
@ -35,28 +37,28 @@ def plotCpuPassmark():
|
||||||
markerSize = 50
|
markerSize = 50
|
||||||
color = 'b'
|
color = 'b'
|
||||||
for label, x1, y1 in zip(labels, x, y):
|
for label, x1, y1 in zip(labels, x, y):
|
||||||
if y1 <= 0.0:
|
if y1 <= 0.0:
|
||||||
continue # no passmark available fo this data
|
continue # no passmark available fo this data
|
||||||
generation=label[-1]
|
generation = label[-1]
|
||||||
if generation == '2':
|
if generation == '2':
|
||||||
color = 'b'
|
color = 'b'
|
||||||
else:
|
else:
|
||||||
color = 'r'
|
color = 'r'
|
||||||
marker = markersCycler.next()
|
marker = markersCycler.next()
|
||||||
plt.scatter( x1, y1, color = color, s = markerSize, marker = marker[0], label = label)
|
plt.scatter(x1, y1, color=color, s=markerSize, marker=marker[0], label=label)
|
||||||
plt.xlabel(u'theoretical cpu speed [core.GHz]')
|
plt.xlabel(u'theoretical cpu speed [core.GHz]')
|
||||||
plt.ylabel(u'passmark [?]')
|
plt.ylabel(u'passmark [?]')
|
||||||
plt.title(u'comparison between cpu theoretical and effective speed')
|
plt.title(u'comparison between cpu theoretical and effective speed')
|
||||||
plt.xlim( xmin = 0.0 )
|
plt.xlim(xmin=0.0)
|
||||||
plt.ylim( ymin = 0.0 )
|
plt.ylim(ymin=0.0)
|
||||||
plt.legend(bbox_to_anchor=(0.2, 1.0))
|
plt.legend(bbox_to_anchor=(0.2, 1.0))
|
||||||
#plt.legend()
|
# plt.legend()
|
||||||
plt.draw()
|
plt.draw()
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
def create_unique_marker(config_index):
|
def create_unique_marker(config_index):
|
||||||
marker_string=''
|
marker_string = ''
|
||||||
alphabet_size = 26
|
alphabet_size = 26
|
||||||
alphabel_base = 0x41
|
alphabel_base = 0x41
|
||||||
while True:
|
while True:
|
||||||
|
@ -68,6 +70,7 @@ def create_unique_marker(config_index):
|
||||||
config_index = config_index // alphabet_size
|
config_index = config_index // alphabet_size
|
||||||
return marker_string
|
return marker_string
|
||||||
|
|
||||||
|
|
||||||
class ConfigAxisDef():
|
class ConfigAxisDef():
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -81,6 +84,7 @@ class ConfigAxisDef():
|
||||||
def get_value_for_config(self, config):
|
def get_value_for_config(self, config):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ConfigPrice(ConfigAxisDef):
|
class ConfigPrice(ConfigAxisDef):
|
||||||
|
|
||||||
def get_axis_label(self):
|
def get_axis_label(self):
|
||||||
|
@ -89,6 +93,7 @@ class ConfigPrice(ConfigAxisDef):
|
||||||
def get_value_for_config(self, config):
|
def get_value_for_config(self, config):
|
||||||
return config.get_price()
|
return config.get_price()
|
||||||
|
|
||||||
|
|
||||||
class ConfigFlops(ConfigAxisDef):
|
class ConfigFlops(ConfigAxisDef):
|
||||||
|
|
||||||
def get_axis_label(self):
|
def get_axis_label(self):
|
||||||
|
@ -97,6 +102,7 @@ class ConfigFlops(ConfigAxisDef):
|
||||||
def get_value_for_config(self, config):
|
def get_value_for_config(self, config):
|
||||||
return config.get_flops()
|
return config.get_flops()
|
||||||
|
|
||||||
|
|
||||||
class ConfigFlopsPerEuro(ConfigAxisDef):
|
class ConfigFlopsPerEuro(ConfigAxisDef):
|
||||||
|
|
||||||
def get_axis_label(self):
|
def get_axis_label(self):
|
||||||
|
@ -104,48 +110,49 @@ class ConfigFlopsPerEuro(ConfigAxisDef):
|
||||||
|
|
||||||
def get_value_for_config(self, config):
|
def get_value_for_config(self, config):
|
||||||
kWHPrice = 0.07 * 1.5
|
kWHPrice = 0.07 * 1.5
|
||||||
containerLifetime = 7.0 # in years
|
containerLifetime = 7.0 # in years
|
||||||
powerUsageEfficiency = 0.5
|
powerUsageEfficiency = 0.5
|
||||||
|
|
||||||
powerUsedInLifetime = (config.get_power_consumption() * containerLifetime * 365 * 24) / powerUsageEfficiency
|
powerUsedInLifetime = (config.get_power_consumption() * containerLifetime * 365 * 24) / powerUsageEfficiency
|
||||||
itemTotalCost = config.get_price() + (powerUsedInLifetime / 1000.0 * kWHPrice )
|
itemTotalCost = config.get_price() + (powerUsedInLifetime / 1000.0 * kWHPrice)
|
||||||
|
|
||||||
item_total_num_ops = config.get_flops() * containerLifetime * 365 * 24 * 3600
|
item_total_num_ops = config.get_flops() * containerLifetime * 365 * 24 * 3600
|
||||||
return item_total_num_ops / itemTotalCost
|
return item_total_num_ops / itemTotalCost
|
||||||
|
|
||||||
|
|
||||||
def plot_configs(configs, xaxis_def, yaxis_def, plot_title):
|
def plot_configs(configs, xaxis_def, yaxis_def, plot_title):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
configs (list(Config)): the tist of configurations to plot
|
configs (list(Config)): the tist of configurations to plot
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def GHzToMHz( frequency ):
|
def GHzToMHz(frequency):
|
||||||
return frequency * 1000.0
|
return frequency * 1000.0
|
||||||
|
|
||||||
def getColorCodeFromItemLabel(label):
|
def getColorCodeFromItemLabel(label):
|
||||||
generation=label[-1]
|
# generation = label[-1]
|
||||||
(num_servers, model, num_cpus, proc_id, ram_size) = re.split('_', label)
|
(num_servers, model, num_cpus, 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,
|
||||||
'haswell':0.2,
|
'haswell': 0.2,
|
||||||
'broadwell':0.2,
|
'broadwell': 0.2,
|
||||||
'skylake':0.4,
|
'skylake': 0.4,
|
||||||
'coffeelake':0.6,
|
'coffeelake': 0.6,
|
||||||
'cascadelake':1.0,
|
'cascadelake': 1.0,
|
||||||
'rome': 0.8,
|
'rome': 0.8,
|
||||||
}[Cpu(proc_id).architecture]
|
}[Cpu(proc_id).architecture]
|
||||||
# if model == 'r620':
|
# if model == 'r620':
|
||||||
# color = 'r'
|
# color = 'r'
|
||||||
# elif model == 'r630':
|
# elif model == 'r630':
|
||||||
# color = 'g'
|
# color = 'g'
|
||||||
# elif model == 'r730':
|
# elif model == 'r730':
|
||||||
# color = 'm'
|
# color = 'm'
|
||||||
# elif model == 'c6220':
|
# elif model == 'c6220':
|
||||||
# if generation == '2':
|
# if generation == '2':
|
||||||
# color = 'b'
|
# color = 'b'
|
||||||
# else:
|
# else:
|
||||||
# color = 'y'
|
# color = 'y'
|
||||||
hue = {
|
hue = {
|
||||||
'dell-poweredge-r620': 0.6,
|
'dell-poweredge-r620': 0.6,
|
||||||
'dell-poweredge-r630': 0.6,
|
'dell-poweredge-r630': 0.6,
|
||||||
|
@ -159,7 +166,7 @@ def plot_configs(configs, xaxis_def, yaxis_def, plot_title):
|
||||||
'dell-poweredge-c6320': 1.0,
|
'dell-poweredge-c6320': 1.0,
|
||||||
'dell-poweredge-c6420': 1.0,
|
'dell-poweredge-c6420': 1.0,
|
||||||
'dell-precision-3630': 0.2
|
'dell-precision-3630': 0.2
|
||||||
}[model]
|
}[model]
|
||||||
value = 0.9
|
value = 0.9
|
||||||
return matplotlib.colors.hsv_to_rgb((hue, saturation, value))
|
return matplotlib.colors.hsv_to_rgb((hue, saturation, value))
|
||||||
|
|
||||||
|
@ -169,15 +176,15 @@ def plot_configs(configs, xaxis_def, yaxis_def, plot_title):
|
||||||
|
|
||||||
markerSize = 50
|
markerSize = 50
|
||||||
|
|
||||||
plt.subplot(1,2,1)
|
plt.subplot(1, 2, 1)
|
||||||
|
|
||||||
markersCycler = itertools.cycle(itertools.product(markerTypes, markerColors))
|
# markersCycler = itertools.cycle(itertools.product(markerTypes, markerColors))
|
||||||
|
|
||||||
config_index = 0
|
config_index = 0
|
||||||
for config in configs:
|
for config in configs:
|
||||||
cpu = config.cpu
|
cpu = config.cpu
|
||||||
config_label = str(config.num_servers) + '_' + config.chassis.uid + '_' + str(config.num_cpu_per_server) + '_' + cpu.uid + '_' + str(config.ram_size/config.num_servers) + 'gb'
|
config_label = str(config.num_servers) + '_' + config.chassis.uid + '_' + str(config.num_cpu_per_server) + '_' + cpu.uid + '_' + str(config.ram_size / config.num_servers) + 'gb'
|
||||||
|
|
||||||
x1 = xaxis_def.get_value_for_config(config)
|
x1 = xaxis_def.get_value_for_config(config)
|
||||||
y1 = yaxis_def.get_value_for_config(config)
|
y1 = yaxis_def.get_value_for_config(config)
|
||||||
|
|
||||||
|
@ -186,22 +193,22 @@ def plot_configs(configs, xaxis_def, yaxis_def, plot_title):
|
||||||
color = getColorCodeFromItemLabel(config_label)
|
color = getColorCodeFromItemLabel(config_label)
|
||||||
# marker = markersCycler.next()
|
# marker = markersCycler.next()
|
||||||
# marker = get_marker_from_label( label )
|
# marker = get_marker_from_label( label )
|
||||||
#print(x1, y1)
|
# print(x1, y1)
|
||||||
short_label = config_label.replace('dell-poweredge-','').replace('intel-xeon-','')
|
short_label = config_label.replace('dell-poweredge-', '').replace('intel-xeon-', '')
|
||||||
plt.scatter( x1, y1, facecolors=color, s=(markerSize * len(create_unique_marker(config_index))) , marker='$\mathrm{%s}$' % create_unique_marker(config_index), label=short_label)
|
plt.scatter(x1, y1, facecolors=color, s=(markerSize * len(create_unique_marker(config_index))), marker='$\mathrm{%s}$' % create_unique_marker(config_index), label=short_label)
|
||||||
if False: # y1 > 5.0e16:
|
if False: # y1 > 5.0e16:
|
||||||
plt.annotate( u'%s' % short_label,
|
plt.annotate(u'%s' % short_label,
|
||||||
xy = (x1, y1), xytext = (x1*4.0, (y1-5.2e16)*7.1),
|
xy=(x1, y1), xytext=(x1 * 4.0, (y1 - 5.2e16) * 7.1),
|
||||||
textcoords = 'data', ha = 'right', va = 'bottom',
|
textcoords='data', ha='right', va='bottom',
|
||||||
bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
|
bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
|
||||||
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
|
arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0'))
|
||||||
config_index += 1
|
config_index += 1
|
||||||
|
|
||||||
plt.xlabel(xaxis_def.get_axis_label())
|
plt.xlabel(xaxis_def.get_axis_label())
|
||||||
plt.ylabel(yaxis_def.get_axis_label())
|
plt.ylabel(yaxis_def.get_axis_label())
|
||||||
plt.title(plot_title)
|
plt.title(plot_title)
|
||||||
plt.xlim( xmin = 0.0 )
|
plt.xlim(xmin=0.0)
|
||||||
plt.ylim( ymin = 0.0 )
|
plt.ylim(ymin=0.0)
|
||||||
plt.minorticks_on()
|
plt.minorticks_on()
|
||||||
plt.grid(b=True, which='major', color='b', linestyle='-', linewidth=0.5)
|
plt.grid(b=True, which='major', color='b', linestyle='-', linewidth=0.5)
|
||||||
plt.grid(b=True, which='minor', color='b', linestyle='-', linewidth=0.2)
|
plt.grid(b=True, which='minor', color='b', linestyle='-', linewidth=0.2)
|
||||||
|
@ -210,7 +217,8 @@ def plot_configs(configs, xaxis_def, yaxis_def, plot_title):
|
||||||
|
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
def plot_configurators(configurators, ram_per_core, xaxis_def, yaxis_def, plot_title, config_filter=lambda config : True):
|
|
||||||
|
def plot_configurators(configurators, ram_per_core, xaxis_def, yaxis_def, plot_title, config_filter=lambda config: True):
|
||||||
configs = []
|
configs = []
|
||||||
for configurator in configurators:
|
for configurator in configurators:
|
||||||
for cpu in configurator.get_cpu_options():
|
for cpu in configurator.get_cpu_options():
|
||||||
|
@ -222,7 +230,3 @@ def plot_configurators(configurators, ram_per_core, xaxis_def, yaxis_def, plot_t
|
||||||
configs.append(config)
|
configs.append(config)
|
||||||
|
|
||||||
plot_configs(configs, xaxis_def=xaxis_def, yaxis_def=yaxis_def, plot_title=plot_title)
|
plot_configs(configs, xaxis_def=xaxis_def, yaxis_def=yaxis_def, plot_title=plot_title)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
plot_2020_matinfo_configs
|
|
||||||
|
|
|
@ -4,9 +4,10 @@ from concho.dell import DellConfiguratorParser2020
|
||||||
from concho.dell import DellConfiguratorParser2021
|
from concho.dell import DellConfiguratorParser2021
|
||||||
from concho.procs_chooser import plot_configurators
|
from concho.procs_chooser import plot_configurators
|
||||||
from concho.procs_chooser import ConfigPrice
|
from concho.procs_chooser import ConfigPrice
|
||||||
from concho.procs_chooser import ConfigFlops
|
# from concho.procs_chooser import ConfigFlops
|
||||||
from concho.procs_chooser import ConfigFlopsPerEuro
|
from concho.procs_chooser import ConfigFlopsPerEuro
|
||||||
|
|
||||||
|
|
||||||
def test_all_matinfo_2020_configs():
|
def test_all_matinfo_2020_configs():
|
||||||
# configurator = DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html')
|
# configurator = DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html')
|
||||||
# print(configurator)
|
# print(configurator)
|
||||||
|
@ -15,10 +16,11 @@ def test_all_matinfo_2020_configs():
|
||||||
DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html', DellConfiguratorParser2020()),
|
DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html', DellConfiguratorParser2020()),
|
||||||
DellMatinfoConfigurator('rcrc1406676-4824727 - Cat 2 Conf 7 PowerEdge R940 - Dell.html', DellConfiguratorParser2020()),
|
DellMatinfoConfigurator('rcrc1406676-4824727 - Cat 2 Conf 7 PowerEdge R940 - Dell.html', DellConfiguratorParser2020()),
|
||||||
# dell.DellPowerEdgeR940(),
|
# dell.DellPowerEdgeR940(),
|
||||||
]
|
]
|
||||||
|
|
||||||
plot_configurators(configurators=configurators, ram_per_core=4.0e9, xaxis_def=ConfigPrice(), yaxis_def=ConfigFlopsPerEuro(), plot_title='total cost including electricity')
|
plot_configurators(configurators=configurators, ram_per_core=4.0e9, xaxis_def=ConfigPrice(), yaxis_def=ConfigFlopsPerEuro(), plot_title='total cost including electricity')
|
||||||
|
|
||||||
|
|
||||||
def test_credits_2020_configs():
|
def test_credits_2020_configs():
|
||||||
# configurator = DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html')
|
# configurator = DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html')
|
||||||
# print(configurator)
|
# print(configurator)
|
||||||
|
@ -27,8 +29,8 @@ def test_credits_2020_configs():
|
||||||
DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html', DellConfiguratorParser2020()),
|
DellMatinfoConfigurator('rcrc1406676-4834664 - Cat2 Conf4 PowerEdge R640 - Dell.html', DellConfiguratorParser2020()),
|
||||||
DellMatinfoConfigurator('rcrc1406676-4824727 - Cat 2 Conf 7 PowerEdge R940 - Dell.html', DellConfiguratorParser2020()),
|
DellMatinfoConfigurator('rcrc1406676-4824727 - Cat 2 Conf 7 PowerEdge R940 - Dell.html', DellConfiguratorParser2020()),
|
||||||
# dell.DellPowerEdgeR940(),
|
# dell.DellPowerEdgeR940(),
|
||||||
]
|
]
|
||||||
|
|
||||||
# config_filter = lambda config : config.cpu.uid in [
|
# config_filter = lambda config : config.cpu.uid in [
|
||||||
# 'intel-xeon-gold-5222',
|
# 'intel-xeon-gold-5222',
|
||||||
# 'intel-xeon-gold-6226r',
|
# 'intel-xeon-gold-6226r',
|
||||||
|
@ -40,18 +42,19 @@ def test_credits_2020_configs():
|
||||||
# 'intel-xeon-gold-6240',
|
# 'intel-xeon-gold-6240',
|
||||||
# ]
|
# ]
|
||||||
|
|
||||||
config_filter = lambda config : config.get_price() < 40000.0
|
def config_filter(config):
|
||||||
|
return config.get_price() < 40000.0
|
||||||
|
|
||||||
plot_configurators(configurators=configurators, ram_per_core=4.0e9, xaxis_def=ConfigPrice(), yaxis_def=ConfigFlopsPerEuro(), plot_title='physmol/ts credit 2020 configs', config_filter=config_filter)
|
plot_configurators(configurators=configurators, ram_per_core=4.0e9, xaxis_def=ConfigPrice(), yaxis_def=ConfigFlopsPerEuro(), plot_title='physmol/ts credit 2020 configs', config_filter=config_filter)
|
||||||
|
|
||||||
|
|
||||||
def test_credits_2021_configs():
|
def test_credits_2021_configs():
|
||||||
configurators = [
|
configurators = [
|
||||||
DellMatinfoConfigurator('20210407 - Cat2 Conf4 PowerEdge R640 - Dell.html', DellConfiguratorParser2021()),
|
DellMatinfoConfigurator('20210407 - Cat2 Conf4 PowerEdge R640 - Dell.html', DellConfiguratorParser2021()),
|
||||||
DellMatinfoConfigurator('20210407 - Cat2 Conf7 PowerEdge R940 - Dell.html', DellConfiguratorParser2021()),
|
DellMatinfoConfigurator('20210407 - Cat2 Conf7 PowerEdge R940 - Dell.html', DellConfiguratorParser2021()),
|
||||||
DellMatinfoConfigurator('20210407 - Cat2 Conf8 PowerEdge R7525 - Dell.html', DellConfiguratorParser2021()),
|
DellMatinfoConfigurator('20210407 - Cat2 Conf8 PowerEdge R7525 - Dell.html', DellConfiguratorParser2021()),
|
||||||
DellMatinfoConfigurator('20210407 - Cat2 Conf10 PowerEdge R6525 - Dell.html', DellConfiguratorParser2021()),
|
# DellMatinfoConfigurator('20210407 - Cat2 Conf10 PowerEdge R6525 - Dell.html', DellConfiguratorParser2021()),
|
||||||
]
|
]
|
||||||
|
|
||||||
# config_filter = lambda config : config.cpu.uid in [
|
# config_filter = lambda config : config.cpu.uid in [
|
||||||
# 'intel-xeon-gold-5222',
|
# 'intel-xeon-gold-5222',
|
||||||
# 'intel-xeon-gold-6226r',
|
# 'intel-xeon-gold-6226r',
|
||||||
|
@ -63,10 +66,11 @@ def test_credits_2021_configs():
|
||||||
# 'intel-xeon-gold-6240',
|
# 'intel-xeon-gold-6240',
|
||||||
# ]
|
# ]
|
||||||
|
|
||||||
config_filter = lambda config : config.get_price() < 20000.0
|
def config_filter(config):
|
||||||
|
return config.get_price() < 40000.0
|
||||||
|
|
||||||
plot_configurators(configurators=configurators, ram_per_core=4.0e9, xaxis_def=ConfigPrice(), yaxis_def=ConfigFlopsPerEuro(), plot_title='physmol/ts credit 2021 configs', config_filter=config_filter)
|
plot_configurators(configurators=configurators, ram_per_core=4.0e9, xaxis_def=ConfigPrice(), yaxis_def=ConfigFlopsPerEuro(), plot_title='physmol/ts credit 2021 configs', config_filter=config_filter)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_credits_2021_configs()
|
test_credits_2021_configs()
|
||||||
|
|
Loading…
Reference in New Issue