Skip to content

Instantly share code, notes, and snippets.

@daniel-j-h
Created April 20, 2014 16:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daniel-j-h/11118878 to your computer and use it in GitHub Desktop.
Save daniel-j-h/11118878 to your computer and use it in GitHub Desktop.
C++ Intel Threading Building Blocks palindrome example, showing reduction vs. combinable -- note: memory bound
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <fstream>
#include <functional>
#include "tbb/task_scheduler_init.h"
#include "tbb/blocked_range.h"
#include "tbb/parallel_for.h"
#include "tbb/parallel_reduce.h"
#include "tbb/tick_count.h"
#include "tbb/combinable.h"
#include <boost/range/algorithm/count_if.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/case_conv.hpp>
// clang++ -std=c++11 -O2 -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-prototypes -ltbb main.cc
// g++ -std=c++11 -O2 -Wall -Werror -pedantic -Wno-missing-prototype -ltbb main.cc
// ./a.out /usr/share/dict/words
using line_t = std::string;
using lines_t = std::vector<line_t>;
using range_t = tbb::blocked_range<lines_t::iterator>;
bool is_palindrome(const line_t &line)
{
return std::equal(line.begin(), line.begin() + line.size() / 2, line.rbegin());
}
void n_palindromes_reduction(range_t &lines_r)
{
std::size_t identity{0};
auto reducer = [](const range_t &range, std::size_t acc) {
return acc + boost::count_if(range, is_palindrome); // XXX: implicit conversion changes signedness
};
auto combiner = std::plus<std::size_t>{};
auto t0 = tbb::tick_count::now();
auto n_palindromes = tbb::parallel_reduce(lines_r, identity, reducer, combiner);
auto t1 = tbb::tick_count::now();
std::cout << "reduction, elapsed " << (t1 - t0).seconds() << "s: " << n_palindromes << std::endl;
}
void n_palindromes_combinable(range_t &lines_r)
{
tbb::combinable<std::size_t> n_palindromes;
auto t0 = tbb::tick_count::now();
tbb::parallel_for(lines_r, [&n_palindromes](range_t &range) {
for (const auto &line : range) {
if (is_palindrome(line))
++n_palindromes.local();
}
});
auto n_palindromes_combined = n_palindromes.combine(std::plus<std::size_t>{});
auto t1 = tbb::tick_count::now();
std::cout << "combinable, elapsed " << (t1 - t0).seconds() << "s: " << n_palindromes_combined << std::endl;
}
void cleanup_lines(range_t &lines_r)
{
tbb::parallel_for(lines_r, [](range_t &range) {
for (auto &line : range) {
boost::trim(line);
boost::to_lower(line);
}
});
}
int main(int argc, char **argv)
{
lines_t args{argv, argv + argc};
if (args.size() != 2) return -1;
std::ifstream in{args.at(1)};
if (!in) return -1;
lines_t lines{
std::istream_iterator<line_t>{in},
std::istream_iterator<line_t>{}
};
range_t lines_r{
std::begin(lines),
std::end(lines)
};
tbb::task_scheduler_init sentry;
cleanup_lines(lines_r);
n_palindromes_reduction(lines_r);
n_palindromes_combinable(lines_r);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment