Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions source/link/link.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include "link/link.hpp"

#include "logger/logger.hpp"
#include "metrics/metrics_collector.hpp"
#include "scheduler.hpp"

namespace sim {
Expand All @@ -15,8 +14,10 @@ Link::Link(Id a_id, std::weak_ptr<IDevice> a_from, std::weak_ptr<IDevice> a_to,
m_to(a_to),
m_speed(a_speed),
m_propagation_delay(a_delay),
m_from_egress(a_max_from_egress_buffer_size),
m_to_ingress(a_max_to_ingress_buffer_size) {
m_from_egress(a_max_from_egress_buffer_size, a_id,
LinkQueueType::FromEgress),
m_to_ingress(a_max_to_ingress_buffer_size, a_id,
LinkQueueType::ToIngress) {
if (a_from.expired() || a_to.expired()) {
LOG_WARN("Passed link to device is expired");
} else if (a_speed == SpeedGbps(0)) {
Expand Down Expand Up @@ -142,10 +143,6 @@ void Link::arrive(Packet packet) {
return;
}

MetricsCollector::get_instance().add_queue_size(
get_id(), Scheduler::get_instance().get_current_time(),
m_from_egress.get_size());

m_to.lock()->notify_about_arrival(
Scheduler::get_instance().get_current_time());
LOG_INFO("Packet arrived to the next device. Packet: " +
Expand Down
6 changes: 3 additions & 3 deletions source/link/link.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include "event/event.hpp"
#include "link/i_link.hpp"
#include "packet_queue/simple_packet_queue.hpp"
#include "packet_queue/link_queue.hpp"

namespace sim {

Expand Down Expand Up @@ -70,10 +70,10 @@ class Link : public ILink, public std::enable_shared_from_this<Link> {
TimeNs m_propagation_delay;

// Queue at the ingress port of the m_to device
SimplePacketQueue m_from_egress;
LinkQueue m_from_egress;

// Queue at the egress port of the m_to device
SimplePacketQueue m_to_ingress;
LinkQueue m_to_ingress;
};

} // namespace sim
2 changes: 1 addition & 1 deletion source/link/packet_queue/i_packet_queue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class IPacketQueue {
virtual ~IPacketQueue() = default;

virtual bool push(Packet packet) = 0;
virtual Packet front() = 0;
virtual Packet front() const = 0;
virtual void pop() = 0;

virtual bool empty() const = 0;
Expand Down
49 changes: 49 additions & 0 deletions source/link/packet_queue/link_queue.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "link_queue.hpp"

#include "metrics/metrics_collector.hpp"
#include "scheduler.hpp"
#include "simple_packet_queue.hpp"

namespace sim {

std::string to_string(LinkQueueType type) {
switch (type) {
case LinkQueueType::FromEgress:
return "from_ingress_queue_size";
case LinkQueueType::ToIngress:
return "to_ingress_queue_size";
default:
LOG_ERROR(fmt::format("Undefined link queue type: {}",
static_cast<int>(type)));
return "queue_size";
}
}

LinkQueue::LinkQueue(SizeByte a_queue_size, Id a_link_id,
LinkQueueType a_type)
: m_queue(a_queue_size), m_link_id(a_link_id), m_type(a_type) {}

bool LinkQueue::push(Packet packet) {
bool result = m_queue.push(std::move(packet));
MetricsCollector::get_instance().add_queue_size(
m_link_id, Scheduler::get_instance().get_current_time(),
m_queue.get_size(), m_type);
return result;
}

Packet LinkQueue::front() const { return m_queue.front(); }

void LinkQueue::pop() {
m_queue.pop();
MetricsCollector::get_instance().add_queue_size(
m_link_id, Scheduler::get_instance().get_current_time(),
m_queue.get_size(), m_type);
}

SizeByte LinkQueue::get_size() const { return m_queue.get_size(); }

bool LinkQueue::empty() const { return m_queue.empty(); }

SizeByte LinkQueue::get_max_size() const { return m_queue.get_max_size(); }

} // namespace sim
32 changes: 32 additions & 0 deletions source/link/packet_queue/link_queue.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include "simple_packet_queue.hpp"

namespace sim {

enum class LinkQueueType { FromEgress, ToIngress };

std::string to_string(LinkQueueType type);

// Class for two types of links:
// eggress queue of sourse link device or
// ingress queue of desination link device
class LinkQueue : public IPacketQueue {
public:
LinkQueue(SizeByte a_max_size, Id a_link_id, LinkQueueType a_type);
~LinkQueue() = default;

bool push(Packet packet) final;
Packet front() const final;
void pop() final;

SizeByte get_size() const final;
bool empty() const final;
SizeByte get_max_size() const final;

private:
SimplePacketQueue m_queue;
Id m_link_id;
LinkQueueType m_type;
};
} // namespace sim
2 changes: 1 addition & 1 deletion source/link/packet_queue/simple_packet_queue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ bool SimplePacketQueue::push(Packet packet) {
return true;
}

Packet SimplePacketQueue::front() {
Packet SimplePacketQueue::front() const {
if (m_queue.empty()) {
throw std::runtime_error("Can not get front packet from empty queue");
}
Expand Down
3 changes: 1 addition & 2 deletions source/link/packet_queue/simple_packet_queue.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#pragma once
#include <optional>
#include <queue>

#include "i_packet_queue.hpp"
Expand All @@ -14,7 +13,7 @@ class SimplePacketQueue : public IPacketQueue {
// returns true on succseed (remaining space is enought), false
// otherwice
bool push(Packet packet) final;
Packet front() final;
Packet front() const final;
void pop() final;

SizeByte get_size() const final;
Expand Down
2 changes: 1 addition & 1 deletion source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ int main(const int argc, char **argv) {
Logger::get_instance().disable_logs();
}

sim::MetricsCollector::get_instance().set_metrics_filter(
sim::MetricsCollector::set_metrics_filter(
flags["metrics-filter"].as<std::string>());

sim::YamlParser parser;
Expand Down
33 changes: 33 additions & 0 deletions source/metrics/draw_plots.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "draw_plots.hpp"

#include "utils/safe_matplot.hpp"

namespace sim {

void draw_on_same_plot(std::filesystem::path path, PlotMetricsData data,
PlotMetadata metadata) {
if (data.empty()) {
return;
}
auto fig = put_on_same_plot(data, metadata);

matplot::safe_save(fig, path.string());
}

matplot::figure_handle put_on_same_plot(PlotMetricsData data,
PlotMetadata metadata) {
auto fig = matplot::figure(true);
auto ax = fig->current_axes();
ax->hold(matplot::on);

for (auto& [values, name] : data) {
values.draw_on_plot(fig, name);
}
ax->xlabel(metadata.x_label);
ax->ylabel(metadata.y_label);
ax->title(metadata.title);
ax->legend(std::vector<std::string>());
return fig;
}

} // namespace sim
17 changes: 17 additions & 0 deletions source/metrics/draw_plots.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once
#include <matplot/matplot.h>

#include "metrics_storage.hpp"

namespace sim {

using PlotMetricsData = std::vector<std::pair<MetricsStorage, std::string> >;

// Puts data from different DataStorage on one plot
matplot::figure_handle put_on_same_plot(PlotMetricsData data,
PlotMetadata metadata);

// Draws data from different DataStorage on one plot
void draw_on_same_plot(std::filesystem::path path, PlotMetricsData data,
PlotMetadata metadata);
} // namespace sim
106 changes: 106 additions & 0 deletions source/metrics/links_queue_size_storage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "links_queue_size_storage.hpp"

#include "draw_plots.hpp"
#include "link/i_link.hpp"
#include "multi_id_metrics_storage.hpp"
#include "utils/safe_matplot.hpp"
#include "write_to_csv.hpp"

namespace sim {

LinksQueueSizeStorage::LinksQueueSizeStorage(std::string a_filter)
: m_filter(a_filter) {}

void LinksQueueSizeStorage::add_record(Id id, LinkQueueType type, TimeNs time,
double value) {
std::pair<Id, LinkQueueType> key = std::make_pair(id, type);
auto it = m_storage.find(key);
if (it == m_storage.end()) {
std::string filename = get_metrics_filename(id);
if (!std::regex_match(filename, m_filter)) {
m_storage[std::move(key)] = std::nullopt;
} else {
MetricsStorage new_storage;
new_storage.add_record(time, value);
m_storage.emplace(std::move(key), std::move(new_storage));
}
} else if (it->second.has_value()) {
it->second->add_record(time, value);
}
}

void LinksQueueSizeStorage::export_to_files(
std::filesystem::path output_dir_path) const {
std::map<Id, std::vector<std::pair<MetricsStorage, std::string> > >
multi_id_storage;
for (const auto& [key, values] : data()) {
auto [id, type] = key;
multi_id_storage[id].emplace_back(values, to_string(type));
}
for (auto [id, storages] : multi_id_storage) {
write_to_csv(storages, output_dir_path / get_metrics_filename(id));
}
}

void LinksQueueSizeStorage::draw_plots(
std::filesystem::path output_dir_path) const {
// for data from both from_ingress and to_ingress queue sizes
std::map<Id, PlotMetricsData> queue_size_data;
for (auto& [key, values] : data()) {
auto [link_id, type] = key;
std::string curve_name = to_string(type);
std::replace(curve_name.begin(), curve_name.end(), '_', ' ');
queue_size_data[link_id].emplace_back(values, curve_name);
}
for (auto [link_id, data] : queue_size_data) {
auto link =
IdentifierFactory::get_instance().get_object<ILink>(link_id);
PlotMetadata metadata = {
"Time, ns", "Values, bytes",
fmt::format("Queue size from {} to {}", link->get_from()->get_id(),
link->get_to()->get_id())};

auto fig = put_on_same_plot(data, metadata);
auto ax = fig->current_axes();

auto limits = ax->xlim();

auto draw_gorizontal_line = [&limits](
double line_y, std::string_view name,
std::initializer_list<float> color) {
matplot::line(0, line_y, limits[1], line_y)
->line_width(1.5)
.color(color)
.display_name(name);
};

draw_gorizontal_line(link->get_max_from_egress_buffer_size().value(),
"max from egress", {1.f, 0.f, 0.f});
draw_gorizontal_line(link->get_max_to_ingress_queue_size().value(),
"max to ingress", {0.f, 0.f, 1.f});

ax->xlim({0, limits[1]});
ax->color("white");

std::filesystem::path plot_path =
output_dir_path / fmt::format("{}.svg", link_id);

matplot::safe_save(fig, plot_path.string());
}
}

std::map<std::pair<Id, LinkQueueType>, MetricsStorage>
LinksQueueSizeStorage::data() const {
std::map<std::pair<Id, LinkQueueType>, MetricsStorage> result;
for (auto [id, maybe_storage] : m_storage) {
if (maybe_storage) {
result[id] = maybe_storage.value();
}
}
return result;
}

std::string LinksQueueSizeStorage::get_metrics_filename(Id id) const {
return fmt::format("queue_size/{}.csv", id);
}
} // namespace sim
35 changes: 35 additions & 0 deletions source/metrics/links_queue_size_storage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once
#include <filesystem>
#include <map>
#include <optional>
#include <regex>
#include <utility>

#include "link/packet_queue/link_queue.hpp"
#include "metrics_storage.hpp"
#include "types.hpp"

namespace sim {
class LinksQueueSizeStorage {
public:
LinksQueueSizeStorage(std::string filter);

void add_record(Id id, LinkQueueType type, TimeNs time, double value);
void export_to_files(std::filesystem::path output_dir_path) const;
void draw_plots(std::filesystem::path output_dir_path) const;

std::map<std::pair<Id, LinkQueueType>, MetricsStorage> data() const;

private:
std::string get_metrics_filename(Id id) const;

// If m_storage does not contain some id, there was no check is metrics file
// name for id correspond to m_filter
// If m_storage[id] = std::nullopt, this check was failed
// Otherwice, check was succseed
std::map<std::pair<Id, LinkQueueType>, std::optional<MetricsStorage>>
m_storage;

std::regex m_filter;
};
} // namespace sim
Loading