0

I'm trying to modify this example from https://software.intel.com/content/www/us/en/develop/blogs/a-feature-detection-example-using-the-intel-threading-building-blocks-flow-graph.html

The idea is I have a "preprocess" function that is applied to each input, and a "process" function that is applied to every pair of preprocessed inputs, scanning the stream. In my example we simply end up calculating the differences between successive square numbers.

My example below does not work. I believe it's because the buffer is empty at the start. In the blog example they fill the buffer at some point. Calling buffer.try_put(0) does not seem to solve it for me. What am I missing? And what is a better way to allow the process to work naturally, simply ignoring the first elements that cannot be fully processed because the buffer is empty?

#include <cstring>
#include <iostream>

#include "tbb/flow_graph.h"

using namespace tbb;
using namespace tbb::flow;

const int N = 13;


template<typename T>
class source_body {

    unsigned my_count;
    int *ninvocations;

public:

    source_body() : ninvocations(NULL) { my_count = 0; }

    source_body(int &_inv) : ninvocations(&_inv) { my_count = 0; }

    bool operator()(T &v) {
        v = (T) my_count++;
        if (ninvocations) ++(*ninvocations);
        if ((int) v < N)
            return true;
        else
            return false;
    }

};

int main() {
    graph g;

    typedef std::tuple<int32_t, int32_t> resource_tuple;

    queue_node<int> buffer(g);
    join_node<resource_tuple, reserving> resource_join(g);

    tbb::flow::source_node<int> src3(g, source_body<int>());
    src3.activate();

    function_node<int, int>
            preprocess_function(g, unlimited,
                                [](const int &a) -> int {

                                    return a * a;
                                }
    );

    make_edge(src3, preprocess_function);

    make_edge(preprocess_function, input_port<1>(resource_join));
    make_edge(preprocess_function, buffer);
    make_edge(buffer, input_port<0>(resource_join));

    function_node<resource_tuple, int>
            process_function(g, unlimited,
                             [](const resource_tuple &a) -> int {
                                 return std::get<1>(a) - std::get<0>(a);
                             }
    );
    make_edge(resource_join, process_function);


    function_node<int> printint(g, serial,
                               [](const int &t) -> void {
                                   std::cout << t << '\n';
                               }
    );
    make_edge(process_function, printint);

    buffer.try_put(0);
    g.wait_for_all();

    return 0;
}
dividebyzero
  • 2,190
  • 1
  • 21
  • 33

1 Answers1

0

The following code works. Replacing reserving by queueing did the trick. Not really ignoring the first element that cannot be processed, though. Still curious to hear what would be the best approach to implement this kind of "scanning" in a TBB graph.

#include <cstring>
#include <iostream>

#include "tbb/flow_graph.h"

using namespace tbb;
using namespace tbb::flow;

const int N = 13;


template<typename T>
class source_body {

    unsigned my_count;
    int *ninvocations;

public:

    source_body() : ninvocations(NULL) { my_count = 0; }

    source_body(int &_inv) : ninvocations(&_inv) { my_count = 0; }

    bool operator()(T &v) {
        v = (T) my_count++;
        if (ninvocations) ++(*ninvocations);
        if ((int) v < N)
            return true;
        else
            return false;
    }

};

int main() {
    graph g;

    typedef std::tuple<int32_t, int32_t> resource_tuple;

    queue_node<int> buffer(g);
    join_node<resource_tuple, queueing> resource_join(g);

    tbb::flow::source_node<int> src3(g, source_body<int>());
    src3.activate();

    function_node<int, int>
            preprocess_function(g, unlimited,
                                [](const int &a) -> int {

                                    return a * a;
                                }
    );

    make_edge(src3, preprocess_function);

    make_edge(preprocess_function, input_port<1>(resource_join));
    make_edge(preprocess_function, buffer);
    make_edge(buffer, input_port<0>(resource_join));

    function_node<resource_tuple, int>
            process_function(g, unlimited,
                             [](const resource_tuple &a) -> int {
                                 return std::get<1>(a) - std::get<0>(a);
                             }
    );
    make_edge(resource_join, process_function);

    function_node<int> printint(g, serial,
                                [](const int &t) -> void {
                                    std::cout << t << '\n';
                                }
    );

    make_edge(process_function, printint);

    buffer.try_put(0);
    g.wait_for_all();

    return 0;
}
dividebyzero
  • 2,190
  • 1
  • 21
  • 33