66# index_collection.save()
77
88import enum
9+ import logging
10+ import os
911import re
1012import subprocess
1113
1214import cpuinfo
1315import psutil
1416import pyudev
1517
16- from kepler_model .util .loader import load_node_type_index
18+ from kepler_model .util .loader import load_json , load_node_type_index
1719from kepler_model .util .saver import save_machine_spec , save_node_type_index
1820
21+ logger = logging .getLogger (__name__ )
22+
23+ default_machine_spec_file = "/etc/kepler/models/machine/spec.json"
1924
2025def rename (name : str ) -> str :
2126 name = name .replace ("(R)" , "" )
@@ -34,6 +39,8 @@ def rename(name: str) -> str:
3439
3540
3641def format_processor (processor ):
42+ if len (processor ) < 2 : # brand_raw is set to "-" on some machine
43+ return ""
3744 return "_" .join (re .sub (r"\(.*\)" , "" , rename (processor )).split ()).replace ("-" , "_" ).lower ().replace ("_v" , "v" )
3845
3946
@@ -43,8 +50,7 @@ def format_vendor(vendor):
4350
4451GB = 1024 * 1024 * 1024
4552
46-
47- def generate_spec (data_path , machine_id ):
53+ def discover_spec_values ():
4854 processor = ""
4955 vendor = ""
5056 cpu_info = cpuinfo .get_cpu_info ()
@@ -55,19 +61,44 @@ def generate_spec(data_path, machine_id):
5561 if device .get ("ID_VENDOR" ) is not None :
5662 vendor = format_vendor (device .get ("ID_VENDOR" ))
5763 break
64+ if vendor == "" and "vendor_id_raw" in cpu_info :
65+ vendor = format_vendor (cpu_info ["vendor_id_raw" ])
66+
5867 cores = psutil .cpu_count (logical = True )
5968 chips = max (1 , int (subprocess .check_output ('cat /proc/cpuinfo | grep "physical id" | sort -u | wc -l' , shell = True )))
6069 threads_per_core = max (1 , cores // psutil .cpu_count (logical = False ))
6170 memory = psutil .virtual_memory ().total
6271 memory_gb = int (memory / GB )
6372 freq = psutil .cpu_freq (percpu = False )
64- cpu_freq_mhz = round (max (freq .max , freq .current ) / 100 ) * 100 # round to one decimal of GHz
65- spec_values = {"vendor" : vendor , "processor" : processor , "cores" : cores , "chips" : chips , "memory" : memory_gb , "frequency" : cpu_freq_mhz , "threads_per_core" : threads_per_core }
73+ spec_values = {
74+ "vendor" : vendor ,
75+ "processor" : processor ,
76+ "cores" : cores ,
77+ "chips" : chips ,
78+ "memory" : memory_gb ,
79+ "threads_per_core" : threads_per_core
80+ }
81+ if freq is not None :
82+ cpu_freq_mhz = round (max (freq .max , freq .current ) / 100 ) * 100 # round to one decimal of GHz
83+ spec_values ["frequency" ] = cpu_freq_mhz
84+ return spec_values
85+
86+ def generate_spec (data_path , machine_id ):
87+ spec_values = discover_spec_values ()
6688 spec = NodeTypeSpec (** spec_values )
67- print (f"Save machine spec ({ data_path } ): " )
68- print (str (spec ))
89+ logger .info (f"Save machine spec to { data_path } /{ machine_id } " )
6990 save_machine_spec (data_path , machine_id , spec )
7091
92+ def get_machine_spec (cmd_machine_spec_file : str ):
93+ if cmd_machine_spec_file :
94+ spec = load_json (cmd_machine_spec_file )
95+ if spec is not None :
96+ return spec
97+ if os .path .exists (default_machine_spec_file ):
98+ spec = load_json (default_machine_spec_file )
99+ if spec is not None :
100+ return spec
101+ return discover_spec_values ()
71102
72103class NodeAttribute (str , enum .Enum ):
73104 PROCESSOR = "processor"
@@ -76,7 +107,6 @@ class NodeAttribute(str, enum.Enum):
76107 MEMORY = "memory"
77108 FREQ = "frequency"
78109
79-
80110def load_node_type_spec (node_type_index_json ):
81111 node_type_spec_index = dict ()
82112 if node_type_index_json is not None :
@@ -86,9 +116,18 @@ def load_node_type_spec(node_type_index_json):
86116 node_type_spec_index [int (index )] = spec
87117 return node_type_spec_index
88118
89-
90119no_data = None
91120
121+ def attr_has_value (attrs : dict , key : NodeAttribute ) -> bool :
122+ if key not in attrs :
123+ return False
124+ value = attrs [key ]
125+ if value != no_data and value :
126+ if key != NodeAttribute .PROCESSOR :
127+ if float (value ) <= 0 :
128+ return False
129+ return True
130+ return False
92131
93132# NodeTypeSpec defines spec of each node_type index
94133class NodeTypeSpec :
@@ -101,6 +140,13 @@ def __init__(self, **kwargs):
101140 self .attrs [NodeAttribute .FREQ ] = kwargs .get ("frequency" , no_data )
102141 self .members = []
103142
143+ # check if all attribute is none
144+ def is_none (self ):
145+ for key in self .attrs .keys ():
146+ if attr_has_value (self .attrs , key ):
147+ return False
148+ return True
149+
104150 def load (self , json_obj ):
105151 for attr , attr_values in json_obj ["attrs" ].items ():
106152 self .attrs [attr ] = attr_values
@@ -124,7 +170,7 @@ def cover(self, compare_spec):
124170 if not isinstance (compare_spec , NodeTypeSpec ):
125171 return False
126172 for attr in NodeAttribute :
127- if compare_spec .attrs [ attr ] is not None :
173+ if attr_has_value ( compare_spec .attrs , attr ) :
128174 try :
129175 # Attempt to convert values to floats
130176 if float (self .attrs [attr ]) != float (compare_spec .attrs [attr ]):
@@ -205,4 +251,3 @@ def copy(self):
205251 for node_type in removed_items :
206252 del node_collection .node_type_index [node_type ]
207253 return node_collection
208-
0 commit comments