Project
Loading...
Searching...
No Matches
test_Graphviz.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#include "Mocking.h"
13#include "../src/ComputingResourceHelpers.h"
14#include "../src/DeviceSpecHelpers.h"
15#include "../src/GraphvizHelpers.h"
16#include "../src/SimpleResourceManager.h"
19#include "Headers/DataHeader.h"
20
21#include <catch_amalgamated.hpp>
22#include <sstream>
23
24using namespace o2::framework;
25
26// because comparing the whole thing is a pain.
27void lineByLineComparision(const std::string& as, const std::string& bs)
28{
29 std::istringstream a(as);
30 std::istringstream b(bs);
31
32 char bufferA[1024];
33 char bufferB[1024];
34 while (a.good() && b.good()) {
35 a.getline(bufferA, 1024);
36 b.getline(bufferB, 1024);
37 REQUIRE(std::string(bufferA) == std::string(bufferB));
38 }
39 REQUIRE(a.eof());
40 REQUIRE(b.eof());
41}
42
43namespace
44{
45// This is how you can define your processing in a declarative way
47{
48 return {{"A", Inputs{},
49 Outputs{OutputSpec{"TST", "A1"},
50 OutputSpec{"TST", "A2"}}},
51 {"B",
52 {InputSpec{"x", "TST", "A1"}},
53 Outputs{OutputSpec{"TST", "B1"}}},
54 {"C", Inputs{InputSpec{"x", "TST", "A2"}},
55 Outputs{OutputSpec{"TST", "C1"}}},
56 {"D",
57 Inputs{InputSpec{"i1", "TST", "B1"},
58 InputSpec{"i2", "TST", "C1"}},
59 Outputs{}}};
60}
61} // namespace
62
63namespace
64{
65
67{
68 return {
69 {"A",
70 {},
71 {
72 OutputSpec{"TST", "A"},
73 }},
74 timePipeline({"B",
75 {InputSpec{"a", "TST", "A"}},
76 {OutputSpec{"TST", "B"}}},
77 3),
78 timePipeline({"C",
79 {InputSpec{"b", "TST", "B"}},
80 {OutputSpec{"TST", "C"}}},
81 2),
82 };
83}
84} // namespace
85
86TEST_CASE("TestGraphviz")
87{
88 auto workflow = defineDataProcessing();
89 std::ostringstream str;
90 auto expectedResult = R"EXPECTED(digraph structs {
91 node[shape=record]
92 "A" [label="A"];
93 "B" [label="B"];
94 "C" [label="C"];
95 "D" [label="D"];
96}
97)EXPECTED";
99 lineByLineComparision(str.str(), expectedResult);
100 std::vector<DeviceSpec> devices;
101 for (auto& device : devices) {
102 REQUIRE(device.id != "");
103 }
104 auto configContext = makeEmptyConfigContext();
105 auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext);
106 auto completionPolicies = CompletionPolicy::createDefaultPolicies();
107 auto callbacksPolicies = CallbacksPolicy::createDefaultPolicies();
108 std::vector<ComputingResource> resources = {ComputingResourceHelpers::getLocalhostResource()};
109 SimpleResourceManager rm(resources);
110 DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow, channelPolicies, completionPolicies, callbacksPolicies, devices, rm, "workflow-id", *configContext);
111 str.str("");
113 lineByLineComparision(str.str(), R"EXPECTED(digraph structs {
114 node[shape=record]
115 "A" [label="{{}|A(2)|{<from_A_to_B>from_A_to_B|<from_A_to_C>from_A_to_C}}"];
116 "B" [label="{{<from_A_to_B>from_A_to_B}|B(2)|{<from_B_to_D>from_B_to_D}}"];
117 "C" [label="{{<from_A_to_C>from_A_to_C}|C(2)|{<from_C_to_D>from_C_to_D}}"];
118 "D" [label="{{<from_B_to_D>from_B_to_D|<from_C_to_D>from_C_to_D}|D(2)|{}}"];
119 "A":"from_A_to_B"-> "B":"from_A_to_B" [label="22000"]
120 "A":"from_A_to_C"-> "C":"from_A_to_C" [label="22001"]
121 "B":"from_B_to_D"-> "D":"from_B_to_D" [label="22002"]
122 "C":"from_C_to_D"-> "D":"from_C_to_D" [label="22003"]
123}
124)EXPECTED");
125}
126
127TEST_CASE("TestGraphvizWithPipeline")
128{
129 auto workflow = defineDataProcessing2();
130 std::ostringstream str;
131 auto expectedResult = R"EXPECTED(digraph structs {
132 node[shape=record]
133 "A" [label="A"];
134 "B" [label="B"];
135 "C" [label="C"];
136}
137)EXPECTED";
139 lineByLineComparision(str.str(), expectedResult);
140 std::vector<DeviceSpec> devices;
141 for (auto& device : devices) {
142 REQUIRE(device.id != "");
143 }
144 auto configContext = makeEmptyConfigContext();
145 auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext);
146 auto completionPolicies = CompletionPolicy::createDefaultPolicies();
147 auto callbacksPolicies = CallbacksPolicy::createDefaultPolicies();
148 std::vector<ComputingResource> resources = {ComputingResourceHelpers::getLocalhostResource()};
149 SimpleResourceManager rm(resources);
150 DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow, channelPolicies, completionPolicies, callbacksPolicies, devices, rm, "workflow-id", *configContext);
151 str.str("");
153 lineByLineComparision(str.str(), R"EXPECTED(digraph structs {
154 node[shape=record]
155 "A" [label="{{}|A(3)|{<from_A_to_B_t0>from_A_to_B_t0|<from_A_to_B_t1>from_A_to_B_t1|<from_A_to_B_t2>from_A_to_B_t2}}"];
156 "B_t0" [label="{{<from_A_to_B_t0>from_A_to_B_t0}|B_t0(3)|{<from_B_t0_to_C_t0>from_B_t0_to_C_t0|<from_B_t0_to_C_t1>from_B_t0_to_C_t1}}"];
157 "B_t1" [label="{{<from_A_to_B_t1>from_A_to_B_t1}|B_t1(3)|{<from_B_t1_to_C_t0>from_B_t1_to_C_t0|<from_B_t1_to_C_t1>from_B_t1_to_C_t1}}"];
158 "B_t2" [label="{{<from_A_to_B_t2>from_A_to_B_t2}|B_t2(3)|{<from_B_t2_to_C_t0>from_B_t2_to_C_t0|<from_B_t2_to_C_t1>from_B_t2_to_C_t1}}"];
159 "C_t0" [label="{{<from_B_t0_to_C_t0>from_B_t0_to_C_t0|<from_B_t1_to_C_t0>from_B_t1_to_C_t0|<from_B_t2_to_C_t0>from_B_t2_to_C_t0}|C_t0(3)|{}}"];
160 "C_t1" [label="{{<from_B_t0_to_C_t1>from_B_t0_to_C_t1|<from_B_t1_to_C_t1>from_B_t1_to_C_t1|<from_B_t2_to_C_t1>from_B_t2_to_C_t1}|C_t1(3)|{}}"];
161 "A":"from_A_to_B_t0"-> "B_t0":"from_A_to_B_t0" [label="22000"]
162 "A":"from_A_to_B_t1"-> "B_t1":"from_A_to_B_t1" [label="22001"]
163 "A":"from_A_to_B_t2"-> "B_t2":"from_A_to_B_t2" [label="22002"]
164 "B_t0":"from_B_t0_to_C_t0"-> "C_t0":"from_B_t0_to_C_t0" [label="22003"]
165 "B_t1":"from_B_t1_to_C_t0"-> "C_t0":"from_B_t1_to_C_t0" [label="22005"]
166 "B_t2":"from_B_t2_to_C_t0"-> "C_t0":"from_B_t2_to_C_t0" [label="22007"]
167 "B_t0":"from_B_t0_to_C_t1"-> "C_t1":"from_B_t0_to_C_t1" [label="22004"]
168 "B_t1":"from_B_t1_to_C_t1"-> "C_t1":"from_B_t1_to_C_t1" [label="22006"]
169 "B_t2":"from_B_t2_to_C_t1"-> "C_t1":"from_B_t2_to_C_t1" [label="22008"]
170}
171)EXPECTED");
172}
WorkflowSpec defineDataProcessing(ConfigContext const &configcontext)
std::unique_ptr< ConfigContext > makeEmptyConfigContext()
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
TEST_CASE("test_prepareArguments")
std::vector< DataProcessorSpec > WorkflowSpec
DataProcessorSpec timePipeline(DataProcessorSpec original, size_t count)
std::vector< InputSpec > Inputs
std::vector< OutputSpec > Outputs
static std::vector< CallbacksPolicy > createDefaultPolicies()
static std::vector< ChannelConfigurationPolicy > createDefaultPolicies(ConfigContext const &configContext)
Default policies to use, based on the contents of the @configContex content.
static std::vector< CompletionPolicy > createDefaultPolicies()
Helper to create the default configuration.
static void dataProcessorSpecs2DeviceSpecs(const WorkflowSpec &workflow, std::vector< ChannelConfigurationPolicy > const &channelPolicies, std::vector< CompletionPolicy > const &completionPolicies, std::vector< DispatchPolicy > const &dispatchPolicies, std::vector< ResourcePolicy > const &resourcePolicies, std::vector< CallbacksPolicy > const &callbacksPolicies, std::vector< SendingPolicy > const &sendingPolicy, std::vector< ForwardingPolicy > const &forwardingPolicies, std::vector< DeviceSpec > &devices, ResourceManager &resourceManager, std::string const &uniqueWorkflowId, ConfigContext const &configContext, bool optimizeTopology=false, unsigned short resourcesMonitoringInterval=0, std::string const &channelPrefix="", OverrideServiceSpecs const &overrideServices={})
static void dumpDeviceSpec2Graphviz(std::ostream &, const Devices &specs)
Helper to dump a set of devices as a graphviz file.
static void dumpDataProcessorSpec2Graphviz(std::ostream &, const WorkflowSpec &specs, std::vector< std::pair< int, int > > const &edges={})
Helper to dump a workflow as a graphviz file.
void lineByLineComparision(const std::string &as, const std::string &bs)
WorkflowSpec defineDataProcessing2()
const std::string str