1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-10 01:17:40 +03:00

B #6027: Parse host NUMA monitoring (#2440)

Co-authored-by: Ruben S. Montero <rsmontero@opennebula.org>
This commit is contained in:
Pavel Czerný 2023-01-09 18:29:09 +01:00 committed by GitHub
parent bc0caa82f3
commit 0696693531
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 297 additions and 48 deletions

View File

@ -18,6 +18,8 @@
#include "Template.h" #include "Template.h"
class ObjectXML;
/** /**
* CapacityMonitoring stores host monitoring values like * CapacityMonitoring stores host monitoring values like
* - FREE_CPU * - FREE_CPU
@ -56,6 +58,44 @@ public:
int from_template(const Template &tmpl); int from_template(const Template &tmpl);
}; };
class NUMAMonitoringNode : public Template
{
public:
NUMAMonitoringNode()
: Template(false, '=', "NUMA_NODE")
{}
};
/**
* NUMA stores hugepages and memory monitoring
* <NUMA_NODE>
* <ID>
* <HUGEPAGE>
* <SIZE>
* <FREE>
* <MEMORY>
* <FREE>
* <USED>
*/
class NUMAMonitoring
{
public:
NUMAMonitoring() = default;
std::string to_xml() const;
int from_xml(ObjectXML& xml, const std::string& xpath_prefix);
int from_template(const Template &tmpl);
private:
void set_huge_page(unsigned int node_id, unsigned long size, unsigned long fr);
void set_memory(unsigned int node_id, unsigned long used, unsigned long fr);
std::map<unsigned int, NUMAMonitoringNode> nodes;
};
/** /**
* HostMonitoringTemplate stores all host monitoring info, divided to 3 main sections: * HostMonitoringTemplate stores all host monitoring info, divided to 3 main sections:
* - capacity * - capacity
@ -89,6 +129,7 @@ private:
CapacityMonitoring capacity; CapacityMonitoring capacity;
SystemMonitoring system; SystemMonitoring system;
NUMAMonitoring numa;
}; };
#endif // HOST_MONITORING_TEMPLATE_H_ #endif // HOST_MONITORING_TEMPLATE_H_

View File

@ -31,18 +31,21 @@
/** /**
* This class represents the NUMA nodes in a hypervisor for the following attr: * This class represents the NUMA nodes in a hypervisor for the following attr:
* NODE_ID = 0 * NODE_ID = 0
* HUGEPAGE = [ SIZE = "2048", PAGES = "0", FREE = "0"] * HUGEPAGE = [ SIZE = "2048", PAGES = "0", USAGE = "0" ]
* HUGEPAGE = [ SIZE = "1048576", PAGES = "0", FREE = "0"] * HUGEPAGE = [ SIZE = "1048576", PAGES = "0", USAGE = "0" ]
* CORE = [ ID = "3", CPUS = "3:-1,7:-1", FREE = 2] * CORE = [ ID = "3", CPUS = "3:-1,7:-1", FREE = 2, DEDICATED="NO"]
* CORE = [ ID = "1", CPUS = "1:23,5:-1", FREE = 0 ] * CORE = [ ID = "1", CPUS = "1:23,5:-1", FREE = 0, DEDICATED="YES" ]
* CORE = [ ID = "2", CPUS = "2:47,6:-1", FREE = 1] * CORE = [ ID = "2", CPUS = "2:47,6:-1", FREE = 1, DEDICATED="NO"]
* CORE = [ ID = "0", CPUS = "0:23,4:-1", FREE = 0] * CORE = [ ID = "0", CPUS = "0:23,4:-1", FREE = 0, DEDICATED="NO"]
* MEMORY = [ TOTAL = "66806708", FREE = "390568", USED = "66416140", * MEMORY = [ TOTAL = "66806708", DISTANCE = "0 1", USAGE = "8388608" ]
* DISTANCE = "0 1", USAGE = "8388608" ]
* *
* - NODE_ID * - NODE_ID
* - HUGEPAGE is the total PAGES and FREE hugepages of a given SIZE in the node * - HUGEPAGE is the total PAGES and USAGE hugepages of a given SIZE in the node
* - CORE is a CPU core with its ID and sibling CPUs for HT architectures * - CORE is a CPU core with its ID and sibling CPUs for HT architectures
* - USAGE - hugepages or memory allocated by oned
*
* The free hugaepages and memory capacity is stored in the monitoring node,
* see HostMonitoringTemplate.h
*/ */
class HostShareNode : public Template class HostShareNode : public Template
{ {
@ -195,17 +198,15 @@ private:
unsigned long size_kb; unsigned long size_kb;
unsigned int nr; unsigned int nr;
unsigned int free;
unsigned long usage; unsigned long usage;
unsigned long allocated; unsigned long allocated;
/** /**
* @return a VectorAttribute representing this core in the form: * @return a VectorAttribute representing this core in the form:
* HUGEPAGE = [ SIZE = "1048576", PAGES = "200", FREE = "100", * HUGEPAGE = [ SIZE = "1048576", PAGES = "200", USAGE = "100"]
* USAGE = "100"]
*/ */
VectorAttribute * to_attribute(); VectorAttribute * to_attribute() const;
}; };
/** /**
@ -225,13 +226,11 @@ private:
/** /**
* Memory information for this node: * Memory information for this node:
* - total, free and used memory as reported by IM (meminfo file) * - total_mem total memory available
* - mem_used memory allocated to VMs by oned in this node * - mem_usage memory allocated to VMs by oned in this node
* - distance sorted list of nodes, first is the closest (this one) * - distance sorted list of nodes, first is the closest (this one)
*/ */
long long total_mem = 0; long long total_mem = 0;
long long free_mem = 0;
long long used_mem = 0;
long long mem_usage = 0; long long mem_usage = 0;
@ -272,10 +271,9 @@ private:
* hugepage of the same size already exists this function does nothing * hugepage of the same size already exists this function does nothing
* @param size in kb of the page * @param size in kb of the page
* @param nr number of pages * @param nr number of pages
* @param free pages
* @param update if true also adds the page to the object Template * @param update if true also adds the page to the object Template
*/ */
void set_hugepage(unsigned long size, unsigned int nr, unsigned int fr, void set_hugepage(unsigned long size, unsigned int nr,
unsigned long usage, bool update); unsigned long usage, bool update);
void update_hugepage(unsigned long size); void update_hugepage(unsigned long size);

