/* * * Copyright (C) 2024 Brett Terpstra * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "blt/std/utility.h" #include "blt/std/logging.h" #include "blt/std/allocator.h" #include "blt/profiling/profiler_v2.h" #include #include namespace fb { using TYPE = double; class base_t { private: blt::size_t argc_ = 0; protected: TYPE value = 0; public: explicit base_t(blt::size_t argc): argc_(argc) {} [[nodiscard]] inline blt::size_t argc() const { return argc_; } [[nodiscard]] inline TYPE getValue() const { return value; } inline virtual void call(blt::span args) = 0; virtual ~base_t() = default; }; class add_t : public base_t { public: add_t(): base_t(2) {} inline void call(blt::span args) final { value = args[0] + args[1]; } }; class sub_t : public base_t { public: sub_t(): base_t(2) {} inline void call(blt::span args) final { value = args[0] - args[1]; } }; class mul_t : public base_t { public: mul_t(): base_t(2) {} inline void call(blt::span args) final { value = args[0] * args[1]; } }; class div_t : public base_t { public: div_t(): base_t(2) {} inline void call(blt::span args) final { if (args[1] == 0) value = 0; else value = args[0] / args[1]; } }; class value_t : public base_t { public: value_t(): base_t(0) { value = random_value(); } inline void call(blt::span) final {} }; blt::bump_allocator alloc; base_t* create_node_type(type_t i) { switch (i) { case type_t::ADD: return alloc.emplace(); case type_t::SUB: return alloc.emplace(); case type_t::MUL: return alloc.emplace(); case type_t::DIV: return alloc.emplace(); case type_t::VALUE: return alloc.emplace(); default: BLT_ERROR("Hey maybe something weird is going on here"); return nullptr; } } class tree2 { private: struct node_t { base_t* type; std::array children{nullptr}; explicit node_t(type_t type): type(create_node_type(type)) {} void evaluate() { if (type->argc() > 0) { TYPE v1 = children[0]->type->getValue(); TYPE v2 = children[1]->type->getValue(); TYPE d[2]{v1, v2}; type->call(blt::span{d}); } else type->call({}); } double evaluate_tree() { std::stack nodes; std::stack node_stack; nodes.push(this); while (!nodes.empty()) { auto* top = nodes.top(); node_stack.push(top); nodes.pop(); for (blt::size_t i = 0; i < top->type->argc(); i++) nodes.push(top->children[i]); } while (!node_stack.empty()) { node_stack.top()->evaluate(); node_stack.pop(); } return type->getValue(); } ~node_t() { for (blt::size_t i = 0; i < type->argc(); i++) { alloc.destroy(children[i]); alloc.deallocate(children[i]); } alloc.destroy(type); alloc.deallocate(type); } }; node_t* root = nullptr; public: void create(blt::u64 size) { root = alloc.template emplace(random_type()); std::stack> stack; stack.emplace(root, 0); while (!stack.empty()) { auto top = stack.top(); auto* node = top.first; auto depth = top.second; //BLT_WARN("gen type %ld with argc: %ld", node->type, node->argc); stack.pop(); //BLT_TRACE0_STREAM << "Size: " << stack.size() << "\n"; for (blt::size_t i = 0; i < node->type->argc(); i++) { if (depth >= size) { node->children[i] = alloc.template emplace(type_t::VALUE); //BLT_INFO("Skipping due to size, value %lf", node->children[i]->value); continue; } if (choice()) node->children[i] = alloc.template emplace(random_type()); else node->children[i] = alloc.template emplace(random_type_sub()); //BLT_INFO("child %p to %p has type generated %ld with argc %d, value %lf", node->children[i], node, // static_cast(node->children[i]->type), node->children[i]->argc, node->children[i]->value); if (depth < size) stack.emplace(node->children[i], depth + 1); } //BLT_TRACE0_STREAM << "Size: " << stack.size() << "\n"; } // BLT_INFO("We have %ld adds, %ld subs, %ld mul, %ld div, %ld val, == %ld", t1_add, t1_sub, t1_mul, t1_div, t1_val, // t1_add + t1_sub + t1_mul + t1_val + t1_div); } double evaluate() { return root->evaluate_tree(); } ~tree2() { BLT_START_INTERVAL("Tree Destruction", "Inheritance Tree"); alloc.destroy(root); alloc.deallocate(root); BLT_END_INTERVAL("Tree Destruction", "Inheritance Tree"); } }; class tree3 { private: struct node_t { base_t* type = nullptr; node_t** children = nullptr; type_t type_value; explicit node_t(type_t type): type(create_node_type(type)), type_value(type) { if (this->type == nullptr) throw std::bad_alloc(); else if (reinterpret_cast(this->type) % alignof(base_t*) != 0) BLT_WARN("type pointer %p is misaligned, expecting alignment of %ld reminder %ld", this->type, alignof(base_t*), reinterpret_cast(this->type) % alignof(base_t*)); children = alloc.emplace_many(this->type->argc()); for (blt::size_t i = 0; i < this->type->argc(); i++) children[i] = nullptr; if (reinterpret_cast(this->children) % alignof(node_t**) != 0) BLT_WARN("children pointer is misaligned, expecting alignment of %ld remainder %ld", this->children, alignof(node_t**), reinterpret_cast(this->children) % alignof(node_t**)); } void evaluate() const { if (type->argc() > 0) { TYPE v1 = children[0]->type->getValue(); TYPE v2 = children[1]->type->getValue(); TYPE d[2]{v1, v2}; type->call(blt::span{d}); } else type->call({}); } double evaluate_tree() { std::stack nodes; std::stack node_stack; nodes.push(this); while (!nodes.empty()) { auto* top = nodes.top(); node_stack.push(top); nodes.pop(); for (blt::size_t i = 0; i < top->type->argc(); i++) nodes.push(top->children[i]); } while (!node_stack.empty()) { node_stack.top()->evaluate(); node_stack.pop(); } return type->getValue(); } ~node_t() { for (blt::size_t i = 0; i < type->argc(); i++) { alloc.destroy(children[i]); alloc.deallocate(children[i]); } alloc.deallocate(children); alloc.destroy(type); alloc.deallocate(type); } }; node_t* root = nullptr; public: tree3() { // BLT_INFO(alignof(node_t*)); // BLT_TRACE(alignof(node_t*[2])); // BLT_DEBUG(alignof(node_t*[3])); // BLT_INFO(sizeof(node_t*)); // std::exit(0); } void create(blt::u64 size) { root = alloc.template emplace(random_type()); std::stack> stack; stack.emplace(root, 0); while (!stack.empty()) { auto top = stack.top(); auto* node = top.first; auto depth = top.second; //BLT_WARN("gen type %ld with argc: %ld", node->type, node->argc); stack.pop(); //BLT_TRACE0_STREAM << "Size: " << stack.size() << "\n"; for (blt::size_t i = 0; i < node->type->argc(); i++) { if (depth >= size) { node->children[i] = alloc.template emplace(type_t::VALUE); //BLT_INFO("Skipping due to size, value %lf", node->children[i]->value); continue; } if (choice()) node->children[i] = alloc.template emplace(random_type()); else node->children[i] = alloc.template emplace(random_type_sub()); //BLT_INFO("child %p to %p has type generated %ld with argc %d, value %lf", node->children[i], node, // static_cast(node->children[i]->type), node->children[i]->argc, node->children[i]->value); if (depth < size) stack.emplace(node->children[i], depth + 1); } //BLT_TRACE0_STREAM << "Size: " << stack.size() << "\n"; } // BLT_INFO("We have %ld adds, %ld subs, %ld mul, %ld div, %ld val, == %ld", t1_add, t1_sub, t1_mul, t1_div, t1_val, // t1_add + t1_sub + t1_mul + t1_val + t1_div); } double evaluate() { return root->evaluate_tree(); } ~tree3() { BLT_START_INTERVAL("Tree Destruction", "Inheritance Tree v2"); alloc.destroy(root); alloc.deallocate(root); BLT_END_INTERVAL("Tree Destruction", "Inheritance Tree v2"); } }; void run() { constexpr auto size = 512; constexpr auto tree_size = 17; engine.reset(); tree2 love[size]; BLT_START_INTERVAL("Tree Construction", "Inheritance Tree"); for (auto& i : love) i.create(tree_size); BLT_END_INTERVAL("Tree Construction", "Inheritance Tree"); BLT_START_INTERVAL("Tree Evaluation", "Inheritance Tree"); for (auto& i : love) blt::black_box(i.evaluate()); BLT_END_INTERVAL("Tree Evaluation", "Inheritance Tree"); } void run2() { constexpr auto size = 512; constexpr auto tree_size = 17; engine.reset(); tree3 love[size]; BLT_START_INTERVAL("Tree Construction", "Inheritance Tree v2"); for (auto& i : love) i.create(tree_size); BLT_END_INTERVAL("Tree Construction", "Inheritance Tree v2"); BLT_START_INTERVAL("Tree Evaluation", "Inheritance Tree v2"); for (auto& i : love) blt::black_box(i.evaluate()); BLT_END_INTERVAL("Tree Evaluation", "Inheritance Tree v2"); } void test3() { auto cum = new blt::u8[512]; auto v = blt::array::construct(cum, 512); auto& vr = *v; BLT_TRACE("%p", cum); BLT_TRACE(v); BLT_TRACE(*vr); vr[0] = 0; BLT_TRACE(*vr); vr[1] = 0; BLT_TRACE(*vr); vr[5] = 50; BLT_DEBUG(vr[5]); BLT_TRACE(*vr); blt::black_box(v); delete[] cum; run(); run2(); // using testing = blt::size_t; // constexpr blt::size_t INT_SIZE = blt::BLT_2MB_SIZE * 8 / sizeof(testing); // auto** data = new testing*[INT_SIZE]; // // for (blt::size_t i = 0; i < INT_SIZE; i++) // { // data[i] = alloc.emplace(); // *data[i] = 256; // } // // for (blt::size_t i = 0; i < INT_SIZE; i++) // { // alloc.deallocate(data[i]); // auto* blk = alloc.blk(data[i]); // if (*data[i] != 256) // BLT_WARN("Data is not 256 (%d)! %ld || %ld || 0x%lx || 0x%lx pointer %p part of block %p", *data[i], i % blt::BLT_2MB_SIZE, i, i, i % blt::BLT_2MB_SIZE, data[i], blk); // } // delete[] data; } }