improved dimm filling in cpu slots

previously, only one dimm was used per channel, which resulted in too expensive configurations when the number of cores increased.
This commit is contained in:
Guillaume Raffy 2020-09-28 17:09:23 +02:00
parent 53eb1be087
commit a22f88ec6a
2 changed files with 74 additions and 29 deletions

View File

@ -2,6 +2,7 @@ import re
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
import numpy import numpy
from concho import dell from concho import dell
import math
class Item(): class Item():
@ -190,7 +191,7 @@ class Config():
def __init__(self, configurator): def __init__(self, configurator):
self.configurator = configurator self.configurator = configurator
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.cpu_slots_mem = [] self.cpu_slots_mem = []
@ -199,6 +200,48 @@ class Config():
def chassis(self): def chassis(self):
return self.configurator.chassis.item return self.configurator.chassis.item
@staticmethod
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
slot_options = []
# try all combinations of dimms
best_slot_options = None
best_price = None
for slot_index in range(num_dimm_slots_per_channel):
slot_options.append(0)
no_more_configs = False
while no_more_configs == False:
config_capacity = 0
config_price = 0
for slot_index in range(num_dimm_slots_per_channel):
dimm_option = available_dimms[slot_options[slot_index]]
config_capacity += float(dimm_option.item.num_gb) * math.pow(2.0, 30.0)
config_price += dimm_option.price
if config_capacity >= min_ram_per_channel: # only remember the combination if it complies with the minimal memory constraint
if best_price is None or config_price < best_price:
best_price = config_price
best_slot_options = slot_options.copy()
# generate the next combination of dimms
for slot_index in range(num_dimm_slots_per_channel):
slot_options[slot_index] += 1
if slot_options[slot_index] < len(available_dimms):
break
else:
if slot_index == num_dimm_slots_per_channel - 1:
no_more_configs = True # all combinations of dimm in the slots have been covered
else:
slot_options[slot_index] = 0
assert best_slot_options is not None, "Failed to find a dimm combination that provides %f bytes per channel." % min_ram_per_channel
slot_dimms = []
for dimm_slot_index in range(num_dimm_slots_per_channel):
dimm = available_dimms[best_slot_options[dimm_slot_index]].item
if dimm.num_gb == 0:
dimm = None
slot_dimms.append(dimm)
return slot_dimms
def set_ram(self, ram_per_core=None, ram_per_server=None, ram_per_cpu=None): def set_ram(self, ram_per_core=None, ram_per_server=None, ram_per_cpu=None):
# ramUpgradePrice128Gb = { # ramUpgradePrice128Gb = {
@ -225,33 +268,14 @@ class Config():
ram_per_cpu = ram_per_server / self.num_cpu_per_server ram_per_cpu = ram_per_server / self.num_cpu_per_server
ram_per_channel = ram_per_cpu / cpu.num_ram_channels ram_per_channel = ram_per_cpu / cpu.num_ram_channels
dimm_capacity = None
if ram_per_channel > 64.0e9: slot_dimms = Config._find_dimm_combination(self.configurator.chassis.item.num_dimm_slots_per_channel, ram_per_channel, self.configurator.get_dimm_options())
assert False, 'ram_per_channel is too big (%f bytes > 64 Gb)' % ram_per_channel
elif ram_per_channel > 32.0e9: print(cpu.uid, cpu.num_cores, ram_per_channel, [0 if dimm is None else dimm.num_gb for dimm in slot_dimms])
dimm_capacity = 64
elif ram_per_channel > 16.0e9:
dimm_capacity = 32
elif ram_per_channel > 8.0e9:
dimm_capacity = 16
elif ram_per_channel > 4.0e9:
dimm_capacity = 8
else:
try:
self.configurator.get_dimm_price(4)
dimm_capacity = 4
except:
# 4Gb dimms are not available, use 8 Gb instead
dimm_capacity = 8
# print('warning : forcing dimm capacity to 16G !!!!!!')
# dimm_capacity = 16
dimm = self.configurator.get_dimm(dimm_capacity)
assert dimm
print(cpu.uid, cpu.num_cores, ram_per_channel)
for cpu_slot_mem in self.cpu_slots_mem: for cpu_slot_mem in self.cpu_slots_mem:
for mem_channel in cpu_slot_mem.mem_channels: for mem_channel in cpu_slot_mem.mem_channels:
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):
mem_channel.dimms[dimm_slot_index] = dimm mem_channel.dimms[dimm_slot_index] = slot_dimms[dimm_slot_index]
@property @property
def ram_size(self): def ram_size(self):
@ -293,20 +317,38 @@ class Config():
return flops return flops
def set_cpu(self, cpu): def _init_dimm_slots(self):
self.cpu = cpu
# create the dimm slots # create the dimm slots
self.cpu_slots_mem = [] self.cpu_slots_mem = []
if self.cpu is None:
return
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(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):
mem_channel.dimms.append(None) # dimm slots are empty mem_channel.dimms.append(None) # dimm slots are empty
cpu_slot_mem.mem_channels.append(mem_channel) cpu_slot_mem.mem_channels.append(mem_channel)
self.cpu_slots_mem.append(cpu_slot_mem) self.cpu_slots_mem.append(cpu_slot_mem)
def set_cpu(self, cpu):
self.cpu = cpu
# update the dimm slots accordingly
self._init_dimm_slots()
@property
def num_cpu_per_server(self):
return self._num_cpu_per_server
@num_cpu_per_server.setter
def num_cpu_per_server(self, num_cpu_per_server):
self._num_cpu_per_server = num_cpu_per_server
# update the dimm slots accordingly
self._init_dimm_slots()
@property @property
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
@ -353,6 +395,9 @@ 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_dimm_options(self):
return list(self.modules['ram'].options.values())
def get_item(self, item_uid): def get_item(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:

View File

@ -142,9 +142,9 @@ def plot_system_efficiency():
if not cpu.architecture in ['coffeelake', 'skylake','cascadelake']: if not cpu.architecture in ['coffeelake', 'skylake','cascadelake']:
continue continue
config = configurator.create_config() config = configurator.create_config()
config.num_cpu_per_server = config.configurator.chassis.item.num_cpu_slots_per_server
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
item_label = numpy.append( item_label, config.chassis.uid + '_' + cpu.uid + '_' + str(config.ram_size) + 'gb' ) 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