Skip to content

Instantly share code, notes, and snippets.

@anutosh491
Created November 15, 2024 07:32
Show Gist options
  • Select an option

  • Save anutosh491/8ef8fddac545acfad05039164679ecf4 to your computer and use it in GitHub Desktop.

Select an option

Save anutosh491/8ef8fddac545acfad05039164679ecf4 to your computer and use it in GitHub Desktop.
For supporting %%timeit for xeus-cpp
execution.hpp
/************************************************************************************
* Copyright (c) 2023, xeus-cpp contributors *
* Copyright (c) 2023, Johan Mabille, Loic Gouarin, Sylvain Corlay, Wolf Vollprecht *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
************************************************************************************/
#ifndef XMAGICS_EXECUTION_HPP
#define XMAGICS_EXECUTION_HPP
#include <cstddef>
#include <string>
#include "xeus-cpp/xmagics.hpp"
#include "xeus-cpp/xoptions.hpp"
namespace xcpp
{
class timeit : public xmagic_line_cell
{
public:
timeit();
virtual void operator()(const std::string& line) override
{
std::string cline = line;
std::string cell = "";
execute(cline, cell);
}
virtual void operator()(const std::string& line, const std::string& cell) override
{
std::string cline = line;
std::string ccell = cell;
execute(cline, ccell);
}
private:
void get_options(argparser &argpars);
std::string inner(std::size_t number, const std::string& code) const;
std::string _format_time(double timespan, std::size_t precision) const;
void execute(std::string& line, std::string& cell);
};
}
#endif
execution.cpp
/************************************************************************************
* Copyright (c) 2023, xeus-cpp contributors *
* Copyright (c) 2023, Johan Mabille, Loic Gouarin, Sylvain Corlay, Wolf Vollprecht *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
************************************************************************************/
#include <cstddef>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "clang/Interpreter/CppInterOp.h"
#include "execution.hpp"
#include "../xparser.hpp"
namespace xcpp
{
timeit::timeit()
{
bool compilation_result = false;
std::string chrono = "#include <chrono>";
compilation_result = Cpp::Process(chrono.c_str());
std::string init_timeit = "auto _t0 = std::chrono::high_resolution_clock::now();\n";
init_timeit += "auto _t1 = std::chrono::high_resolution_clock::now();\n";
compilation_result = Cpp::Process(init_timeit.c_str());
}
void timeit::get_options(argparser &argpars)
{
argpars.add_description("Time execution of a C++ statement or expression");
argpars.add_argument("-n", "--number")
.help("execute the given statement n times in a loop. If this value is not given, a fitting value is chosen")
.default_value(0)
.scan<'i', int>();
argpars.add_argument("-r", "--repeat")
.help("repeat the loop iteration r times and take the best result")
.default_value(7)
.scan<'i', int>();
argpars.add_argument("-p", "--precision")
.help("use a precision of p digits to display the timing result")
.default_value(3)
.scan<'i', int>();
argpars.add_argument("expression")
.help("expression to be evaluated")
.remaining();
// Add custom help (does not call `exit` avoiding to restart the kernel)
argpars.add_argument("-h", "--help")
.action([&](const std::string & /*unused*/)
{
std::cout << argpars.help().str();
})
.default_value(false)
.help("shows help message")
.implicit_value(true)
.nargs(0);
}
std::string timeit::inner(std::size_t number, const std::string& code) const
{
std::string timeit_code = "";
timeit_code += "_t0 = std::chrono::high_resolution_clock::now();\n";
timeit_code += "for (std::size_t _i = 0; _i < " + std::to_string(number) + "; ++_i) {\n";
timeit_code += " " + code + "\n";
timeit_code += "}\n";
timeit_code += "_t1 = std::chrono::high_resolution_clock::now();\n";
timeit_code += "std::chrono::duration<double>(_t1-_t0).count();";
return timeit_code;
}
std::string timeit::_format_time(double timespan, std::size_t precision) const
{
std::vector<std::string> units{"s", "ms", "us", "ns"};
std::vector<double> scaling{1, 1e3, 1e6, 1e9};
std::ostringstream output;
int order;
if (timespan > 0.0)
{
order = std::min(-static_cast<int>(std::floor(std::floor(std::log10(timespan)) / 3)), 3);
}
else
{
order = 3;
}
output.precision(precision);
output << timespan * scaling[order] << " " << units[order];
return output.str();
}
void timeit::execute(std::string& line, std::string& cell)
{
// std::istringstream iss(line);
// std::vector<std::string> results((std::istream_iterator<std::string>(iss)),
// std::istream_iterator<std::string>());
argparser argpars("timeit", XEUS_CPP_VERSION, argparse::default_arguments::none);
get_options(argpars);
argpars.parse(line);
// TODO find a way to use std::size_t
int number = argpars.get<int>("-n");
int repeat = argpars.get<int>("-r");
int precision = argpars.get<int>("-p");
std::string code;
try
{
const auto& v = argpars.get<std::vector<std::string>>("expression");
for (const auto& s : v)
{
code += " " + s;
}
}
catch (std::logic_error& e)
{
if (trim(cell).empty() && (argpars["-h"] == false))
{
std::cerr << "No expression given to evaluate" << std::endl;
}
}
code += cell;
if (trim(code).empty())
{
return;
}
auto errorlevel = 0;
std::string ename;
std::string evalue;
intptr_t output_value = 0;
bool hadError = false;
bool compilation_result = false;
try
{
if (number == 0)
{
for (std::size_t n = 0; n < 10; ++n)
{
number = std::pow(10, n);
std::string timeit_code = inner(number, code);
output_value = Cpp::Evaluate(timeit_code.c_str(), &hadError);
double result_as_double = static_cast<double>(output_value);
if (result_as_double >= 0.2)
{
break;
}
}
}
std::vector<double> all_runs;
double mean = 0;
double stdev = 0;
for (std::size_t r = 0; r < static_cast<std::size_t>(repeat); ++r)
{
std::string timeit_code = inner(number, code);
output_value = Cpp::Evaluate(timeit_code.c_str(), &hadError);
double result_as_double = static_cast<double>(output_value);
all_runs.push_back(result_as_double / number);
mean += all_runs.back();
}
mean /= repeat;
for (std::size_t r = 0; r < static_cast<std::size_t>(repeat); ++r)
{
stdev += (all_runs[r] - mean) * (all_runs[r] - mean);
}
stdev = std::sqrt(stdev / repeat);
std::cout << _format_time(mean, precision) << " +- " << _format_time(stdev, precision);
std::cout << " per loop (mean +- std. dev. of " << repeat << " run" << ((repeat == 1) ? ", " : "s ");
std::cout << number << " loop" << ((number == 1) ? "" : "s") << " each)" << std::endl;
}
catch (std::exception& e)
{
errorlevel = 1;
ename = "Standard Exception";
evalue = e.what();
}
catch (...)
{
errorlevel = 1;
ename = "Error";
}
if (compilation_result)
{
errorlevel = 1;
ename = "Interpreter Error";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment