• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  Copyright John Maddock 2015.
2 //  Use, modification and distribution are subject to the
3 //  Boost Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifdef _MSC_VER
7 #  pragma warning (disable : 4224)
8 #endif
9 
10 #include <boost/regex.hpp>
11 #include <boost/lexical_cast.hpp>
12 #include <boost/filesystem.hpp>
13 #include <boost/filesystem/fstream.hpp>
14 #include <boost/interprocess/sync/named_mutex.hpp>
15 #include <boost/interprocess/sync/scoped_lock.hpp>
16 #include <vector>
17 #include <set>
18 #include <iostream>
19 #include <sstream>
20 #include <iomanip>
21 #include "table_helper.hpp"
22 
23 void add_cell(boost::intmax_t val, const std::string& table_name, const std::string& row_name, const std::string& column_heading);
24 void add_to_all_sections(const std::string& id, std::string list_name = "performance_all_sections");
25 
26 std::vector<std::vector<double> > data;
27 std::vector<std::tuple<double, std::string, std::string, std::string> > items_to_add;
28 
sanitize_string(const std::string & s)29 inline std::string sanitize_string(const std::string& s)
30 {
31    static const boost::regex e("[^a-zA-Z0-9]+");
32    std::string result = boost::regex_replace(s, e, "_");
33    while(result[0] == '_')
34       result.erase(0);
35    return result;
36 }
37 
format_precision(double val,int digits)38 std::string format_precision(double val, int digits)
39 {
40    std::stringstream ss;
41    ss << std::setprecision(digits);
42    ss << std::fixed;
43    ss << val;
44    return ss.str();
45 }
46 
47 static std::string content;
48 boost::filesystem::path path_to_content;
49 
50 struct content_loader
51 {
content_loadercontent_loader52    content_loader(){}
~content_loadercontent_loader53    ~content_loader()
54    {
55       boost::interprocess::named_mutex mu(boost::interprocess::open_or_create, "handle_test_result");
56       boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(mu);
57       boost::filesystem::path p(__FILE__);
58       p = p.parent_path();
59       p /= "doc";
60       p /= "performance_tables.qbk";
61       path_to_content = p;
62       if(boost::filesystem::exists(p))
63       {
64          boost::filesystem::ifstream is(p);
65          if(is.good())
66          {
67             do
68             {
69                char c = static_cast<char>(is.get());
70                if(c != EOF)
71                   content.append(1, c);
72             } while(is.good());
73          }
74       }
75       //
76       // Now iterate through results and add them one at a time:
77       //
78       for(auto i = items_to_add.begin(); i != items_to_add.end(); ++i)
79       {
80          add_cell(static_cast<boost::uintmax_t>(std::get<0>(*i) / 1e-9), std::get<1>(*i), std::get<2>(*i), std::get<3>(*i));
81       }
82       //
83       // Write out the results:
84       //
85       boost::filesystem::ofstream os(path_to_content);
86       os << content;
87    }
instantiatecontent_loader88    void instantiate()const
89    {
90    }
91 };
92 
93 static const content_loader loader;
94 
load_table(std::vector<std::vector<std::string>> & table,std::string::const_iterator begin,std::string::const_iterator end)95 void load_table(std::vector<std::vector<std::string> >& table, std::string::const_iterator begin, std::string::const_iterator end)
96 {
97    static const boost::regex item_e(
98       "\\["
99       "([^\\[\\]]*(?0)?)*"
100       "\\]"
101       );
102 
103    boost::regex_token_iterator<std::string::const_iterator> i(begin, end, item_e), j;
104 
105    while(i != j)
106    {
107       // Add a row:
108       table.push_back(std::vector<std::string>());
109       boost::regex_token_iterator<std::string::const_iterator> k(i->first + 1, i->second - 1, item_e);
110       while(k != j)
111       {
112          // Add a cell:
113          table.back().push_back(std::string(k->first + 1, k->second - 1));
114          ++k;
115       }
116       ++i;
117    }
118 }
119 
save_table(std::vector<std::vector<std::string>> & table)120 std::string save_table(std::vector<std::vector<std::string> >& table)
121 {
122    std::string result;
123 
124    for(std::vector<std::vector<std::string> >::const_iterator i = table.begin(), j = table.end(); i != j; ++i)
125    {
126       result += "[";
127       for(std::vector<std::string>::const_iterator k = i->begin(), l = i->end(); k != l; ++k)
128       {
129          result += "[";
130          result += *k;
131          result += "]";
132       }
133       result += "]\n";
134    }
135    return result;
136 }
137 
add_to_all_sections(const std::string & id,std::string list_name)138 void add_to_all_sections(const std::string& id, std::string list_name)
139 {
140    std::string::size_type pos = content.find("[template " + list_name + "[]"), end_pos;
141    if(pos == std::string::npos)
142    {
143       //
144       // Just append to the end:
145       //
146       content.append("\n[template ").append(list_name).append("[]\n[").append(id).append("]\n]\n");
147    }
148    else
149    {
150       //
151       // Read in the all list of sections, add our new one (in alphabetical order),
152       // and then rewrite the whole thing:
153       //
154       static const boost::regex item_e(
155          "\\["
156          "((?=[^\\]])[^\\[\\]]*+(?0)?+)*+"
157          "\\]|\\]"
158          );
159       boost::regex_token_iterator<std::string::const_iterator> i(content.begin() + pos + 12 + list_name.size(), content.end(), item_e), j;
160       std::set<std::string> sections;
161       while(i != j)
162       {
163          if(i->length() == 1)
164          {
165             end_pos = i->first - content.begin();
166             break;
167          }
168          sections.insert(std::string(i->first + 1, i->second - 1));
169          ++i;
170       }
171       sections.insert(id);
172       std::string new_list = "\n";
173       for(std::set<std::string>::const_iterator sec = sections.begin(); sec != sections.end(); ++sec)
174       {
175          new_list += "[" + *sec + "]\n";
176       }
177       content.replace(pos + 12 + list_name.size(), end_pos - pos - 12 - list_name.size(), new_list);
178    }
179 }
180 
get_colour(boost::uintmax_t val,boost::uintmax_t best)181 std::string get_colour(boost::uintmax_t val, boost::uintmax_t best)
182 {
183    if(val <= best * 1.2)
184       return "green";
185    if(val > best * 2)
186       return "red";
187    return "blue";
188 }
189 
get_value_from_cell(const std::string & cell)190 boost::intmax_t get_value_from_cell(const std::string& cell)
191 {
192    static const boost::regex time_e("(\\d+)ns");
193    boost::smatch what;
194    if(regex_search(cell, what, time_e))
195    {
196       return boost::lexical_cast<boost::uintmax_t>(what.str(1));
197    }
198    return -1;
199 }
200 
add_cell(boost::intmax_t val,const std::string & table_name,const std::string & row_name,const std::string & column_heading)201 void add_cell(boost::intmax_t val, const std::string& table_name, const std::string& row_name, const std::string& column_heading)
202 {
203    //
204    // Load the table, add our data, and re-write:
205    //
206    std::string table_id = "table_" + sanitize_string(table_name);
207    boost::regex table_e("\\[table:" + table_id
208       + "\\s[^\\[]++"
209       "((\\["
210       "([^\\[\\]]*+(?2)?+)*+"
211       "\\]\\s*+)*+\\s*+)"
212       "\\]"
213       );
214 
215    boost::smatch table_location;
216    if(regex_search(content, table_location, table_e))
217    {
218       std::vector<std::vector<std::string> > table_data;
219       load_table(table_data, table_location[1].first, table_location[1].second);
220       //
221       // Figure out which column we're on:
222       //
223       unsigned column_id = 1001u;
224       for(unsigned i = 0; i < table_data[0].size(); ++i)
225       {
226          if(table_data[0][i] == column_heading)
227          {
228             column_id = i;
229             break;
230          }
231       }
232       if(column_id > 1000)
233       {
234          //
235          // Need a new column, must be adding a new compiler to the table!
236          //
237          table_data[0].push_back(column_heading);
238          for(unsigned i = 1; i < table_data.size(); ++i)
239             table_data[i].push_back(std::string());
240          column_id = table_data[0].size() - 1;
241       }
242       //
243       // Figure out the row:
244       //
245       unsigned row_id = 1001;
246       for(unsigned i = 1; i < table_data.size(); ++i)
247       {
248          if(table_data[i][0] == row_name)
249          {
250             row_id = i;
251             break;
252          }
253       }
254       if(row_id > 1000)
255       {
256          //
257          // Need a new row, add it now:
258          //
259          table_data.push_back(std::vector<std::string>());
260          table_data.back().push_back(row_name);
261          for(unsigned i = 1; i < table_data[0].size(); ++i)
262             table_data.back().push_back(std::string());
263          row_id = table_data.size() - 1;
264       }
265       //
266       // Find the best result in this row:
267       //
268       boost::uintmax_t best = (std::numeric_limits<boost::uintmax_t>::max)();
269       std::vector<boost::intmax_t> values;
270       for(unsigned i = 1; i < table_data[row_id].size(); ++i)
271       {
272          if(i == column_id)
273          {
274             if(val < best)
275                best = val;
276             values.push_back(val);
277          }
278          else
279          {
280             std::cout << "Existing cell value was " << table_data[row_id][i] << std::endl;
281             boost::uintmax_t cell_val = get_value_from_cell(table_data[row_id][i]);
282             std::cout << "Extracted value: " << cell_val << std::endl;
283             if(cell_val < best)
284                best = cell_val;
285             values.push_back(cell_val);
286          }
287       }
288       //
289       // Update the row:
290       //
291       for(unsigned i = 1; i < table_data[row_id].size(); ++i)
292       {
293          std::string& s = table_data[row_id][i];
294          s = "[role ";
295          if(values[i - 1] < 0)
296          {
297             s += "grey -]";
298          }
299          else
300          {
301             s += get_colour(values[i - 1], best);
302             s += " ";
303             s += format_precision(static_cast<double>(values[i - 1]) / best, 2);
304             s += "[br](";
305             s += boost::lexical_cast<std::string>(values[i - 1]) + "ns)]";
306          }
307       }
308       //
309       // Convert back to a string and insert into content:
310       std::sort(table_data.begin() + 1, table_data.end(), [](std::vector<std::string> const& a, std::vector<std::string> const& b) { return a[0] < b[0]; } );
311       std::string c = save_table(table_data);
312       content.replace(table_location.position(1), table_location.length(1), c);
313    }
314    else
315    {
316       //
317       // Create a new table and try again:
318       //
319       std::string new_table = "\n[template " + table_id;
320       new_table += "[]\n[table:" + table_id;
321       new_table += " ";
322       new_table += table_name;
323       new_table += "\n[[Function][";
324       new_table += column_heading;
325       new_table += "]]\n";
326       new_table += "[[";
327       new_table += row_name;
328       new_table += "][[role blue 1.00[br](";
329       new_table += boost::lexical_cast<std::string>(val);
330       new_table += "ns)]]]\n]\n]\n";
331 
332       std::string::size_type pos = content.find("[/tables:]");
333       if(pos != std::string::npos)
334          content.insert(pos + 10, new_table);
335       else
336          content += "\n\n[/tables:]\n" + new_table;
337       //
338       // Add a section for this table as well:
339       //
340       std::string section_id = "section_" + sanitize_string(table_name);
341       if(content.find(section_id + "[]") == std::string::npos)
342       {
343          std::string new_section = "\n[template " + section_id + "[]\n[section:" + section_id + " " + table_name + "]\n[" + table_id + "]\n[endsect]\n]\n";
344          pos = content.find("[/sections:]");
345          if(pos != std::string::npos)
346             content.insert(pos + 12, new_section);
347          else
348             content += "\n\n[/sections:]\n" + new_section;
349          add_to_all_sections(section_id);
350       }
351       //
352       // Add to list of all tables (not in sections):
353       //
354       add_to_all_sections(table_id, "performance_all_tables");
355    }
356 }
357 
report_execution_time(double t,std::string table,std::string row,std::string heading)358 void report_execution_time(double t, std::string table, std::string row, std::string heading)
359 {
360    items_to_add.push_back(std::make_tuple(t, table, row, heading));
361    //add_cell(static_cast<boost::uintmax_t>(t / 1e-9), table, row, heading);
362 }
363 
get_compiler_options_name()364 std::string get_compiler_options_name()
365 {
366 #if defined(BOOST_MSVC) || defined(__ICL)
367    std::string result;
368 #ifdef BOOST_MSVC
369    result = "cl ";
370 #else
371    result = "icl ";
372 #endif
373 #ifdef _M_AMD64
374 #ifdef __AVX__
375    result += "/arch:AVX /Ox";
376 #else
377    result += "/Ox";
378 #endif
379    result += " (x64 build)";
380 #else
381 #ifdef _DEBUG
382    result +=  "/Od";
383 #elif defined(__AVX2__)
384    result += "/arch:AVX2 /Ox";
385 #elif defined(__AVX__)
386    result += "/arch:AVX /Ox";
387 #elif _M_IX86_FP == 2
388    result += "/arch:sse2 /Ox";
389 #else
390    result += "/arch:ia32 /Ox";
391 #endif
392    result += " (x86 build)";
393 #endif
394    std::cout << "Compiler options are found as: " << result << std::endl;
395    return result;
396 #else
397    return "Unknown";
398 #endif
399 }
400 
401