summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/test/cppsuite/test_harness/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/test/cppsuite/test_harness/core')
-rw-r--r--src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.cpp85
-rw-r--r--src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.h95
-rw-r--r--src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.cpp305
-rw-r--r--src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.h114
-rw-r--r--src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.cpp37
-rw-r--r--src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.h58
-rw-r--r--src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.cpp75
-rw-r--r--src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.h55
8 files changed, 824 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.cpp b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.cpp
new file mode 100644
index 00000000000..aeb691fe674
--- /dev/null
+++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.cpp
@@ -0,0 +1,85 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "component.h"
+#include "test_harness/util/api_const.h"
+
+namespace test_harness {
+component::component(const std::string &name, configuration *config) : _config(config), _name(name)
+{
+}
+
+component::~component()
+{
+ delete _config;
+}
+
+void
+component::load()
+{
+ logger::log_msg(LOG_INFO, "Loading component: " + _name);
+ _enabled = _config->get_optional_bool(ENABLED, true);
+ _throttle = throttle(_config);
+ /* If we're not enabled we shouldn't be running. */
+ _running = _enabled;
+}
+
+void
+component::run()
+{
+ logger::log_msg(LOG_INFO, "Running component: " + _name);
+ while (_enabled && _running) {
+ do_work();
+ _throttle.sleep();
+ }
+}
+
+void
+component::do_work()
+{
+ /* Not implemented. */
+}
+
+bool
+component::enabled() const
+{
+ return (_enabled);
+}
+
+void
+component::end_run()
+{
+ _running = false;
+}
+
+void
+component::finish()
+{
+ logger::log_msg(LOG_INFO, "Running finish stage of component: " + _name);
+}
+} // namespace test_harness
diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.h b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.h
new file mode 100644
index 00000000000..5a8f8f81cf5
--- /dev/null
+++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.h
@@ -0,0 +1,95 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef COMPONENT_H
+#define COMPONENT_H
+
+#include "configuration.h"
+#include "throttle.h"
+
+namespace test_harness {
+/*
+ * A component is a class that defines 4 unique stages in its life-cycle, the stages must be run in
+ * the following order: load, run, end_run, finish.
+ *
+ *
+ */
+class component {
+ public:
+ explicit component(const std::string &name, configuration *config);
+ virtual ~component();
+
+ /* Delete the copy constructor and the assignment operator. */
+ component(const component &) = delete;
+ component &operator=(const component &) = delete;
+
+ /*
+ * The load function should perform all tasks required to setup the component for the main phase
+ * of the test. An example operation performed in the load phase would be populating a database.
+ */
+ virtual void load();
+
+ /*
+ * The run function provides a top level loop that calls the do_work function every X seconds as
+ * defined by the throttle. Each run() method defined by the components is called in its own
+ * thread by the top level test class.
+ *
+ * If a component does not wish to use the standard run function, it can be overloaded.
+ */
+ virtual void run();
+
+ /* end_run informs the component that is no longer running which closes out its run loop. */
+ void end_run();
+
+ /*
+ * do_work is called every X seconds as defined by the throttle. Generally most components
+ * should do their "operation" in the do_work function.
+ */
+ virtual void do_work();
+
+ /* Gets the value of the _enabled variable. */
+ bool enabled() const;
+
+ /*
+ * The finish phase is a cleanup phase. Created objects are destroyed here and any final testing
+ * requirements can be performed in this phase. An example could be the verification of the
+ * database, or checking some relevant statistics.
+ */
+ virtual void finish();
+
+ protected:
+ bool _enabled = false;
+ volatile bool _running = false;
+ throttle _throttle;
+ configuration *_config;
+
+ private:
+ std::string _name;
+};
+} // namespace test_harness
+#endif
diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.cpp b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.cpp
new file mode 100644
index 00000000000..f508dc76bea
--- /dev/null
+++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.cpp
@@ -0,0 +1,305 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <algorithm>
+#include <stack>
+
+#include "configuration.h"
+
+namespace test_harness {
+/* Static methods implementation. */
+static bool
+config_item_to_bool(const WT_CONFIG_ITEM item)
+{
+ return (item.val != 0);
+}
+
+static int64_t
+config_item_to_int(const WT_CONFIG_ITEM item)
+{
+ return (item.val);
+}
+
+static std::string
+config_item_to_string(const WT_CONFIG_ITEM item)
+{
+ return std::string(item.str, item.len);
+}
+
+static std::vector<std::string>
+config_item_to_list(const WT_CONFIG_ITEM item)
+{
+ auto str = config_item_to_string(item);
+
+ /* Get rid of the brackets. */
+ testutil_assert(!str.empty() && str.front() == '[' && str.back() == ']');
+ str.pop_back();
+ str.erase(0, 1);
+
+ return (split_string(str, ','));
+}
+
+/* configuration class implementation. */
+configuration::configuration(const std::string &test_config_name, const std::string &config)
+{
+ const auto *config_entry = __wt_test_config_match(test_config_name.c_str());
+ if (config_entry == nullptr)
+ testutil_die(EINVAL, "failed to match test config name");
+ std::string default_config = std::string(config_entry->base);
+ /* Merge in the default configuration. */
+ _config = merge_default_config(default_config, config);
+ logger::log_msg(LOG_INFO, "Full config: " + _config);
+
+ int ret =
+ wiredtiger_test_config_validate(nullptr, nullptr, test_config_name.c_str(), _config.c_str());
+ if (ret != 0)
+ testutil_die(EINVAL, "failed to validate given config, ensure test config exists");
+ ret = wiredtiger_config_parser_open(nullptr, _config.c_str(), _config.size(), &_config_parser);
+ if (ret != 0)
+ testutil_die(EINVAL, "failed to create configuration parser for provided config");
+}
+
+configuration::configuration(const WT_CONFIG_ITEM &nested)
+{
+ if (nested.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_STRUCT)
+ testutil_die(EINVAL, "provided config item isn't a structure");
+ int ret = wiredtiger_config_parser_open(nullptr, nested.str, nested.len, &_config_parser);
+ if (ret != 0)
+ testutil_die(EINVAL, "failed to create configuration parser for provided sub config");
+}
+
+configuration::~configuration()
+{
+ if (_config_parser != nullptr) {
+ _config_parser->close(_config_parser);
+ _config_parser = nullptr;
+ }
+}
+
+std::string
+configuration::get_string(const std::string &key)
+{
+ return get<std::string>(key, false, types::STRING, "", config_item_to_string);
+}
+
+std::string
+configuration::get_optional_string(const std::string &key, const std::string &def)
+{
+ return get<std::string>(key, true, types::STRING, def, config_item_to_string);
+}
+
+bool
+configuration::get_bool(const std::string &key)
+{
+ return get<bool>(key, false, types::BOOL, false, config_item_to_bool);
+}
+
+bool
+configuration::get_optional_bool(const std::string &key, const bool def)
+{
+ return get<bool>(key, true, types::BOOL, def, config_item_to_bool);
+}
+
+int64_t
+configuration::get_int(const std::string &key)
+{
+ return get<int64_t>(key, false, types::INT, 0, config_item_to_int);
+}
+
+int64_t
+configuration::get_optional_int(const std::string &key, const int64_t def)
+{
+ return get<int64_t>(key, true, types::INT, def, config_item_to_int);
+}
+
+configuration *
+configuration::get_subconfig(const std::string &key)
+{
+ return get<configuration *>(key, false, types::STRUCT, nullptr,
+ [](WT_CONFIG_ITEM item) { return new configuration(item); });
+}
+
+configuration *
+configuration::get_optional_subconfig(const std::string &key)
+{
+ return get<configuration *>(key, true, types::STRUCT, nullptr,
+ [](WT_CONFIG_ITEM item) { return new configuration(item); });
+}
+
+std::vector<std::string>
+configuration::get_list(const std::string &key)
+{
+ return get<std::vector<std::string>>(key, false, types::LIST, {}, config_item_to_list);
+}
+
+template <typename T>
+T
+configuration::get(
+ const std::string &key, bool optional, types type, T def, T (*func)(WT_CONFIG_ITEM item))
+{
+ WT_DECL_RET;
+ WT_CONFIG_ITEM value = {"", 0, 1, WT_CONFIG_ITEM::WT_CONFIG_ITEM_BOOL};
+
+ ret = _config_parser->get(_config_parser, key.c_str(), &value);
+ if (ret == WT_NOTFOUND && optional)
+ return (def);
+ else if (ret != 0)
+ testutil_die(ret, ("Error while finding config with key \"" + key + "\"").c_str());
+
+ const char *error_msg = "Configuration value doesn't match requested type";
+ if (type == types::STRING &&
+ (value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_STRING &&
+ value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_ID))
+ testutil_die(-1, error_msg);
+ else if (type == types::BOOL && value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_BOOL)
+ testutil_die(-1, error_msg);
+ else if (type == types::INT && value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_NUM)
+ testutil_die(-1, error_msg);
+ else if (type == types::STRUCT && value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_STRUCT)
+ testutil_die(-1, error_msg);
+ else if (type == types::LIST && value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_STRUCT)
+ testutil_die(-1, error_msg);
+
+ return func(value);
+}
+
+std::string
+configuration::merge_default_config(
+ const std::string &default_config, const std::string &user_config)
+{
+ std::string merged_config;
+ auto split_default_config = split_config(default_config);
+ auto split_user_config = split_config(user_config);
+ auto user_it = split_user_config.begin();
+ for (auto default_it = split_default_config.begin(); default_it != split_default_config.end();
+ ++default_it) {
+ if (user_it == split_user_config.end() || user_it->first != default_it->first)
+ /* The default does not exist in the user configuration, add it. */
+ merged_config += default_it->first + "=" + default_it->second;
+ else {
+ /* If we have a sub config merge it in. */
+ if (user_it->second[0] == '(')
+ merged_config += default_it->first + "=(" +
+ merge_default_config(default_it->second, user_it->second) + ')';
+ else
+ /* Add the user configuration as it exists. */
+ merged_config += user_it->first + "=" + user_it->second;
+ ++user_it;
+ }
+ /* Add a comma after every item we add except the last one. */
+ if (split_default_config.end() - default_it != 1)
+ merged_config += ",";
+ }
+ /* Add any remaining user config items. */
+ while (user_it != split_user_config.end()) {
+ merged_config += "," + user_it->first + "=" + user_it->second;
+ ++user_it;
+ }
+ return (merged_config);
+}
+
+std::vector<std::pair<std::string, std::string>>
+configuration::split_config(const std::string &config)
+{
+ std::string cut_config = config;
+ std::vector<std::pair<std::string, std::string>> split_config;
+ std::string key = "", value = "";
+ bool in_subconfig = false;
+ bool expect_value = false;
+ std::stack<char> parens;
+
+ /* All configuration strings must be at least 2 characters. */
+ testutil_assert(config.size() > 1);
+
+ /* Remove prefix and trailing "()". */
+ if (config[0] == '(')
+ cut_config = config.substr(1, config.size() - 2);
+
+ size_t start = 0, len = 0;
+ for (size_t i = 0; i < cut_config.size(); ++i) {
+ if (cut_config[i] == '(' || cut_config[i] == '[') {
+ parens.push(cut_config[i]);
+ in_subconfig = true;
+ }
+ if (cut_config[i] == ')' || cut_config[i] == ']') {
+ parens.pop();
+ in_subconfig = !parens.empty();
+ }
+ if (cut_config[i] == '=' && !in_subconfig) {
+ if (len == 0) {
+ testutil_die(EINVAL, "error parsing config: detected empty key");
+ }
+ if (expect_value) {
+ testutil_die(EINVAL,
+ "error parsing config: syntax error parsing value for key ['%s']: '%s'",
+ key.c_str(), cut_config.substr(start, len).c_str());
+ }
+ expect_value = true;
+ key = cut_config.substr(start, len);
+ start += len + 1;
+ len = 0;
+ continue;
+ }
+ if (cut_config[i] == ',' && !in_subconfig) {
+ if (len == 0) {
+ testutil_die(
+ EINVAL, "error parsing config: detected empty value for key:'%s'", key.c_str());
+ }
+ if (!expect_value) {
+ testutil_die(EINVAL,
+ "error parsing config: syntax error parsing key value pair: '%s'",
+ cut_config.substr(start, len).c_str());
+ }
+ expect_value = false;
+ if (start + len >= cut_config.size())
+ break;
+ value = cut_config.substr(start, len);
+ start += len + 1;
+ len = 0;
+ split_config.push_back(std::make_pair(key, value));
+ continue;
+ }
+ ++len;
+ }
+ if (expect_value) {
+ value = cut_config.substr(start, len);
+ split_config.push_back(std::make_pair(key, value));
+ }
+
+ /* We have to sort the config here otherwise we will match incorrectly while merging. */
+ std::sort(split_config.begin(), split_config.end(), comparator);
+ return (split_config);
+}
+
+bool
+configuration::comparator(
+ std::pair<std::string, std::string> a, std::pair<std::string, std::string> b)
+{
+ return (a.first < b.first);
+}
+} // namespace test_harness
diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.h b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.h
new file mode 100644
index 00000000000..b61defc9d3f
--- /dev/null
+++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.h
@@ -0,0 +1,114 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef CONFIGURATION_H
+#define CONFIGURATION_H
+
+#include <string>
+#include <vector>
+
+#include "test_harness/util/logger.h"
+
+extern "C" {
+#include "test_util.h"
+}
+
+namespace test_harness {
+inline std::vector<std::string>
+split_string(const std::string &str, const char delim)
+{
+ std::vector<std::string> splits;
+ std::string current_str;
+ for (const auto c : str) {
+ if (c == delim) {
+ if (!current_str.empty()) {
+ splits.push_back(current_str);
+ current_str.clear();
+ }
+ } else
+ current_str.push_back(c);
+ }
+ if (!current_str.empty())
+ splits.push_back(std::move(current_str));
+ return (splits);
+}
+
+class configuration {
+ public:
+ explicit configuration(const std::string &test_config_name, const std::string &config);
+ explicit configuration(const WT_CONFIG_ITEM &nested);
+
+ ~configuration();
+
+ /*
+ * Wrapper functions for retrieving basic configuration values. Ideally tests can avoid using
+ * the config item struct provided by wiredtiger.
+ *
+ * When getting a configuration value that may not exist for that configuration string or
+ * component, the optional forms of the functions can be used. In this case a default value must
+ * be passed and it will be set to that value.
+ */
+ std::string get_string(const std::string &key);
+ std::string get_optional_string(const std::string &key, const std::string &def);
+ bool get_bool(const std::string &key);
+ bool get_optional_bool(const std::string &key, const bool def);
+ int64_t get_int(const std::string &key);
+ int64_t get_optional_int(const std::string &key, const int64_t def);
+ configuration *get_subconfig(const std::string &key);
+ configuration *get_optional_subconfig(const std::string &key);
+ std::vector<std::string> get_list(const std::string &key);
+ std::vector<std::string> get_optional_list(const std::string &key);
+
+ private:
+ enum class types { BOOL, INT, LIST, STRING, STRUCT };
+
+ template <typename T>
+ T get(const std::string &key, bool optional, types type, T def, T (*func)(WT_CONFIG_ITEM item));
+
+ /*
+ * Merge together two configuration strings, the user one and the default one.
+ */
+ static std::string merge_default_config(
+ const std::string &default_config, const std::string &user_config);
+
+ /*
+ * Split a config string into keys and values, taking care to not split incorrectly when we have
+ * a sub config or array.
+ */
+ static std::vector<std::pair<std::string, std::string>> split_config(const std::string &config);
+
+ static bool comparator(
+ std::pair<std::string, std::string> a, std::pair<std::string, std::string> b);
+
+ private:
+ std::string _config;
+ WT_CONFIG_PARSER *_config_parser = nullptr;
+};
+} // namespace test_harness
+
+#endif
diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.cpp b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.cpp
new file mode 100644
index 00000000000..af806927768
--- /dev/null
+++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.cpp
@@ -0,0 +1,37 @@
+#include "test_harness/test.h"
+#include "test_harness/util/perf_plotter.h"
+#include "op_tracker.h"
+
+namespace test_harness {
+op_tracker::op_tracker(const std::string id, const std::string &test_name)
+ : _id(id), _test_name(test_name), _it_count(0), _total_time_taken(0)
+{
+}
+
+void
+op_tracker::append_stats()
+{
+ uint64_t avg = (uint64_t)_total_time_taken / _it_count;
+ std::string stat = "{\"name\":\"" + _id + "\",\"value\":" + std::to_string(avg) + "}";
+ perf_plotter::instance().add_stat(stat);
+}
+
+template <typename T>
+auto
+op_tracker::track(T lambda)
+{
+ auto _start_time = std::chrono::steady_clock::now();
+ int ret = lambda();
+ auto _end_time = std::chrono::steady_clock::now();
+ _total_time_taken += (_end_time - _start_time).count();
+ _it_count += 1;
+
+ return ret;
+}
+
+op_tracker::~op_tracker()
+{
+ if (_it_count != 0)
+ append_stats();
+}
+}; // namespace test_harness
diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.h b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.h
new file mode 100644
index 00000000000..eea99b2414c
--- /dev/null
+++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.h
@@ -0,0 +1,58 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <chrono>
+#include <fstream>
+#include <string>
+
+namespace test_harness {
+
+/*
+ * Class that tracks the performance of given operations and appends the stats to the perf file.
+ */
+class op_tracker {
+ public:
+ explicit op_tracker(const std::string id, const std::string &test_name);
+ virtual ~op_tracker();
+
+ /* Calculates the average time and appends the stat to the perf file. */
+ void append_stats();
+
+ /*
+ * Does timing for a given operation and keeps track of how many operations have been executed
+ * as well as total time taken.
+ */
+ template <typename T> auto track(T lambda);
+
+ private:
+ std::string _id;
+ std::string _test_name;
+ int _it_count;
+ uint64_t _total_time_taken;
+};
+} // namespace test_harness
diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.cpp b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.cpp
new file mode 100644
index 00000000000..af7b94e8f98
--- /dev/null
+++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.cpp
@@ -0,0 +1,75 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <thread>
+
+#include "configuration.h"
+#include "test_harness/util/api_const.h"
+#include "throttle.h"
+
+namespace test_harness {
+throttle::throttle(const std::string &throttle_rate)
+{
+ std::string magnitude;
+ uint64_t multiplier = 0;
+ /*
+ * Find the ms, s, or m in the string. Searching for "ms" first as the following two searches
+ * would match as well.
+ */
+ size_t pos = throttle_rate.find("ms");
+ if (pos != std::string::npos)
+ multiplier = 1;
+ else {
+ pos = throttle_rate.find("s");
+ if (pos != std::string::npos)
+ multiplier = 1000;
+ else {
+ pos = throttle_rate.find("m");
+ if (pos != std::string::npos)
+ multiplier = 60 * 1000;
+ else
+ testutil_die(-1, "no rate specifier given");
+ }
+ }
+ magnitude = throttle_rate.substr(0, pos);
+ /* This will throw if it can't cast, which is fine. */
+ _ms = std::stoi(magnitude) * multiplier;
+}
+
+/* Use optional and default to 1s per op in case something doesn't define this. */
+throttle::throttle(configuration *config) : throttle(config->get_optional_string(OP_RATE, "1s")) {}
+
+/* Default to a second per operation. */
+throttle::throttle() : throttle("1s") {}
+
+void
+throttle::sleep()
+{
+ std::this_thread::sleep_for(std::chrono::milliseconds(_ms));
+}
+} // namespace test_harness
diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.h b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.h
new file mode 100644
index 00000000000..24161ea956e
--- /dev/null
+++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.h
@@ -0,0 +1,55 @@
+/*-
+ * Public Domain 2014-present MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef THROTTLE_H
+#define THROTTLE_H
+
+#include <string>
+
+/* Forward declarations for classes to reduce compilation time and modules coupling. */
+class configuration;
+
+namespace test_harness {
+class throttle {
+ public:
+ explicit throttle(const std::string &throttle_rate);
+
+ /* Use optional and default to 1s per op in case something doesn't define this. */
+ explicit throttle(configuration *config);
+
+ /* Default to a second per operation. */
+ throttle();
+
+ void sleep();
+
+ private:
+ uint64_t _ms = 1000;
+};
+} // namespace test_harness
+
+#endif