DtCraft Examples
This page gives you a quick overview of a few DtCraft programs using our stream graph programming API.
Hello World
In this example, we create a stream graph with two vertices A and B. The two vertices send a string "Hello world"
to
each other and close the stream after receiving the string from the other.
dtc::Graph G;
auto A = G.vertex();
auto B = G.vertex();
auto lambda = [] (dtc::Vertex& v, dtc::InputStream& is) {
if(std::string s; is(s) != -1) {
std::cout << "Received: " << s << '\n';
return dtc::Event::REMOVE;
}
return dtc::Event::DEFAULT;
};
auto AB = G.stream(A, B).on(lambda);
auto BA = G.stream(B, A).on(lambda);
A.on([&AB] (dtc::Vertex& v) { (*v.ostream(AB))("hello world from A"s); });
B.on([&BA] (dtc::Vertex& v) { (*v.ostream(BA))("hello world from B"s); });
dtc::Executor(G).run();
Pi Estimation
In this example, we estimate π by using a Monte Carlo method. The stream graph contains a master vertex and three slave vertices. We create four containers each of 1 CPU for each vertex and its adjacent streams to enable parallel execution. Each slave vertex randomly generates points in a 1x1 square and reports the number of points that fall in the unit circle enclosed by the square. Then the master derives π based on the reported numbers from slaves.
struct Result{
std::atomic<int> value {0};
std::atomic<int> count {0};
Result(const Result& r) : value{r.value.load()}, count{r.count.load()} {}
};
constexpr int num_slaves = 3;
constexpr int num_samples = 3000;
dtc::Graph G;
std::vector<dtc::VertexBuilder> slaves;
std::vector<dtc::StreamBuilder> m2s, s2m;
auto master = G.vertex();
for(auto i=0; i<num_slaves; ++i) {
slaves.emplace_back(G.vertex());
m2s.emplace_back(G.stream(master, slaves.back()));
s2m.emplace_back(G.stream(slaves.back(), master));
}
master.on(
[&] (dtc::Vertex& v) {
v.any = Result();
for(auto &s: m2s){
(*v.ostream(s))(num_samples/num_slaves);
}
}
);
// Stream: master to slave
for(int i=0; i<num_slaves; ++i) {
m2s[i].on(
[other=s2m[i]] (dtc::Vertex& slave, dtc::InputStream& is) {
if(int num_samples = 0, count = 0; is(num_samples) != -1) {
for(int i = 0; i < num_samples; ++i){
auto x = dtc::random<double>(-1.,1.);
auto y = dtc::random<double>(-1.,1.);
if( x*x + y*y <= 1.0 ){
++count;
}
}
(*slave.ostream(other))(count);
return dtc::Event::REMOVE;
}
return dtc::Event::DEFAULT;
}
);
}
// Stream: slave to master
for(int i=0; i<num_slaves; ++i) {
s2m[i].on(
[&m2s, num_samples] (dtc::Vertex& master, dtc::InputStream& is) {
if(int value = 0; is(value) != -1) {
auto& result = std::any_cast<Result&>(master.any);
if(result.value += value; ++result.count == num_slaves) {
std::cout << "pi estimation : " << 4.0*result.value/num_samples << '\n';
}
return dtc::Event::REMOVE;
}
return dtc::Event::DEFAULT;
}
);
}
G.container().num_cpus(1).add(master);
G.container().num_cpus(1).add(slaves[0]);
G.container().num_cpus(1).add(slaves[1]);
G.container().num_cpus(1).add(slaves[2]);
dtc::Executor(G).run();
External Program
In this example, we demonstrate DtCraft's capability of working with external programs. This can be extremely useful for those to integrate existing applications with legacy code or so. The stream graph creates two vertices and launch two simple programs to print the root directory and gcc version.
dtc::Graph G;
dtc::Graph G;
auto A = G.vertex().program("/bin/ls / -al");
auto B = G.vertex().program("/usr/bin/gcc -v");
G.stream(A, B).tag("AB");
G.container().add(A);
G.container().add(B);
dtc::Executor(G).run();
Additional Examples
Additional examples are packaged with DtCraft source under the folderexamples/
.