View File

@ -98,7 +98,6 @@
<xs:element name="HUGEPAGE" minOccurs="0" maxOccurs="unbounded"> <xs:element name="HUGEPAGE" minOccurs="0" maxOccurs="unbounded">
<xs:complexType> <xs:complexType>
<xs:all> <xs:all>
<xs:element name="FREE" type="xs:integer"/>
<xs:element name="PAGES" type="xs:integer"/> <xs:element name="PAGES" type="xs:integer"/>
<xs:element name="SIZE" type="xs:integer"/> <xs:element name="SIZE" type="xs:integer"/>
<xs:element name="USAGE" type="xs:integer"/> <xs:element name="USAGE" type="xs:integer"/>
@ -109,10 +108,8 @@
<xs:complexType> <xs:complexType>
<xs:all> <xs:all>
<xs:element name="DISTANCE" type="xs:string"/> <xs:element name="DISTANCE" type="xs:string"/>
<xs:element name="FREE" type="xs:integer"/>
<xs:element name="TOTAL" type="xs:integer"/> <xs:element name="TOTAL" type="xs:integer"/>
<xs:element name="USAGE" type="xs:integer"/> <xs:element name="USAGE" type="xs:integer"/>
<xs:element name="USED" type="xs:integer"/>
</xs:all> </xs:all>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
@ -177,6 +174,25 @@
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="NUMA_NODE" minOccurs="0" maxOccurs="unbounded">
<xs:element name="HUGEPAGE" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:all>
<xs:element name="FREE" type="xs:integer"/>
<xs:element name="SIZE" type="xs:integer"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="MEMORY">
<xs:complexType>
<xs:all>
<xs:element name="FREE" type="xs:string"/>
<xs:element name="USED" type="xs:integer"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="NODE_ID" type="xs:integer"/>
</xs:element>
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>

View File

