Alexandria 2.31.0
SDC-CH common library for the Euclid project
Loading...
Searching...
No Matches
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"
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
39using namespace Pyston;
40namespace po = boost::program_options;
41namespace fs = boost::filesystem;
42namespace py = boost::python;
43
47double world2pix(double x) {
48 return std::log10(x) * std::sin(x / 2);
49}
50
51template <typename T>
53
56
60class Example : public Elements::Program {
61
62private:
64 fs::path m_dot_file;
65
66public:
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
179 auto callables = getFunctions();
180
181 std::cout << "Method,Arguments,";
182 for (int nthread = 1; nthread <= m_threads; ++nthread) {
183 std::cout << nthread << ",";
184 }
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 }
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 }
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
static Elements::Logging logger
Logger.
Definition Example.cpp:55
double world2pix(double x)
Definition Example.cpp:47
#define PYSTON_MODULE_INIT
Definition Module.h:38
T at(T... args)
static Logging getLogger(const std::string &name="")
void info(const std::string &logMessage)
void evalExamples()
Definition Example.cpp:178
std::pair< std::vector< double >, Arguments > createParameters(int n)
Definition Example.cpp:135
void runCpp(const std::shared_ptr< Node< double > > &node, const Arguments &args)
Definition Example.cpp:152
void runPython(boost::python::object func, const std::vector< double > &args)
Definition Example.cpp:145
fs::path m_dot_file
Definition Example.cpp:64
void generateGraphviz(Node< double > &node, int nparams)
Definition Example.cpp:77
int m_threads
Definition Example.cpp:63
Elements::ExitCode mainMethod(std::map< std::string, po::variable_value > &args) override
Definition Example.cpp:212
po::options_description defineSpecificProgramOptions() override
Definition Example.cpp:67
std::map< int, std::pair< py::object, std::shared_ptr< Node< double > > > > getFunctions()
Definition Example.cpp:94
std::vector< double > measure(std::function< void(void)> func)
Definition Example.cpp:158
int m_repeats
Definition Example.cpp:63
void registerFunction(const std::string &repr, std::function< Signature > functor)
virtual void visit(Visitor &) const =0
T count(T... args)
T emplace_back(T... args)
T endl(T... args)
T fixed(T... args)
#define MAIN_FOR(ELEMENTS_PROGRAM_NAME)
T log10(T... args)
T make_pair(T... args)
T setprecision(T... args)
T setw(T... args)
T sin(T... args)
T to_string(T... args)