Alexandria  2.25.0
SDC-CH common library for the Euclid project
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Example.cpp
Go to the documentation of this file.
1 
21 #include <fstream>
22 #include <map>
23 #include <string>
24 
25 #include "Pyston/Exceptions.h"
27 #include "Pyston/GIL.h"
28 #include "Pyston/Graph/Functors.h"
30 #include "Pyston/Module.h"
34 #include <boost/program_options.hpp>
35 #include <boost/python.hpp>
36 #include <boost/thread.hpp>
37 #include <boost/timer/timer.hpp>
38 
39 using namespace Pyston;
40 namespace po = boost::program_options;
41 namespace fs = boost::filesystem;
42 namespace py = boost::python;
43 
47 double world2pix(double x) {
48  return std::log10(x) * std::sin(x / 2);
49 }
50 
51 template <typename T>
53 
56 
60 class Example : public Elements::Program {
61 
62 private:
63  int m_threads, m_repeats;
64  fs::path m_dot_file;
65 
66 public:
67  po::options_description defineSpecificProgramOptions() override {
68  po::options_description options{"Pyston example options"};
69  options.add_options()("no-threads", po::value<int>()->default_value(1), "Number of threads")(
70  "repeats", po::value<int>()->default_value(50000), "Number of iterations inside the timing block")(
71  "file", po::value<std::string>()->default_value("example.py"), "Python file to run")(
72  "dot-file", po::value<std::string>(), "Generate a graphviz dot file with the computing graph (prefix)");
73 
74  return options;
75  }
76 
77  void generateGraphviz(Node<double>& node, int nparams) {
78  if (m_dot_file.empty())
79  return;
80 
81  auto full_name = m_dot_file.native() + "." + std::to_string(nparams);
82 
83  logger.info() << "Generating " << full_name;
84 
85  std::ofstream out(full_name.c_str());
86  GraphvizGenerator generator(std::to_string(nparams));
87  node.visit(generator);
88  out << generator.str();
89  }
90 
96 
97  GILLocker locker;
98 
99  py::object pyston = py::import("pyston");
100  py::dict evaluate = py::extract<py::dict>(pyston.attr("evaluate"));
101  py::list keys = evaluate.keys();
102 
103  for (int i = 0; i < py::len(keys); ++i) {
104  int nparams = py::extract<int>(keys[i]);
105  logger.info() << "Found callable with " << nparams << " parameters";
106 
107  try {
108  // Setup placeholders
109  py::list placeholders;
110  for (int arg = 0; arg < nparams; ++arg) {
111  auto placeholder = std::make_shared<Placeholder<double>>(arg);
112  placeholders.append(placeholder);
113  }
114 
115  // Get the function
116  py::object func = evaluate[nparams];
117 
118  // Trigger a build of the tree calling with the placeholders
119  py::object comp_tree = func(*py::tuple(placeholders));
120  std::shared_ptr<Node<double>> node = py::extract<std::shared_ptr<Node<double>>>(comp_tree);
121 
122  // Generate graphviz if needed
123  generateGraphviz(*node, nparams);
124 
125  // Store
126  calls[nparams] = std::make_pair(func, node);
127  } catch (const py::error_already_set&) {
128  throw Exception();
129  }
130  }
131 
132  return calls;
133  }
134 
137  for (int i = 0; i < n; ++i) {
138  double value = ::drand48() * 100;
139  result.first.push_back(value);
140  result.second.emplace_back(value);
141  }
142  return result;
143  }
144 
145  void runPython(boost::python::object func, const std::vector<double>& args) {
146  for (int j = 0; j < m_repeats; ++j) {
147  GILLocker locker;
148  func(*py::tuple(args));
149  }
150  }
151 
152  void runCpp(const std::shared_ptr<Node<double>>& node, const Arguments& args) {
153  for (int j = 0; j < m_repeats; ++j) {
154  node->eval(args);
155  }
156  }
157 
159  std::vector<double> measures;
160 
161  for (int nthreads = 1; nthreads <= m_threads; ++nthreads) {
162  boost::thread_group thread_group;
163  boost::timer::cpu_timer timer;
164  for (int n = 0; n < nthreads; ++n) {
165  thread_group.create_thread(func);
166  }
167  thread_group.join_all();
168  timer.stop();
169 
170  auto calls_per_ns = (nthreads * m_repeats) / static_cast<double>(timer.elapsed().wall);
171  auto calls_per_sec = calls_per_ns * 1e9;
172  measures.emplace_back(calls_per_sec);
173  }
174 
175  return measures;
176  }
177 
178  void evalExamples() {
179  auto callables = getFunctions();
180 
181  std::cout << "Method,Arguments,";
182  for (int nthread = 1; nthread <= m_threads; ++nthread) {
183  std::cout << nthread << ",";
184  }
185  std::cout << std::endl;
186 
187  for (auto& pair : callables) {
188  logger.info() << "Timing calls with " << pair.first << " parameters";
189 
190  auto params = createParameters(pair.first);
191  auto pyFunc = boost::bind(&Example::runPython, this, pair.second.first, params.first);
192  auto cppFunc = boost::bind(&Example::runCpp, this, pair.second.second, params.second);
193 
194  // Python
195  auto measurements = measure(pyFunc);
196  std::cout << "Python," << pair.first << ",";
197  for (int nthread = 1; nthread <= m_threads; ++nthread) {
198  std::cout << std::fixed << std::setw(15) << std::setprecision(2) << measurements[nthread - 1] << ",";
199  }
200  std::cout << std::endl;
201 
202  // Pyston
203  measurements = measure(cppFunc);
204  std::cout << "Pyston," << pair.first << ",";
205  for (int nthread = 1; nthread <= m_threads; ++nthread) {
206  std::cout << std::fixed << std::setw(15) << std::setprecision(2) << measurements[nthread - 1] << ",";
207  }
208  std::cout << std::endl;
209  }
210  }
211 
213  // Options
214  m_threads = args.at("no-threads").as<int>();
215  m_repeats = args.at("repeats").as<int>();
216  if (args.count("dot-file"))
217  m_dot_file = args.at("dot-file").as<std::string>();
218 
219  // Initialize python
220  PyImport_AppendInittab("pyston", PYSTON_MODULE_INIT);
221  Py_Initialize();
222 #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION <= 6
223  PyEval_InitThreads();
224 #endif
225  PyEval_SaveThread();
226 
227  fs::path pyfile = args.at("file").as<std::string>();
228  if (!fs::exists(pyfile)) {
229  pyfile = Elements::getAuxiliaryPath(pyfile);
230  }
231 
232  try {
233  {
234  GILLocker locker;
235  auto main_module = boost::python::import("__main__");
236  auto main_namespace = main_module.attr("__dict__");
237 
238  ExpressionTreeBuilder builder;
239  builder.registerFunction<double(double)>("world2pix", World2Pix<double>());
240 
241  py::exec_file(pyfile.native().c_str(), main_namespace);
242  }
243 
244  // Evaluate calls
245  evalExamples();
246  } catch (const py::error_already_set&) {
247  throw Exception();
248  }
249 
250  return Elements::ExitCode::OK;
251  }
252 };
253 
void generateGraphviz(Node< double > &node, int nparams)
Definition: Example.cpp:77
double world2pix(double x)
Definition: Example.cpp:47
void evalExamples()
Definition: Example.cpp:178
int m_threads
Definition: Example.cpp:63
T to_string(T...args)
T endl(T...args)
void runCpp(const std::shared_ptr< Node< double >> &node, const Arguments &args)
Definition: Example.cpp:152
void info(const std::string &logMessage)
fs::path m_dot_file
Definition: Example.cpp:64
std::pair< std::vector< double >, Arguments > createParameters(int n)
Definition: Example.cpp:135
T log10(T...args)
STL class.
T setw(T...args)
STL class.
std::map< int, std::pair< py::object, std::shared_ptr< Node< double > > > > getFunctions()
Definition: Example.cpp:94
T sin(T...args)
T at(T...args)
STL class.
#define MAIN_FOR(ELEMENTS_PROGRAM_NAME)
void runPython(boost::python::object func, const std::vector< double > &args)
Definition: Example.cpp:145
static Elements::Logging logger
Logger.
Definition: Example.cpp:55
std::vector< double > measure(std::function< void(void)> func)
Definition: Example.cpp:158
T make_pair(T...args)
T count(T...args)
T fixed(T...args)
#define PYSTON_MODULE_INIT
Definition: Module.h:38
void registerFunction(const std::string &repr, std::function< Signature > functor)
STL class.
po::options_description defineSpecificProgramOptions() override
Definition: Example.cpp:67
T setprecision(T...args)
static Logging getLogger(const std::string &name="")
virtual void visit(Visitor &) const =0
Elements::ExitCode mainMethod(std::map< std::string, po::variable_value > &args) override
Definition: Example.cpp:212
T emplace_back(T...args)