Repository navigation
Expand file tree
/
Copy pathtest_simgraph.cpp
More file actions
150 lines (134 loc) · 4.6 KB
/
Copy pathtest_simgraph.cpp
File metadata and controls
150 lines (134 loc) · 4.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include "SimModule.h"
namespace {
struct Packet {
explicit Packet(int initial) : value(initial) {}
int value;
};
void Check(bool condition, const char* message)
{
if (!condition) {
throw std::runtime_error(message);
}
}
class Stage final : public gfsim::SimModule {
public:
Stage(std::string name, gfsim::SimQueue<Packet>* input,
gfsim::SimQueue<Packet>* output)
: SimModule(std::move(name)), input_(BindInput(input)),
output_(BindOutput(output)) {}
void Build() override {}
void Work() override
{
if (input_->Empty() || output_->Full()) {
return;
}
output_->Write(input_->Front());
input_->Pop();
GetSim()->MarkProgress();
}
void Xfer() override {}
void Reset() override {}
void ReportStat() override {}
private:
INPUT gfsim::SimQueue<Packet>* input_;
OUTPUT gfsim::SimQueue<Packet>* output_;
};
class Pipeline final : public gfsim::SimModule {
public:
explicit Pipeline(gfsim::SimSystem* system)
: SimModule("Pipeline", system) {}
void Build() override
{
SetObjectCapacity(5); // three physical queues and two child modules
auto* input = AddInnerQueue(
std::make_shared<gfsim::SimQueue<Packet>>("input queue"));
auto* middle = AddInnerQueue(
std::make_shared<gfsim::SimQueue<Packet>>("middle queue"));
auto* output = AddInnerQueue(
std::make_shared<gfsim::SimQueue<Packet>>("output queue"));
input_ = BindOutput(input);
output_ = BindInput(output);
AddSubmodule(std::make_shared<Stage>("Stage A", input, middle));
AddSubmodule(std::make_shared<Stage>("Stage B", middle, output));
BuildInnerQueues();
BuildChildren();
}
void Work() override
{
if (!sent_ && !input_->Full()) {
input_->Write(std::make_shared<Packet>(1));
sent_ = true;
GetSim()->MarkProgress();
}
if (!output_->Empty()) {
output_->Read();
GetSim()->MarkProgress();
}
WorkChildren();
}
void Xfer() override { AdvanceInnerQueues(); XferChildren(); }
void Reset() override { sent_ = false; ResetInnerQueues(); ResetChildren(); }
void ReportStat() override { ReportChildren(); }
private:
OUTPUT gfsim::SimQueue<Packet>* input_ = nullptr;
INPUT gfsim::SimQueue<Packet>* output_ = nullptr;
bool sent_ = false;
};
void TestGraph(const std::string& path)
{
gfsim::SimSys system;
auto pipeline = std::make_shared<Pipeline>(&system);
system.AddModule(pipeline);
bool rejected = false;
try {
std::ostringstream beforeBuild;
system.WriteDot(beforeBuild);
} catch (const std::logic_error&) {
rejected = true;
}
Check(rejected, "DOT generation must require a built system");
system.Build();
std::ostringstream graph;
system.WriteDot(graph);
const std::string dot = graph.str();
Check(dot.find("digraph GFSIM") != std::string::npos &&
dot.find("subgraph cluster_m0") != std::string::npos &&
dot.find("subgraph cluster_m1") != std::string::npos &&
dot.find("subgraph cluster_m2") != std::string::npos,
"parent and two children must form nested module subgraphs");
Check(dot.find("shape=cylinder") != std::string::npos &&
dot.find("middle queue") != std::string::npos &&
dot.find("input queue") != std::string::npos &&
dot.find("output queue") != std::string::npos,
"named queues must be visible as queue-shaped nodes");
Check(dot.find("m0 -> q0") != std::string::npos &&
dot.find("q0 -> m1") != std::string::npos &&
dot.find("m1 -> q1") != std::string::npos &&
dot.find("q1 -> m2") != std::string::npos &&
dot.find("m2 -> q2") != std::string::npos &&
dot.find("q2 -> m0") != std::string::npos,
"input and output bindings must become directed queue edges");
system.SaveDot(path);
std::ifstream saved(path);
std::ostringstream savedText;
savedText << saved.rdbuf();
Check(savedText.str() == dot, "SaveDot must write the same graph as WriteDot");
}
} // namespace
int main(int argc, char** argv)
{
try {
Check(argc == 2, "graph test requires an output path");
TestGraph(argv[1]);
} catch (const std::exception& error) {
std::cerr << error.what() << '\n';
return 1;
}
return 0;
}