diff options
author | Benji Dial <benji@benjidial.net> | 2023-05-29 16:36:19 -0400 |
---|---|---|
committer | Benji Dial <benji@benjidial.net> | 2023-05-29 16:36:19 -0400 |
commit | 97c79ff771d4993e322d0d6c44f265180797b2eb (patch) | |
tree | 5513cf25721cf21c06efd913ed2f82b980e3cb24 /bench/bench_window.cpp | |
parent | 338549f9cd49fa0f3001826c6605663fa6dd019b (diff) | |
download | lib94-97c79ff771d4993e322d0d6c44f265180797b2eb.tar.gz |
a whole lot more
Diffstat (limited to 'bench/bench_window.cpp')
-rw-r--r-- | bench/bench_window.cpp | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/bench/bench_window.cpp b/bench/bench_window.cpp new file mode 100644 index 0000000..bcdc12d --- /dev/null +++ b/bench/bench_window.cpp @@ -0,0 +1,324 @@ +#include <fstream> + +#include "bench_window.hpp" +#include "main.hpp" + +bench_window::bench_window() + : runner_stop_now(false), + runner_stop_on_death(true), + runner_stop_on_win(true), + runner_update_ui(true), + control_box(Gtk::Orientation::VERTICAL), + new_round_button("new round"), + single_step_button("single step"), + start_button("start"), + stop_button("stop"), + draw_each_step_toggle("draw each step"), + pause_on_death_toggle("pause on death"), + pause_on_win_toggle("pause on win"), + add_warrior_button("add warrior"), + remove_warrior_button("remove warrior"), + runner({}), + runner_active(false) { + + warrior_list_store = Gtk::TreeStore::create(warrior_list_columns); + instructions_store = Gtk::TreeStore::create(instructions_columns); + + warrior_list_view.set_model(warrior_list_store); + instructions_view.set_model(instructions_store); + + warrior_list_view.get_selection()->set_mode(Gtk::SelectionMode::SINGLE); + instructions_view.get_selection()->set_mode(Gtk::SelectionMode::NONE); + + warrior_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &bench_window::update_buttons)); + + warrior_list_view.append_column("name", warrior_list_columns.warrior_name); + warrior_list_view.append_column("#p", warrior_list_columns.processes); + warrior_list_view.append_column("pc", warrior_list_columns.next_pc); + + instructions_view.append_column("", instructions_columns.address); + instructions_view.append_column("", instructions_columns.instruction); + + for (lib94::number_t i = 0; i < LIB94_CORE_SIZE; ++i) { + auto row = instructions_store->append(); + (*row)[instructions_columns.address] = i; + } + + update_ui(); + + draw_each_step_toggle.activate(); + pause_on_death_toggle.activate(); + pause_on_win_toggle.activate(); + + new_round_button.signal_clicked().connect(sigc::mem_fun(*this, &bench_window::on_click_new_round)); + single_step_button.signal_clicked().connect(sigc::mem_fun(*this, &bench_window::on_click_single_step)); + start_button.signal_clicked().connect(sigc::mem_fun(*this, &bench_window::on_click_start)); + stop_button.signal_clicked().connect(sigc::mem_fun(*this, &bench_window::on_click_stop)); + add_warrior_button.signal_clicked().connect(sigc::mem_fun(*this, &bench_window::on_click_add_warrior)); + remove_warrior_button.signal_clicked().connect(sigc::mem_fun(*this, &bench_window::on_click_remove_warrior)); + + draw_each_step_toggle.signal_toggled().connect(sigc::mem_fun(*this, &bench_window::on_toggle_draw_each_step)); + pause_on_death_toggle.signal_toggled().connect(sigc::mem_fun(*this, &bench_window::on_toggle_pause_on_death)); + pause_on_win_toggle.signal_toggled().connect(sigc::mem_fun(*this, &bench_window::on_toggle_pause_on_win)); + + control_box.append(new_round_button); + control_box.append(single_step_button); + control_box.append(start_button); + control_box.append(stop_button); + control_box.append(draw_each_step_toggle); + control_box.append(pause_on_death_toggle); + control_box.append(pause_on_win_toggle); + control_box.append(add_warrior_button); + control_box.append(remove_warrior_button); + + warrior_list_scroll.set_child(warrior_list_view); + warrior_list_scroll.set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC); + warrior_list_scroll.set_vexpand(); + + control_box.append(warrior_list_scroll); + + control_box.append(core_rate_label); + control_box.append(core_render_label); + + instructions_scroll.set_child(instructions_view); + instructions_scroll.set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC); + + control_box.set_size_request(200, -1); + core.set_expand(); + instructions_scroll.set_size_request(200, -1); + + main_box.append(control_box); + main_box.append(core); + main_box.append(instructions_scroll); + + set_child(main_box); + set_title("lib94 bench"); + + runner_update_ui_dispatcher.connect(sigc::mem_fun(*this, &bench_window::update_ui)); + runner_stopping_dispatcher.connect(sigc::mem_fun(*this, &bench_window::on_runner_stopping)); +} + +void bench_window::add_modified_for_instruction_view(std::set<lib94::number_t> the_set) { + for (lib94::number_t n : the_set) + modified_addresses_for_instructions_view.insert(n); +} + +const lib94::warrior *bench_window::do_step() { + auto time = std::chrono::system_clock::now(); + last_core_step_distance = time - last_core_step_start; + last_core_step_start = time; + + const lib94::warrior *result = lib94::single_step(); + + core.mut.lock(); + core.age_all(); + core.add_new_writes(lib94::get_written_addresses()); + core.add_new_reads(lib94::get_read_addresses()); + core.add_new_executions(lib94::get_executed_addresses()); + core.mut.unlock(); + + add_modified_for_instruction_view(lib94::get_written_addresses()); + add_modified_for_instruction_view(lib94::get_read_addresses()); + add_modified_for_instruction_view(lib94::get_executed_addresses()); + + lib94::clear_address_sets(); + return result; +} + +void bench_window::runner_main() { + std::chrono::system_clock::time_point last_step = std::chrono::system_clock::now(); + + core_mutex.lock(); + while (!runner_stop_now) { + bool death = do_step() != 0; + + if (runner_stop_on_death && death) + break; + if (runner_stop_on_win && death && lib94::alive_warrior_count() == 1) + break; + if (runner_update_ui) + runner_update_ui_dispatcher.emit(); + + core_mutex.unlock(); + std::this_thread::sleep_until(last_step + time_between_steps); + last_step = std::chrono::system_clock::now(); + core_mutex.lock(); + } + + runner_stopping_dispatcher.emit(); + core_mutex.unlock(); +} + +void bench_window::on_click_single_step() { + do_step(); + update_ui(); +} + +void bench_window::on_click_new_round() { + lib94::clear_core({ + .op = lib94::DAT, + .mod = lib94::F, + .amode = lib94::DIRECT, + .bmode = lib94::DIRECT, + .anumber = 0, + .bnumber = 0 + }); + + lib94::init_round(warriors.data(), warriors.size()); + + core.mut.lock(); + core.age_scale = std::pow(2.0 / 3.0, 1.0 / (float)warriors.size()); + core.clear_all(); + core.mut.unlock(); + + modified_addresses_for_instructions_view.clear(); + for (lib94::number_t i = 0; i < LIB94_CORE_SIZE; ++i) + instructions_store->children()[i][instructions_columns.instruction] + = lib94::instruction_to_string(lib94::get_instruction(i)); + + update_ui(); +} + +void bench_window::on_click_start() { + runner_active = true; + update_ui(); + runner_stop_now = false; + runner = std::thread(sigc::mem_fun(*this, &bench_window::runner_main)); +} + +void bench_window::on_click_stop() { + runner_stop_now = true; +} + +void bench_window::on_toggle_draw_each_step() { + runner_update_ui = draw_each_step_toggle.get_active(); +} + +void bench_window::on_toggle_pause_on_death() { + runner_stop_on_death = pause_on_death_toggle.get_active(); +} + +void bench_window::on_toggle_pause_on_win() { + runner_stop_on_win = pause_on_win_toggle.get_active(); +} + +void bench_window::on_add_warrior_dialog_response(int response_id, Gtk::FileChooserDialog *dialog) { + if (response_id == Gtk::ResponseType::OK) { + + Glib::RefPtr<Gio::File> file = dialog->get_file(); + char *contents; + gsize length; + file->load_contents(contents, length); + + auto w = lib94::compile_warrior(std::string(contents, length)); + + delete contents; + + if (std::holds_alternative<lib94::warrior *>(w)) { + warriors.push_back(std::get<lib94::warrior *>(w)); + on_click_new_round(); + } + + else { + Gtk::MessageDialog *md = new Gtk::MessageDialog(std::string("Failed to compile: ") + std::get<std::string>(w)); + md->set_transient_for(*this); + md->set_modal(); + md->signal_response().connect([md](int) {delete md;}); + md->show(); + } + } + + delete dialog; +} + +void bench_window::on_click_add_warrior() { + Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog("select a warrior"); + + dialog->set_transient_for(*this); + dialog->set_modal(); + dialog->signal_response().connect(sigc::bind(sigc::mem_fun(*this, &bench_window::on_add_warrior_dialog_response), dialog)); + dialog->add_button("add", Gtk::ResponseType::OK); + dialog->add_button("cancel", Gtk::ResponseType::CANCEL); + + Glib::RefPtr<Gtk::FileFilter> text_filter = Gtk::FileFilter::create(); + text_filter->add_mime_type("text/plain"); + text_filter->set_name("text files"); + dialog->add_filter(text_filter); + + Glib::RefPtr<Gtk::FileFilter> any_filter = Gtk::FileFilter::create(); + any_filter->add_pattern("*"); + any_filter->set_name("all files"); + dialog->add_filter(any_filter); + + dialog->show(); +} + +void bench_window::on_click_remove_warrior() { + auto iter = warrior_list_view.get_selection()->get_selected(); + if (iter) { + + while (!(*iter)[warrior_list_columns.warrior]) + iter = iter->parent(); + + const lib94::warrior *w = (*iter)[warrior_list_columns.warrior]; + + for (auto i = warriors.begin(); i != warriors.end(); ++i) + if (*i == w) { + warriors.erase(i); + break; + } + + on_click_new_round(); + + delete w; + + } +} + +void bench_window::update_buttons() { + new_round_button.set_sensitive(!runner_active && warriors.size() > 0); + single_step_button.set_sensitive(!runner_active && lib94::alive_warrior_count() > 0); + start_button.set_sensitive(!runner_active && lib94::alive_warrior_count() > 0); + stop_button.set_sensitive(runner_active); + add_warrior_button.set_sensitive(!runner_active); + remove_warrior_button.set_sensitive(!runner_active && warrior_list_view.get_selection()->get_selected()); +} + +void bench_window::update_ui() { + if (runner_active) + core_mutex.lock(); + + update_buttons(); + + core_render_label.set_text("core render: " + ns_to_string(core.last_draw_time)); + core_rate_label.set_text("core rate: " + hz_to_string(1000000000.0 / (double)last_core_step_distance.count())); + + core.queue_draw(); + + warrior_list_store->clear(); + + for (const lib94::warrior *w : warriors) { + auto w_row = warrior_list_store->append(); + (*w_row)[warrior_list_columns.warrior] = w; + (*w_row)[warrior_list_columns.warrior_name] = w->name; + auto procs = lib94::get_processes(w); + (*w_row)[warrior_list_columns.processes] = procs.size(); + (*w_row)[warrior_list_columns.next_pc] = procs.size() ? std::to_string(procs[0]) : ""; + } + + //warrior_list_view.expand_all(); + + for (lib94::number_t i : modified_addresses_for_instructions_view) + instructions_store->children()[i][instructions_columns.instruction] + = lib94::instruction_to_string(lib94::get_instruction(i)); + modified_addresses_for_instructions_view.clear(); + + if (runner_active) + core_mutex.unlock(); +} + +void bench_window::on_runner_stopping() { + runner.join(); + runner_active = false; + update_ui(); +} |