239 lines
8.0 KiB
Python
239 lines
8.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
from abc import abstractmethod
|
|
import numpy
|
|
# import pylab
|
|
import matplotlib.pyplot as plt
|
|
import matplotlib.colors
|
|
import itertools
|
|
import re
|
|
import hashlib
|
|
# from string import ascii_lowercase
|
|
# from concho.config import Configurator
|
|
# from concho.config import Config
|
|
from concho.config import Cpu
|
|
# from concho import dell
|
|
|
|
markerTypes = [',', '+', '.', '^', 'v', '<', '>', 'o', '*', '1', '2', '3', '4', '8', 's', 'p', 'h', 'H', 'x', 'X', 'D', 'd', '|', '_']
|
|
# for c in ascii_lowercase:
|
|
# markerTypes.append('$%s$' % c)
|
|
# markerColors=('r', 'g', 'b')
|
|
markerColors = ('r')
|
|
|
|
|
|
def get_marker(proc_id):
|
|
hash_object = hashlib.md5(proc_id.encode('utf-8'))
|
|
hash = int(hash_object.hexdigest(), 16)
|
|
return markerTypes[hash % len(markerTypes)]
|
|
|
|
|
|
def plotCpuPassmark():
|
|
cpuTable = numpy.genfromtxt('cpu_table.tsv', dtype=("|U10", float, int, float, float), names=True, delimiter='\t')
|
|
plt.subplot(1, 1, 0)
|
|
plt.subplots_adjust(bottom=0.1)
|
|
markersCycler = itertools.cycle(itertools.product(markerTypes, markerColors))
|
|
labels = cpuTable['id']
|
|
x = cpuTable['clock'] * cpuTable['num_cores']
|
|
y = cpuTable['cpumark']
|
|
markerSize = 50
|
|
color = 'b'
|
|
for label, x1, y1 in zip(labels, x, y):
|
|
if y1 <= 0.0:
|
|
continue # no passmark available fo this data
|
|
generation = label[-1]
|
|
if generation == '2':
|
|
color = 'b'
|
|
else:
|
|
color = 'r'
|
|
marker = markersCycler.next()
|
|
plt.scatter(x1, y1, color=color, s=markerSize, marker=marker[0], label=label)
|
|
plt.xlabel(u'theoretical cpu speed [core.GHz]')
|
|
plt.ylabel(u'passmark [?]')
|
|
plt.title(u'comparison between cpu theoretical and effective speed')
|
|
plt.xlim(xmin=0.0)
|
|
plt.ylim(ymin=0.0)
|
|
plt.legend(bbox_to_anchor=(0.2, 1.0))
|
|
# plt.legend()
|
|
plt.draw()
|
|
plt.show()
|
|
|
|
|
|
def create_unique_marker(config_index):
|
|
marker_string = ''
|
|
alphabet_size = 26
|
|
alphabel_base = 0x41
|
|
while True:
|
|
digit_index = config_index % alphabet_size
|
|
marker_string = chr(alphabel_base + digit_index) + marker_string
|
|
if config_index < alphabet_size:
|
|
break
|
|
else:
|
|
config_index = config_index // alphabet_size
|
|
return marker_string
|
|
|
|
|
|
class ConfigAxisDef():
|
|
|
|
def __init__(self):
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_axis_label(self):
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_value_for_config(self, config):
|
|
pass
|
|
|
|
|
|
class ConfigPrice(ConfigAxisDef):
|
|
|
|
def get_axis_label(self):
|
|
return u'price [€]'
|
|
|
|
def get_value_for_config(self, config):
|
|
return config.get_price()
|
|
|
|
|
|
class ConfigFlops(ConfigAxisDef):
|
|
|
|
def get_axis_label(self):
|
|
return u'num total DP operations per second'
|
|
|
|
def get_value_for_config(self, config):
|
|
return config.get_flops()
|
|
|
|
|
|
class ConfigFlopsPerEuro(ConfigAxisDef):
|
|
|
|
def get_axis_label(self):
|
|
return u'num total DP operations/total cost [€/^-1]'
|
|
|
|
def get_value_for_config(self, config):
|
|
kWHPrice = 0.30 # from yjuet on 20/01/2023 : 300€/MWh
|
|
containerLifetime = 7.0 # in years
|
|
powerUsageEfficiency = 0.5
|
|
|
|
powerUsedInLifetime = (config.get_power_consumption() * containerLifetime * 365 * 24) / powerUsageEfficiency
|
|
itemTotalCost = config.get_price() + (powerUsedInLifetime / 1000.0 * kWHPrice)
|
|
|
|
item_total_num_ops = config.get_flops() * containerLifetime * 365 * 24 * 3600
|
|
return item_total_num_ops / itemTotalCost
|
|
|
|
|
|
def plot_configs(configs, xaxis_def, yaxis_def, plot_title):
|
|
"""
|
|
Args:
|
|
configs (list(Config)): the tist of configurations to plot
|
|
"""
|
|
|
|
def GHzToMHz(frequency):
|
|
return frequency * 1000.0
|
|
|
|
def getColorCodeFromItemLabel(label):
|
|
# generation = label[-1]
|
|
(num_servers, model, num_cpus, proc_id, ram_size) = re.split('_', label)
|
|
saturation = {
|
|
'sandy bridge': 0.0,
|
|
'ivy bridge': 0.2,
|
|
'haswell': 0.2,
|
|
'broadwell': 0.2,
|
|
'skylake': 0.4,
|
|
'coffeelake': 0.6,
|
|
'cascadelake': 0.8,
|
|
'icelake': 1.0,
|
|
'rome': 0.8,
|
|
'milan': 1.0,
|
|
}[Cpu(proc_id).architecture]
|
|
# if model == 'r620':
|
|
# color = 'r'
|
|
# elif model == 'r630':
|
|
# color = 'g'
|
|
# elif model == 'r730':
|
|
# color = 'm'
|
|
# elif model == 'c6220':
|
|
# if generation == '2':
|
|
# color = 'b'
|
|
# else:
|
|
# color = 'y'
|
|
hue = {
|
|
'dell-poweredge-r620': 0.6,
|
|
'dell-poweredge-r630': 0.6,
|
|
'dell-poweredge-r640': 0.6,
|
|
'dell-poweredge-r6525': 0.5,
|
|
'dell-poweredge-c4310': 0.6,
|
|
'dell-poweredge-r730': 0.4,
|
|
'dell-poweredge-r7525': 0.3,
|
|
'dell-poweredge-r940': 0.8,
|
|
'dell-poweredge-c6220': 1.0,
|
|
'dell-poweredge-c6320': 1.0,
|
|
'dell-poweredge-c6420': 1.0,
|
|
'dell-precision-3630': 0.2,
|
|
'hpe-proliant-dl360-gen10': 0.3,
|
|
'hpe-proliant-dl360-gen10+': 0.55,
|
|
'hpe-proliant-dl385-gen10': 0.0,
|
|
'hpe-proliant-dl385-gen10+': 0.0
|
|
}[model]
|
|
value = 0.9
|
|
return matplotlib.colors.hsv_to_rgb((hue, saturation, value))
|
|
|
|
def get_marker_from_label(label):
|
|
(model, proc_id, ram_size) = re.split('_', label)
|
|
return get_marker(proc_id)
|
|
|
|
markerSize = 50
|
|
|
|
plt.subplot(1, 2, 1)
|
|
|
|
# markersCycler = itertools.cycle(itertools.product(markerTypes, markerColors))
|
|
|
|
config_index = 0
|
|
for config in configs:
|
|
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'
|
|
|
|
x1 = xaxis_def.get_value_for_config(config)
|
|
y1 = yaxis_def.get_value_for_config(config)
|
|
|
|
print(config_label, x1, y1)
|
|
if y1 > 0.0001:
|
|
color = getColorCodeFromItemLabel(config_label)
|
|
# marker = markersCycler.next()
|
|
# marker = get_marker_from_label( label )
|
|
# print(x1, y1)
|
|
short_label = config_label.replace('dell-poweredge-', '').replace('intel-xeon-', '').replace('hpe-proliant-', '').replace('-gen', '-g')
|
|
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:
|
|
plt.annotate(u'%s' % short_label,
|
|
xy=(x1, y1), xytext=(x1 * 4.0, (y1 - 5.2e16) * 7.1),
|
|
textcoords='data', ha='right', va='bottom',
|
|
bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
|
|
arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0'))
|
|
config_index += 1
|
|
|
|
plt.xlabel(xaxis_def.get_axis_label())
|
|
plt.ylabel(yaxis_def.get_axis_label())
|
|
plt.title(plot_title)
|
|
plt.xlim(xmin=0.0)
|
|
plt.ylim(ymin=0.0)
|
|
plt.minorticks_on()
|
|
plt.grid(visible=True, which='major', color='b', linestyle='-', linewidth=0.5)
|
|
plt.grid(visible=True, which='minor', color='b', linestyle='-', linewidth=0.2)
|
|
plt.legend(bbox_to_anchor=(1.1, 1.1), ncol=2)
|
|
plt.draw()
|
|
|
|
plt.show()
|
|
|
|
|
|
def plot_configurators(configurators, ram_per_core, xaxis_def, yaxis_def, plot_title, config_filter=lambda config: True):
|
|
configs = []
|
|
for configurator in configurators:
|
|
for cpu in configurator.get_cpu_options():
|
|
config = configurator.create_config()
|
|
config.num_cpu_per_server = int(min(config.configurator.chassis.item.num_cpu_slots_per_server, cpu.max_cpus))
|
|
config.set_cpu(cpu)
|
|
config.set_ram(ram_per_core=ram_per_core)
|
|
if config_filter(config):
|
|
configs.append(config)
|
|
|
|
plot_configs(configs, xaxis_def=xaxis_def, yaxis_def=yaxis_def, plot_title=plot_title)
|