@ -684,7 +684,14 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
end end
if numa_nodes && !numa_nodes.empty? if numa_nodes && !numa_nodes.empty?
print_numa_nodes(numa_nodes) begin
monitoring_numa =
host.to_hash['HOST']['MONITORING']['NUMA_NODE']
rescue StandardError
monitoring_numa = nil
end
print_numa_nodes(numa_nodes, monitoring_numa)
end end
puts puts
@ -769,14 +776,34 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
table.show(pcis) table.show(pcis)
end end
def print_numa_nodes(numa_nodes) def print_numa_nodes(numa_nodes, monitoring)
numa_nodes = get_numa_data(numa_nodes) numa_nodes = get_numa_data(numa_nodes)
merge_numa_monitoring(numa_nodes, monitoring)
print_numa_cores(numa_nodes) print_numa_cores(numa_nodes)
print_numa_memory(numa_nodes) print_numa_memory(numa_nodes)
print_numa_hugepages(numa_nodes) print_numa_hugepages(numa_nodes)
end end
def merge_numa_monitoring(numa_nodes, monitoring)
return if monitoring.nil?
monitoring = [monitoring] if monitoring.class == Hash
numa_nodes.each do |node|
mon_node = monitoring.find {|x| x['NODE_ID'] == node['NODE_ID'] }
node['MEMORY']['FREE'] = mon_node['MEMORY']['FREE']
node['MEMORY']['USED'] = mon_node['MEMORY']['USED']
node['HUGEPAGE'].each do |hp|
mon_hp = mon_node['HUGEPAGE'].find {|x| x['SIZE'] == hp['SIZE'] }
hp['FREE'] = mon_hp['FREE']
end
end
end
def get_numa_data(numa_nodes) def get_numa_data(numa_nodes)
numa_nodes = [numa_nodes] if numa_nodes.class == Hash numa_nodes = [numa_nodes] if numa_nodes.class == Hash
@ -886,8 +913,12 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
end end
column :USED_REAL, 'Used memory', :size => 20, :left => true do |d| column :USED_REAL, 'Used memory', :size => 20, :left => true do |d|
if d['MEMORY']['USED'].nil?
'-'
else
OpenNebulaHelper.unit_to_str(d['MEMORY']['USED'].to_i, {}) OpenNebulaHelper.unit_to_str(d['MEMORY']['USED'].to_i, {})
end end
end
column :USED_ALLOCATED, 'U memory', column :USED_ALLOCATED, 'U memory',
:size => 20, :left => true do |d| :size => 20, :left => true do |d|
@ -895,8 +926,12 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
end end
column :FREE, 'Free memory', :size => 8, :left => true do |d| column :FREE, 'Free memory', :size => 8, :left => true do |d|
if d['MEMORY']['FREE'].nil?
'-'
else
OpenNebulaHelper.unit_to_str(d['MEMORY']['FREE'].to_i, {}) OpenNebulaHelper.unit_to_str(d['MEMORY']['FREE'].to_i, {})
end end
end
default :NODE_ID, :TOTAL, :USED_REAL, :USED_ALLOCATED, :FREE default :NODE_ID, :TOTAL, :USED_REAL, :USED_ALLOCATED, :FREE
end end
@ -933,7 +968,7 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
end end
column :FREE, 'Free pages', :size => 8, :left => true do |d| column :FREE, 'Free pages', :size => 8, :left => true do |d|
d['HUGEPAGE']['FREE'] d['HUGEPAGE']['FREE'] || '-'
end end
column :USED, 'allocated pages', :size => 8, :left => true do |d| column :USED, 'allocated pages', :size => 8, :left => true do |d|

View File

