Console: benchmark command execution

This commit is contained in:
Alexander A. Klimov 2020-01-24 13:44:39 +01:00
parent a65f2d6b41
commit cf0c10dd79
5 changed files with 62 additions and 5 deletions

View File

@ -19,6 +19,7 @@ set(base_SOURCES
atomic.hpp atomic.hpp
atomic-file.cpp atomic-file.hpp atomic-file.cpp atomic-file.hpp
base64.cpp base64.hpp base64.cpp base64.hpp
benchmark.hpp
boolean.cpp boolean.hpp boolean-script.cpp boolean.cpp boolean.hpp boolean-script.cpp
bulker.hpp bulker.hpp
configobject.cpp configobject.hpp configobject-ti.hpp configobject-script.cpp configobject.cpp configobject.hpp configobject-ti.hpp configobject-script.cpp

36
lib/base/benchmark.hpp Normal file
View File

@ -0,0 +1,36 @@
/* Icinga 2 | (c) 2020 Icinga GmbH | GPLv2+ */
#ifndef BENCHMARK_H
#define BENCHMARK_H
#include <chrono>
namespace icinga
{
/**
* A stopwatch.
*
* @ingroup base
*/
template<class Clock = std::chrono::steady_clock>
class Benchmark final
{
public:
inline void Start()
{
m_Start = Clock::now();
}
inline double Stop()
{
return std::chrono::duration<double>((Clock::now() - m_Start)).count();
}
private:
typename Clock::time_point m_Start;
};
}
#endif /* BENCHMARK_H */

View File

@ -4,6 +4,7 @@
#include "config/configcompiler.hpp" #include "config/configcompiler.hpp"
#include "remote/consolehandler.hpp" #include "remote/consolehandler.hpp"
#include "remote/url.hpp" #include "remote/url.hpp"
#include "base/benchmark.hpp"
#include "base/configwriter.hpp" #include "base/configwriter.hpp"
#include "base/serializer.hpp" #include "base/serializer.hpp"
#include "base/json.hpp" #include "base/json.hpp"
@ -31,6 +32,7 @@
#include <boost/beast/http/write.hpp> #include <boost/beast/http/write.hpp>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <utility>
#ifdef HAVE_EDITLINE #ifdef HAVE_EDITLINE
@ -418,6 +420,7 @@ incomplete:
lines[fileName] = command; lines[fileName] = command;
Value result; Value result;
double duration = 0.0;
/* Local debug console. */ /* Local debug console. */
if (connectAddr.IsEmpty()) { if (connectAddr.IsEmpty()) {
@ -428,13 +431,21 @@ incomplete:
if (!syntaxOnly || dynamic_cast<ThrowExpression *>(expr.get())) { if (!syntaxOnly || dynamic_cast<ThrowExpression *>(expr.get())) {
if (syntaxOnly) if (syntaxOnly)
std::cerr << " => " << command << std::endl; std::cerr << " => " << command << std::endl;
result = Serialize(expr->Evaluate(scriptFrame), 0);
Benchmark<> benchmark;
benchmark.Start();
auto ev (expr->Evaluate(scriptFrame));
duration = benchmark.Stop();
result = Serialize(std::move(ev), 0);
} else } else
result = true; result = true;
} else { } else {
/* Remote debug console. */ /* Remote debug console. */
try { try {
result = ExecuteScript(l_Session, command, scriptFrame.Sandboxed); result = ExecuteScript(l_Session, command, scriptFrame.Sandboxed, duration);
} catch (const ScriptError&) { } catch (const ScriptError&) {
/* Re-throw the exception for the outside try-catch block. */ /* Re-throw the exception for the outside try-catch block. */
boost::rethrow_exception(boost::current_exception()); boost::rethrow_exception(boost::current_exception());
@ -455,6 +466,7 @@ incomplete:
std::cout << ConsoleColorTag(Console_ForegroundCyan); std::cout << ConsoleColorTag(Console_ForegroundCyan);
ConfigWriter::EmitValue(std::cout, 1, result); ConfigWriter::EmitValue(std::cout, 1, result);
std::cout << ConsoleColorTag(Console_Normal) << "\n"; std::cout << ConsoleColorTag(Console_Normal) << "\n";
std::cout << duration << "s\n";
} else { } else {
std::cout << JsonEncode(result) << "\n"; std::cout << JsonEncode(result) << "\n";
break; break;
@ -639,7 +651,7 @@ Dictionary::Ptr ConsoleCommand::SendRequest()
* @param sandboxed Whether to run this sandboxed. * @param sandboxed Whether to run this sandboxed.
* @return Result value, also contains user errors. * @return Result value, also contains user errors.
*/ */
Value ConsoleCommand::ExecuteScript(const String& session, const String& command, bool sandboxed) Value ConsoleCommand::ExecuteScript(const String& session, const String& command, bool sandboxed, double& duration)
{ {
/* Extend the url parameters for the request. */ /* Extend the url parameters for the request. */
l_Url->SetPath({"v1", "console", "execute-script"}); l_Url->SetPath({"v1", "console", "execute-script"});
@ -661,6 +673,7 @@ Value ConsoleCommand::ExecuteScript(const String& session, const String& command
if (resultInfo->Get("code") >= 200 && resultInfo->Get("code") <= 299) { if (resultInfo->Get("code") >= 200 && resultInfo->Get("code") <= 299) {
result = resultInfo->Get("result"); result = resultInfo->Get("result");
duration = resultInfo->Get("duration");
} else { } else {
String errorMessage = resultInfo->Get("status"); String errorMessage = resultInfo->Get("status");

View File

@ -43,7 +43,7 @@ private:
static Shared<AsioTlsStream>::Ptr Connect(); static Shared<AsioTlsStream>::Ptr Connect();
static Value ExecuteScript(const String& session, const String& command, bool sandboxed); static Value ExecuteScript(const String& session, const String& command, bool sandboxed, double& duration);
static Array::Ptr AutoCompleteScript(const String& session, const String& command, bool sandboxed); static Array::Ptr AutoCompleteScript(const String& session, const String& command, bool sandboxed);
static Dictionary::Ptr SendRequest(); static Dictionary::Ptr SendRequest();

View File

@ -5,6 +5,7 @@
#include "remote/httputility.hpp" #include "remote/httputility.hpp"
#include "remote/filterutility.hpp" #include "remote/filterutility.hpp"
#include "config/configcompiler.hpp" #include "config/configcompiler.hpp"
#include "base/benchmark.hpp"
#include "base/configtype.hpp" #include "base/configtype.hpp"
#include "base/configwriter.hpp" #include "base/configwriter.hpp"
#include "base/scriptglobal.hpp" #include "base/scriptglobal.hpp"
@ -139,12 +140,18 @@ bool ConsoleHandler::ExecuteScriptHelper(boost::beast::http::request<boost::beas
frame.Self = lsf.Locals; frame.Self = lsf.Locals;
frame.Sandboxed = sandboxed; frame.Sandboxed = sandboxed;
Benchmark<> benchmark;
benchmark.Start();
exprResult = expr->Evaluate(frame); exprResult = expr->Evaluate(frame);
auto duration (benchmark.Stop());
resultInfo = new Dictionary({ resultInfo = new Dictionary({
{ "code", 200 }, { "code", 200 },
{ "status", "Executed successfully." }, { "status", "Executed successfully." },
{ "result", Serialize(exprResult, 0) } { "result", Serialize(exprResult, 0) },
{ "duration", duration }
}); });
} catch (const ScriptError& ex) { } catch (const ScriptError& ex) {
DebugInfo di = ex.GetDebugInfo(); DebugInfo di = ex.GetDebugInfo();