Replace params class with nvbench::named_values.

Refactor nvbench::state to use this for axis parameters.

These will also be useful for summaries and measurements.

Also adds a new ASSERT_THROWS_ANY macro to test some of the new API.
This commit is contained in:
Allison Vacanti
2020-12-30 14:45:46 -05:00
parent 8c0b8e3423
commit ad44463d6e
13 changed files with 295 additions and 161 deletions

View File

@@ -5,7 +5,7 @@ set(srcs
cuda_call.cu
float64_axis.cu
int64_axis.cu
params.cu
named_values.cu
state.cu
string_axis.cu
type_axis.cu

View File

@@ -41,19 +41,19 @@ std::vector<nvbench::state> state_generator::create(const axes_metadata &axes)
break;
case axis_type::int64:
state.set_param(
state.m_axis_values.set_int64(
axis_info.axis,
axes.get_int64_axis(axis_info.axis).get_value(axis_info.index));
break;
case axis_type::float64:
state.set_param(
state.m_axis_values.set_float64(
axis_info.axis,
axes.get_float64_axis(axis_info.axis).get_value(axis_info.index));
break;
case axis_type::string:
state.set_param(
state.m_axis_values.set_string(
axis_info.axis,
axes.get_string_axis(axis_info.axis).get_value(axis_info.index));
break;

109
nvbench/named_values.cu Normal file
View File

@@ -0,0 +1,109 @@
#include <nvbench/named_values.cuh>
#include <fmt/format.h>
#include <algorithm>
#include <iterator>
#include <stdexcept>
#include <type_traits>
namespace nvbench
{
void named_values::clear() { m_map.clear(); }
std::size_t named_values::get_size() const { return m_map.size(); }
std::vector<std::string> named_values::get_names() const
{
std::vector<std::string> names;
names.reserve(m_map.size());
std::transform(m_map.cbegin(),
m_map.cend(),
std::back_inserter(names),
[](const auto &val) { return val.first; });
return names;
}
bool named_values::has_value(const std::string &name) const
{
return m_map.find(name) != m_map.cend();
}
const named_values::value_type &
named_values::get_value(const std::string &name) const
{
return m_map.at(name);
}
named_values::type named_values::get_type(const std::string &name) const
{
return std::visit(
[&name]([[maybe_unused]] auto &&arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, nvbench::int64_t>)
{
return nvbench::named_values::type::int64;
}
else if constexpr (std::is_same_v<T, nvbench::float64_t>)
{
return nvbench::named_values::type::float64;
}
else if constexpr (std::is_same_v<T, std::string>)
{
return nvbench::named_values::type::string;
}
throw std::runtime_error(fmt::format("{}:{}: Unknown variant type for "
"entry '{}'.",
__FILE__,
__LINE__,
name));
},
this->get_value(name));
}
nvbench::int64_t named_values::get_int64(const std::string &name) const
{
return std::get<nvbench::int64_t>(this->get_value(name));
}
nvbench::float64_t named_values::get_float64(const std::string &name) const
{
return std::get<nvbench::float64_t>(this->get_value(name));
}
const std::string &named_values::get_string(const std::string &name) const
{
return std::get<std::string>(this->get_value(name));
}
void named_values::set_int64(std::string name, nvbench::int64_t value)
{
m_map.insert(std::make_pair(std::move(name), value_type{std::move(value)}));
}
void named_values::set_float64(std::string name, nvbench::float64_t value)
{
m_map.insert(std::make_pair(std::move(name), value_type{std::move(value)}));
}
void named_values::set_string(std::string name, std::string value)
{
m_map.insert(std::make_pair(std::move(name), value_type{std::move(value)}));
}
void named_values::set_value(std::string name, named_values::value_type value)
{
m_map.insert(std::make_pair(std::move(name), std::move(value)));
}
void named_values::remove_value(const std::string &name)
{
auto iter = m_map.find(name);
if (iter != m_map.end())
{
m_map.erase(iter);
}
}
} // namespace nvbench

55
nvbench/named_values.cuh Normal file
View File

@@ -0,0 +1,55 @@
#pragma once
#include <nvbench/types.cuh>
#include <string>
#include <unordered_map>
#include <variant>
namespace nvbench
{
/**
* Maintains a map of key / value pairs where the keys are names and the
* values may be int64s, float64s, or strings.
*/
struct named_values
{
using value_type =
std::variant<nvbench::int64_t, nvbench::float64_t, std::string>;
enum class type
{
int64,
float64,
string
};
[[nodiscard]] std::size_t get_size() const;
[[nodiscard]] std::vector<std::string> get_names() const;
void set_value(std::string name, value_type value);
void set_int64(std::string name, nvbench::int64_t value);
void set_float64(std::string name, nvbench::float64_t value);
void set_string(std::string name, std::string value);
[[nodiscard]] nvbench::int64_t get_int64(const std::string &name) const;
[[nodiscard]] nvbench::float64_t get_float64(const std::string &name) const;
[[nodiscard]] const std::string &get_string(const std::string &name) const;
[[nodiscard]] type get_type(const std::string &name) const;
[[nodiscard]] bool has_value(const std::string &name) const;
[[nodiscard]] const value_type& get_value(const std::string &name) const;
void clear();
void remove_value(const std::string& name);
private:
using map_type = std::unordered_map<std::string, value_type>;
map_type m_map;
};
} // namespace nvbench

View File

@@ -1,40 +0,0 @@
#include <nvbench/params.cuh>
#include <unordered_map>
#include <utility>
namespace nvbench
{
const std::string &params::get_string_param(const std::string &axis_name) const
{
return m_string_params.at(axis_name);
}
nvbench::int64_t params::get_int64_param(const std::string &axis_name) const
{
return m_int64_params.at(axis_name);
}
nvbench::float64_t params::get_float64_param(const std::string &axis_name) const
{
return m_float64_params.at(axis_name);
}
void params::add_string_param(std::string axis_name, std::string value)
{
m_string_params.insert(
std::make_pair(std::move(axis_name), std::move(value)));
}
void params::add_int64_param(std::string axis_name, nvbench::int64_t value)
{
m_int64_params.insert(std::make_pair(std::move(axis_name), value));
}
void params::add_float64_param(std::string axis_name, nvbench::float64_t value)
{
m_float64_params.insert(std::make_pair(std::move(axis_name), value));
}
} // namespace nvbench

View File

@@ -1,31 +0,0 @@
#pragma once
#include <nvbench/types.cuh>
#include <unordered_map>
namespace nvbench
{
struct params
{
[[nodiscard]] const std::string &
get_string_param(const std::string &axis_name) const;
[[nodiscard]] nvbench::int64_t
get_int64_param(const std::string &axis_name) const;
[[nodiscard]] nvbench::float64_t
get_float64_param(const std::string &axis_name) const;
void add_string_param(std::string axis_name, std::string value);
void add_int64_param(std::string axis_name, nvbench::int64_t value);
void add_float64_param(std::string axis_name, nvbench::float64_t value);
private:
std::unordered_map<std::string, std::string> m_string_params;
std::unordered_map<std::string, nvbench::int64_t> m_int64_params;
std::unordered_map<std::string, nvbench::float64_t> m_float64_params;
};
} // namespace nvbench

View File

@@ -3,44 +3,23 @@
#include <nvbench/types.cuh>
#include <string>
#include <unordered_map>
#include <variant>
namespace nvbench
{
const state::param_type &state::get_param(const std::string &axis_name) const
{
return m_params.at(axis_name);
}
nvbench::int64_t state::get_int64(const std::string &axis_name) const
{
return std::get<nvbench::int64_t>(m_params.at(axis_name));
return m_axis_values.get_int64(axis_name);
}
nvbench::float64_t state::get_float64(const std::string &axis_name) const
{
return std::get<nvbench::float64_t>(m_params.at(axis_name));
return m_axis_values.get_float64(axis_name);
}
const std::string &state::get_string(const std::string &axis_name) const
{
return std::get<std::string>(m_params.at(axis_name));
}
void state::set_param(std::string axis_name, nvbench::int64_t value)
{
m_params.insert(std::make_pair(std::move(axis_name), value));
}
void state::set_param(std::string axis_name, nvbench::float64_t value)
{
m_params.insert(std::make_pair(std::move(axis_name), value));
}
void state::set_param(std::string axis_name, std::string value)
{
m_params.insert(std::make_pair(std::move(axis_name), std::move(value)));
return m_axis_values.get_string(axis_name);
}
} // namespace nvbench

View File

@@ -1,10 +1,9 @@
#pragma once
#include <nvbench/named_values.cuh>
#include <nvbench/types.cuh>
#include <string>
#include <unordered_map>
#include <variant>
namespace nvbench
{
@@ -33,24 +32,9 @@ struct state
protected:
friend struct nvbench::detail::state_generator;
using param_type =
std::variant<nvbench::int64_t, nvbench::float64_t, std::string>;
using params_type = std::unordered_map<std::string, param_type>;
state() = default;
explicit state(params_type params)
: m_params{std::move(params)}
{}
[[nodiscard]] const params_type &get_params() const { return m_params; }
[[nodiscard]] const param_type &get_param(const std::string &name) const;
void set_param(std::string axis_name, nvbench::int64_t value);
void set_param(std::string axis_name, nvbench::float64_t value);
void set_param(std::string axis_name, std::string value);
params_type m_params;
nvbench::named_values m_axis_values;
};
} // namespace nvbench

View File

@@ -5,7 +5,7 @@ set(test_srcs
cpu_timer.cu
float64_axis.cu
int64_axis.cu
params.cu
named_values.cu
state.cu
state_generator.cu
string_axis.cu

94
testing/named_values.cu Normal file
View File

@@ -0,0 +1,94 @@
#include <nvbench/named_values.cuh>
#include "test_asserts.cuh"
#include <algorithm>
void test_empty()
{
nvbench::named_values vals;
ASSERT(vals.get_size() == 0);
ASSERT(vals.get_names().size() == 0);
ASSERT(vals.has_value("Nope") == false);
ASSERT_THROWS_ANY([[maybe_unused]] auto val = vals.get_value("Nope"));
ASSERT_THROWS_ANY([[maybe_unused]] auto type = vals.get_type("Nope"));
// Removing non-existent entries shouldn't cause a problem:
vals.remove_value("Nope");
}
void test_basic()
{
auto sort = [](auto &&vec) {
std::sort(vec.begin(), vec.end());
return std::forward<decltype(vec)>(vec);
};
nvbench::named_values vals;
vals.set_int64("Int", 32);
vals.set_float64("Float", 34.5);
vals.set_string("String", "string!");
vals.set_value("IntVar", nvbench::named_values::value_type{36ll});
std::vector<std::string> names{"Float", "Int", "IntVar", "String"};
ASSERT(vals.get_size() == 4);
ASSERT(sort(vals.get_names()) == names);
ASSERT(vals.has_value("Float"));
ASSERT(vals.has_value("Int"));
ASSERT(vals.has_value("IntVar"));
ASSERT(vals.has_value("String"));
ASSERT(std::get<nvbench::float64_t>(vals.get_value("Float")) == 34.5);
ASSERT(std::get<nvbench::int64_t>(vals.get_value("Int")) == 32);
ASSERT(std::get<nvbench::int64_t>(vals.get_value("IntVar")) == 36);
ASSERT(std::get<std::string>(vals.get_value("String")) == "string!");
ASSERT(vals.get_type("Float") == nvbench::named_values::type::float64);
ASSERT(vals.get_type("Int") == nvbench::named_values::type::int64);
ASSERT(vals.get_type("IntVar") == nvbench::named_values::type::int64);
ASSERT(vals.get_type("String") == nvbench::named_values::type::string);
ASSERT(vals.get_int64("Int") == 32);
ASSERT(vals.get_int64("IntVar") == 36);
ASSERT_THROWS_ANY([[maybe_unused]] auto v = vals.get_int64("Float"));
ASSERT_THROWS_ANY([[maybe_unused]] auto v = vals.get_int64("String"));
ASSERT(vals.get_float64("Float") == 34.5);
ASSERT_THROWS_ANY([[maybe_unused]] auto v = vals.get_float64("Int"));
ASSERT_THROWS_ANY([[maybe_unused]] auto v = vals.get_float64("IntVar"));
ASSERT_THROWS_ANY([[maybe_unused]] auto v = vals.get_float64("String"));
ASSERT(vals.get_string("String") == "string!");
ASSERT_THROWS_ANY([[maybe_unused]] auto v = vals.get_string("Int"));
ASSERT_THROWS_ANY([[maybe_unused]] auto v = vals.get_string("IntVar"));
ASSERT_THROWS_ANY([[maybe_unused]] auto v = vals.get_string("Float"));
vals.remove_value("IntVar");
names = {"Float", "Int", "String"};
ASSERT(vals.get_size() == 3);
ASSERT(sort(vals.get_names()) == names);
ASSERT(!vals.has_value("IntVar"));
ASSERT(vals.has_value("Float"));
ASSERT(vals.has_value("Int"));
ASSERT(vals.has_value("String"));
vals.clear();
names = {};
ASSERT(vals.get_size() == 0);
ASSERT(sort(vals.get_names()) == names);
ASSERT(!vals.has_value("IntVar"));
ASSERT(!vals.has_value("Float"));
ASSERT(!vals.has_value("Int"));
ASSERT(!vals.has_value("String"));
}
int main()
{
test_empty();
test_basic();
}

View File

@@ -1,26 +0,0 @@
#include <nvbench/params.cuh>
#include "test_asserts.cuh"
void test_basic()
{
nvbench::params params;
params.add_string_param("Axis 1", "Value 1");
params.add_int64_param("Axis 2", 2);
params.add_float64_param("Axis 3", 3.);
params.add_string_param("Axis 4", "Value 4");
params.add_int64_param("Axis 5", 5);
params.add_float64_param("Axis 6", 6.);
ASSERT(params.get_string_param("Axis 1") == "Value 1");
ASSERT(params.get_int64_param("Axis 2") == 2);
ASSERT(params.get_float64_param("Axis 3") == 3.);
ASSERT(params.get_string_param("Axis 4") == "Value 4");
ASSERT(params.get_int64_param("Axis 5") == 5);
ASSERT(params.get_float64_param("Axis 6") == 6.);
}
int main()
{
test_basic();
}

View File

@@ -7,22 +7,17 @@
// Subclass to gain access to protected members for testing:
struct state_tester : public nvbench::state
{
using params_type = nvbench::state::params_type;
state_tester()
: nvbench::state()
{}
explicit state_tester(params_type params)
: nvbench::state{std::move(params)}
{}
template <typename... Args>
void set_param(Args &&...args)
template <typename T>
void set_param(std::string name, T &&value)
{
this->state::set_param(std::forward<Args>(args)...);
this->state::m_axis_values.set_value(std::move(name),
nvbench::named_values::value_type{
std::forward<T>(value)});
}
const auto &get_params() const { return m_params; }
};
void test_params()
@@ -36,13 +31,6 @@ void test_params()
ASSERT(state1.get_int64("TestInt") == nvbench::int64_t{22});
ASSERT(state1.get_float64("TestFloat") == nvbench::float64_t{3.14});
ASSERT(state1.get_string("TestString") == "A String!");
// Construct a state from the parameter map built above:
state_tester state2{state1.get_params()};
ASSERT(state2.get_int64("TestInt") == nvbench::int64_t{22});
ASSERT(state2.get_float64("TestFloat") == nvbench::float64_t{3.14});
ASSERT(state2.get_string("TestString") == "A String!");
}
int main() { test_params(); }

View File

@@ -29,3 +29,25 @@
exit(EXIT_FAILURE); \
} \
} while (false)
#define ASSERT_THROWS_ANY(expr) \
do \
{ \
bool threw = false; \
try \
{ \
expr; \
} \
catch (...) \
{ \
threw = true; \
} \
if (!threw) \
{ \
fmt::print("{}:{}: Expression expected exception: '{}'.", \
__FILE__, \
__LINE__, \
#expr); \
exit(EXIT_FAILURE); \
} \
} while (false)