@ -16,6 +16,7 @@
#include "HostMonitoringTemplate.h" #include "HostMonitoringTemplate.h"
#include "ObjectXML.h" #include "ObjectXML.h"
#include "NebulaLog.h"
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -73,6 +74,174 @@ int SystemMonitoring::from_template(const Template &tmpl)
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
string NUMAMonitoring::to_xml() const
{
ostringstream oss;
string node_str;
for (const auto& node : nodes)
{
oss << node.second.to_xml(node_str);
}
return oss.str();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int NUMAMonitoring::from_xml(ObjectXML& xml, const std::string& xpath_prefix)
{
vector<xmlNodePtr> content;
xml.get_nodes(xpath_prefix + "NUMA_NODE", content);
for (const auto node_xml : content)
{
NUMAMonitoringNode node;
node.from_xml_node(node_xml);
unsigned int id;
node.get("NODE_ID", id);
nodes[id] = node;
}
xml.free_nodes(content);
content.clear();
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int NUMAMonitoring::from_template(const Template &tmpl)
{
// Parse HugePages
vector<const VectorAttribute*> huge_pages;
tmpl.get("HUGEPAGE", huge_pages);
for (const auto* page : huge_pages)
{
int node_id;
unsigned long size;
unsigned long fr;
ostringstream oss;
if (page->vector_value("NODE_ID", node_id) != 0)
{
page->to_token(oss);
NebulaLog::warn("HMM", "Hugepage doesn't contain node ID: "
+ oss.str());
continue;
}
if (page->vector_value("SIZE", size) != 0)
{
page->to_token(oss);
NebulaLog::warn("HMM", "Hugepage doesn't contain size: "
+ oss.str());
continue;
}
page->vector_value("FREE", fr);
set_huge_page(node_id, size, fr);
}
// Parse Memory nodes
vector<const VectorAttribute*> mem_nodes;
tmpl.get("MEMORY_NODE", mem_nodes);
for (const auto* mem : mem_nodes)
{
int node_id;
unsigned long used;
unsigned long fr;
ostringstream oss;
if (mem->vector_value("NODE_ID", node_id) != 0)
{
mem->to_token(oss);
NebulaLog::warn("HMM", "Memory node doesn't contain node ID: "
+ oss.str());
continue;
}
mem->vector_value("USED", used);
mem->vector_value("FREE", fr);
set_memory(node_id, used, fr);
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void NUMAMonitoring::set_huge_page(unsigned int node_id, unsigned long size, unsigned long fr)
{
NUMAMonitoringNode* node;
auto it = nodes.find(node_id);
if ( it != nodes.end())
{
node = &it->second;
}
else
{
auto res = nodes.insert(make_pair(node_id, NUMAMonitoringNode()));
node = &res.first->second;
node->add("NODE_ID", node_id);
}
auto vatt = new VectorAttribute("HUGEPAGE");
vatt->replace("SIZE", size);
vatt->replace("FREE", fr);
node->set(vatt);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void NUMAMonitoring::set_memory(unsigned int node_id, unsigned long used, unsigned long fr)
{
NUMAMonitoringNode* node;
auto it = nodes.find(node_id);
if ( it != nodes.end())
{
node = &it->second;
}
else
{
auto res = nodes.insert(make_pair(node_id, NUMAMonitoringNode()));
node = &res.first->second;
node->add("NODE_ID", node_id);
}
auto vatt = new VectorAttribute("MEMORY");
vatt->replace("USED", used);
vatt->replace("FREE", fr);
node->set(vatt);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string HostMonitoringTemplate::to_xml() const string HostMonitoringTemplate::to_xml() const
{ {
if (_oid == -1) if (_oid == -1)
@ -91,6 +260,7 @@ string HostMonitoringTemplate::to_xml() const
oss << xml_print(ID, _oid); oss << xml_print(ID, _oid);
oss << capacity.to_xml(capacity_s); oss << capacity.to_xml(capacity_s);
oss << system.to_xml(system_s); oss << system.to_xml(system_s);
oss << numa.to_xml();
oss << "</MONITORING>"; oss << "</MONITORING>";
@ -135,6 +305,9 @@ int HostMonitoringTemplate::from_xml(const std::string& xml_string)
content.clear(); content.clear();
} }
// ------------ NUMA ---------------
numa.from_xml(xml, "/MONITORING/");
return 0; return 0;
} }
@ -156,6 +329,7 @@ int HostMonitoringTemplate::from_template(const Template &tmpl)
int rc = capacity.from_template(tmpl); int rc = capacity.from_template(tmpl);
rc += system.from_template(tmpl); rc += system.from_template(tmpl);
rc += numa.from_template(tmpl);
return rc; return rc;
} }

View File

@ -232,13 +232,12 @@ VectorAttribute * HostShareNode::Core::to_attribute()
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
VectorAttribute * HostShareNode::HugePage::to_attribute() VectorAttribute * HostShareNode::HugePage::to_attribute() const
{ {
VectorAttribute * vpage = new VectorAttribute("HUGEPAGE"); VectorAttribute * vpage = new VectorAttribute("HUGEPAGE");
vpage->replace("SIZE", size_kb); vpage->replace("SIZE", size_kb);
vpage->replace("PAGES", nr); vpage->replace("PAGES", nr);
vpage->replace("FREE", free);
vpage->replace("USAGE", usage); vpage->replace("USAGE", usage);
return vpage; return vpage;
@ -342,15 +341,13 @@ int HostShareNode::from_xml_node(const xmlNodePtr &node, unsigned int _vt)
unsigned long size_kb, usage_kb; unsigned long size_kb, usage_kb;
unsigned int nr; unsigned int nr;
unsigned int free;
(*vp_it)->vector_value("SIZE", size_kb); (*vp_it)->vector_value("SIZE", size_kb);
(*vp_it)->vector_value("PAGES",nr); (*vp_it)->vector_value("PAGES",nr);
(*vp_it)->vector_value("FREE", free);
(*vp_it)->vector_value("USAGE", usage_kb); (*vp_it)->vector_value("USAGE", usage_kb);
set_hugepage(size_kb, nr, free, usage_kb, false); set_hugepage(size_kb, nr, usage_kb, false);
} }
std::string distance_s; std::string distance_s;
@ -359,8 +356,6 @@ int HostShareNode::from_xml_node(const xmlNodePtr &node, unsigned int _vt)
if (memory != 0) if (memory != 0)
{ {
memory->vector_value("TOTAL", total_mem); memory->vector_value("TOTAL", total_mem);
memory->vector_value("FREE", free_mem);
memory->vector_value("USED", used_mem);
memory->vector_value("USAGE", mem_usage); memory->vector_value("USAGE", mem_usage);
@ -580,8 +575,6 @@ void HostShareNode::set_memory()
VectorAttribute * mem = new VectorAttribute("MEMORY"); VectorAttribute * mem = new VectorAttribute("MEMORY");
mem->replace("TOTAL", total_mem); mem->replace("TOTAL", total_mem);
mem->replace("USED", used_mem);
mem->replace("FREE", free_mem);
mem->replace("USAGE", mem_usage); mem->replace("USAGE", mem_usage);
@ -625,16 +618,15 @@ void HostShareNode::set_core(unsigned int id, std::string& cpus,
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void HostShareNode::set_hugepage(unsigned long size, unsigned int nr, void HostShareNode::set_hugepage(unsigned long size, unsigned int nr,
unsigned int fr, unsigned long usage, bool update) unsigned long usage, bool update)
{ {
auto pt = pages.find(size); auto pt = pages.find(size);
if ( pt != pages.end() ) if ( pt != pages.end() )
{ {
if ( nr != pt->second.nr || fr != pt->second.free ) if ( nr != pt->second.nr )
{ {
pt->second.nr = nr; pt->second.nr = nr;
pt->second.free = fr;
update_hugepages(); update_hugepages();
} }
@ -642,7 +634,7 @@ void HostShareNode::set_hugepage(unsigned long size, unsigned int nr,
return; return;
} }
HugePage h = {size, nr, fr, usage, 0}; HugePage h = {size, nr, usage, 0};
pages.insert(make_pair(h.size_kb, h)); pages.insert(make_pair(h.size_kb, h));
@ -802,7 +794,6 @@ void HostShareNUMA::set_monitorization(Template &ht, unsigned int _vt)
for (auto it = pages.begin(); it != pages.end(); ++it) for (auto it = pages.begin(); it != pages.end(); ++it)
{ {
unsigned int pages = 0; unsigned int pages = 0;
unsigned int free = 0;
unsigned long size = 0; unsigned long size = 0;
@ -812,12 +803,11 @@ void HostShareNUMA::set_monitorization(Template &ht, unsigned int _vt)
} }
(*it)->vector_value("SIZE", size); (*it)->vector_value("SIZE", size);
(*it)->vector_value("FREE", free);
(*it)->vector_value("PAGES",pages); (*it)->vector_value("PAGES",pages);
HostShareNode& node = get_node(node_id); HostShareNode& node = get_node(node_id);
node.set_hugepage(size, pages, free, 0, true); node.set_hugepage(size, pages, 0, true);
} }
std::vector<VectorAttribute *> memory; std::vector<VectorAttribute *> memory;
@ -836,8 +826,6 @@ void HostShareNUMA::set_monitorization(Template &ht, unsigned int _vt)
HostShareNode& node = get_node(node_id); HostShareNode& node = get_node(node_id);
(*it)->vector_value("TOTAL", node.total_mem); (*it)->vector_value("TOTAL", node.total_mem);
(*it)->vector_value("FREE", node.free_mem);
(*it)->vector_value("USED", node.used_mem);
(*it)->vector_value("DISTANCE", distance_s); (*it)->vector_value("DISTANCE", distance_s);

View File

@ -105,7 +105,6 @@ type NumaNode struct {
} }
type HugePage struct { type HugePage struct {
Free int `xml:"FREE,omitempty"`
Pages int `xml:"PAGES,omitempty"` Pages int `xml:"PAGES,omitempty"`
Size int `xml:"SIZE,omitempty"` Size int `xml:"SIZE,omitempty"`
Usage int `xml:"USAGE,omitempty"` Usage int `xml:"USAGE,omitempty"`
@ -113,10 +112,8 @@ type HugePage struct {
type Memory struct { type Memory struct {
Distance string `xml:"DISTANCE,omitempty"` Distance string `xml:"DISTANCE,omitempty"`
Free int `xml:"FREE,omitempty"`
Total int `xml:"TOTAL,omitempty"` Total int `xml:"TOTAL,omitempty"`
Usage int `xml:"USAGE,omitempty"` Usage int `xml:"USAGE,omitempty"`
Used int `xml:"USED,omitempty"`
} }
type Core struct { type Core struct {