summaryrefslogtreecommitdiff
path: root/bench/bench_window.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'bench/bench_window.cpp')
-rw-r--r--bench/bench_window.cpp324
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();
+}