6 #include <catch2/catch_test_macros.hpp>
22 [[nodiscard]]
int array_dimension()
const {
38 size_t num_variables()
const {
50 static constexpr
bool optional =
true;
57 static constexpr
bool optional =
true;
62 template <
typename Identifier>
65 using base_type::base_type;
69 [[nodiscard]] field::A::type& a() {
70 return this->
template get<field::A>();
74 using owning_handle = handle_interface<owning_identifier<storage>>;
77 TEST_CASE(
"Tag type with array_dimension and without num_variables",
"[Neuron][data_structures]") {
78 GIVEN(
"A standalone soa container") {
80 THEN(
"Can we create a handle to a row in it") {
86 TEST_CASE(
"Multi-threaded calls to nrn_ensure_model_data_are_sorted()",
87 "[Neuron][data_structures]") {
88 GIVEN(
"An initialised model (albeit empty for the moment)") {
89 REQUIRE(
hoc_oc(
"create s\nfinitialize(-65)\n") == 0);
91 THEN(
"Call nrn_ensure_model_data_are_sorted multiple times concurrently") {
95 constexpr
auto num_threads = 7;
96 std::vector<std::thread> threads;
98 std::mutex token_mutex{};
99 std::vector<neuron::model_sorted_token> tokens;
103 for (
auto i = 0;
i < num_threads; ++
i) {
104 threads.emplace_back([&tokens, &token_mutex]() {
106 std::unique_lock _{token_mutex};
107 tokens.push_back(token);
111 for (
auto& thread: threads) {
114 REQUIRE(tokens.size() == num_threads);
116 REQUIRE(
hoc_oc(
"delete_section()") == 0);
121 TEST_CASE(
"soa::get_array_dims",
"[Neuron][data_structures]") {
124 data.set_field_status<field::DOn>(
true);
125 data.set_field_status<field::DOff>(
false);
136 CHECK(
data.template get_array_dims<field::DOff>(0) == 1ul);
137 CHECK(
data.template get_array_dims<field::DOn>(0) == 1ul);
140 TEST_CASE(
"soa::get_num_variables",
"[Neuron][data_structures]") {
143 data.set_field_status<field::DOn>(
true);
144 data.set_field_status<field::DOff>(
false);
148 CHECK(
data.get_num_variables<field::C>() ==
c.num_variables());
149 CHECK(
data.get_num_variables<field::DOff>() == 1ul);
150 CHECK(
data.get_num_variables<field::DOn>() == 1ul);
153 TEST_CASE(
"defer delete storage pointer",
"[Neuron][internal][data_structures]") {
160 CHECK(usage_after.size - usage_before.size > 0);
161 CHECK(usage_after.capacity > 0);
162 CHECK(usage_before.size <= usage_before.capacity);
163 CHECK(usage_after.size <= usage_after.capacity);
166 template <
class Tag,
class Storage>
168 std::size_t local_size = 0ul;
169 auto tag =
data.template get_tag<Tag>();
177 TEST_CASE(
"container memory usage",
"[Neuron][internal][data_structures]") {
179 data.set_field_status<field::DOn>(
true);
180 data.set_field_status<field::DOff>(
false);
182 std::size_t row_size = compute_row_size<field::A>(
data) + compute_row_size<field::B>(
data) +
183 compute_row_size<field::C>(
data) + compute_row_size<field::DOn>(
data);
189 auto n_rows =
data.size();
193 CHECK(usage.heavy_data.size == row_size * n_rows);
194 CHECK(usage.heavy_data.size <= usage.heavy_data.capacity);
196 CHECK(usage.stable_identifiers.size % n_rows == 0);
197 CHECK(usage.stable_identifiers.size >= n_rows *
sizeof(std::size_t*));
198 CHECK(usage.stable_identifiers.size < n_rows * 4 *
sizeof(std::size_t*));
199 CHECK(usage.stable_identifiers.size <= usage.stable_identifiers.capacity);
202 TEST_CASE(
"model memory usage",
"[Neuron][internal][data_structures]") {
210 std::vector<neuron::container::Mechanism::Variable>{{
"a", 1},
218 std::vector<neuron::container::Mechanism::Variable>{{
"a", 1}});
223 CHECK(usage.nodes.heavy_data.size > 0);
224 CHECK(usage.nodes.heavy_data.size <= usage.nodes.heavy_data.capacity);
225 CHECK(usage.nodes.stable_identifiers.size > 0);
226 CHECK(usage.nodes.stable_identifiers.size <= usage.nodes.stable_identifiers.capacity);
228 CHECK(usage.mechanisms.heavy_data.size > 0);
229 CHECK(usage.mechanisms.heavy_data.size <= usage.mechanisms.heavy_data.capacity);
230 CHECK(usage.mechanisms.stable_identifiers.size > 0);
231 CHECK(usage.mechanisms.stable_identifiers.size <= usage.mechanisms.stable_identifiers.capacity);
234 TEST_CASE(
"cache::model memory_usage",
"[Neuron][internal][data_structures]") {
274 TEST_CASE(
"total memory usage",
"[Neuron][internal][data_structures]") {
277 CHECK(total.size == (7 * 8) / 2);
278 CHECK(total.capacity == total.size + 7 * 10);
281 TEST_CASE(
"memory usage summary",
"[Neuron][data_structures]") {
284 auto total = usage.compute_total();
286 size_t summary_total = summary.required + summary.convenient + summary.oversized +
288 CHECK(summary.required <= total.size);
289 CHECK(summary.convenient <= total.size);
290 CHECK(summary.leaked <= total.size);
291 CHECK(summary.oversized == total.capacity - total.size);
292 CHECK(summary_total == total.capacity);
int hoc_oc(const char *buf)
std::optional< Model > model
handle_interface< owning_identifier< storage > > owning_handle
Owning handle to a Mechanism instance.
std::vector< void * > * defer_delete_storage
Defer deleting pointers to deallocated memory.
VectorMemoryUsage compute_defer_delete_storage_size()
size_t get_num_variables(T const &t)
std::string format_memory(size_t bytes)
Utility to format memory as a human readable string.
cache::ModelMemoryUsage memory_usage(const std::optional< neuron::cache::Model > &model)
Model & model()
Access the global Model instance.
neuron::model_sorted_token nrn_ensure_model_data_are_sorted()
Ensure neuron::container::* data are sorted.
container::Mechanism::storage & add_mechanism(int type, Args &&... args)
Create a structure to hold the data of a new Mechanism.
container::Node::storage & node_data()
Access the structure containing the data of all Nodes.
Base class defining the public API of Mechanism handles.
Overall SoA datastructures related memory usage.
Memory usage of a neuron::Model.
Memory usage of a storage/soa container.
Size and capacity in bytes.
Memory usage of a neuron::cache::Model.
VectorMemoryUsage compute_total() const
Struct used to index SoAoS data, such as array range variables.
Base class for neuron::container::soa<...> handles.
Utility for generating SOA data structures.
void mark_as_unsorted()
Tell the container it is no longer sorted.
neuron::container::MemoryUsage dummy_memory_usage()
TEST_CASE("Tag type with array_dimension and without num_variables", "[Neuron][data_structures]")
std::size_t compute_row_size(const Storage &data)