diff --git a/loolwsd/.gitignore b/loolwsd/.gitignore index 52e006758..9bdd0f73c 100644 --- a/loolwsd/.gitignore +++ b/loolwsd/.gitignore @@ -46,5 +46,6 @@ loolforkit loolmount loolmap looltool +loolstress loolforkit-nocaps loadtest diff --git a/loolwsd/LOOLStress.cpp b/loolwsd/LOOLStress.cpp new file mode 100644 index 000000000..6232128a7 --- /dev/null +++ b/loolwsd/LOOLStress.cpp @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common.hpp" +#include "LOOLProtocol.hpp" +#include "Util.hpp" +#include "test/helpers.hpp" + +#include +#include + +/// Stress testing and performance/scalability benchmarking tool. + +class Stress: public Poco::Util::Application +{ +public: + Stress(); + ~Stress() {} + + unsigned _numClients; + std::string _serverURI; + +protected: + void defineOptions(Poco::Util::OptionSet& options) override; + void handleOption(const std::string& name, const std::string& value) override; + int main(const std::vector& args) override; +}; + + +using namespace LOOLProtocol; + +using Poco::Net::HTTPClientSession; +using Poco::Net::HTTPRequest; +using Poco::Net::HTTPResponse; +using Poco::Runnable; +using Poco::Thread; +using Poco::URI; +using Poco::Util::Application; +using Poco::Util::HelpFormatter; +using Poco::Util::Option; +using Poco::Util::OptionSet; + +class Worker: public Runnable +{ +public: + + Worker(Stress& app, const std::string& traceFilePath) : + _app(app), _traceFilePath(traceFilePath) + { + } + + void run() override + { + std::cerr << "Connecting to server: " << _app._serverURI << "\n"; + + Poco::URI uri(_app._serverURI); + + const auto documentURL = "lool/ws/file://" + Poco::Path(_traceFilePath).makeAbsolute().toString(); + + std::unique_ptr session; + if (_app._serverURI.compare(0, 5, "https")) + session.reset(new Poco::Net::HTTPSClientSession(uri.getHost(), uri.getPort())); + else + session.reset(new Poco::Net::HTTPClientSession(uri.getHost(), uri.getPort())); + + try + { + + } + catch (const Poco::Exception &e) + { + std::cerr << "Failed to write data: " << e.name() << + " " << e.message() << "\n"; + return; + } + } + +private: + Stress& _app; + std::string _traceFilePath; +}; + +Stress::Stress() : + _numClients(4), +#if ENABLE_SSL + _serverURI("https://127.0.0.1:" + std::to_string(DEFAULT_CLIENT_PORT_NUMBER)) +#else + _serverURI("http://127.0.0.1:" + std::to_string(DEFAULT_CLIENT_PORT_NUMBER)) +#endif +{ +} + +void Stress::defineOptions(OptionSet& optionSet) +{ + Application::defineOptions(optionSet); + + optionSet.addOption(Option("help", "", "Display help information on command line arguments.") + .required(false).repeatable(false)); + optionSet.addOption(Option("clientsperdoc", "", "Number of simultaneous clients on each doc.") + .required(false).repeatable(false) + .argument("concurrency")); + optionSet.addOption(Option("server", "", "URI of LOOL server") + .required(false).repeatable(false) + .argument("uri")); +} + +void Stress::handleOption(const std::string& optionName, + const std::string& value) +{ + Application::handleOption(optionName, value); + + if (optionName == "help") + { + HelpFormatter helpFormatter(options()); + + helpFormatter.setCommand(commandName()); + helpFormatter.setUsage("OPTIONS"); + helpFormatter.setHeader("LibreOffice On-Line tool."); + helpFormatter.format(std::cout); + std::exit(Application::EXIT_OK); + } + else if (optionName == "clientsperdoc") + _numClients = std::max(std::stoi(value), 1); + else if (optionName == "server") + _serverURI = value; + else + { + std::cerr << "Unknown option: " << optionName << std::endl; + exit(1); + } +} + +int Stress::main(const std::vector& args) +{ + std::vector> clients(_numClients * args.size()); + + std::cout << "Args: " << args.size() << std::endl; + + unsigned index = 0; + for (unsigned i = 0; i < args.size(); ++i) + { + std::cout << "Arg: " << args[i] << std::endl; + for (unsigned j = 0; j < _numClients; ++j, ++index) + { + clients[index].reset(new Thread()); + clients[index]->start(*(new Worker(*this, args[i]))); + } + } + + for (const auto& client : clients) + { + client->join(); + } + + return Application::EXIT_OK; +} + +POCO_APP_MAIN(Stress) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am index 148e9c936..d3cd9efc2 100644 --- a/loolwsd/Makefile.am +++ b/loolwsd/Makefile.am @@ -2,7 +2,7 @@ SUBDIRS = . test export ENABLE_DEBUG -bin_PROGRAMS = loolwsd loolforkit loolmap loolmount looltool +bin_PROGRAMS = loolwsd loolforkit loolmap loolmount looltool loolstress dist_bin_SCRIPTS = loolwsd-systemplate-setup @@ -78,6 +78,8 @@ loolmap_SOURCES = loolmap.c looltool_SOURCES = LOOLTool.cpp +loolstress_SOURCES = LOOLStress.cpp + noinst_HEADERS = Admin.hpp \ AdminModel.hpp \ Auth.hpp \