/* This file is part of Ingen. Copyright 2007-2017 David Robillard Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. Ingen 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 Affero General Public License for details. You should have received a copy of the GNU Affero General Public License along with Ingen. If not, see . */ #include "ingen/Atom.hpp" #include "ingen/Clock.hpp" #include "ingen/Configuration.hpp" #include "ingen/EngineBase.hpp" #include "ingen/Forge.hpp" #include "ingen/Parser.hpp" #include "ingen/World.hpp" #include "ingen/runtime_paths.hpp" #include #include #include #include #include #include #include #include namespace ingen::bench { namespace { std::unique_ptr world; void ingen_try(bool cond, const char* msg) { if (!cond) { std::cerr << "ingen: Error: " << msg << "\n"; world.reset(); exit(EXIT_FAILURE); } } std::string real_path(const char* path) { char* const c_real_path = realpath(path, nullptr); std::string result(c_real_path ? c_real_path : ""); free(c_real_path); return result; } int run(int argc, char** argv) { // Create world try { world = std::make_unique(nullptr, nullptr, nullptr); world->conf().add( "output", "output", 'O', "File to write benchmark output", ingen::Configuration::SESSION, world->forge().String, Atom()); world->load_configuration(argc, argv); } catch (std::exception& e) { std::cout << "ingen: " << e.what() << "\n"; return EXIT_FAILURE; } // Get mandatory command line arguments const Atom& load = world->conf().option("load"); const Atom& out = world->conf().option("output"); if (!load.is_valid() || !out.is_valid()) { std::cerr << "Usage: ingen_bench --load START_GRAPH --output OUT_FILE\n"; return EXIT_FAILURE; } // Get start graph and output file options const std::string start_graph = real_path(static_cast(load.get_body())); const std::string out_file = static_cast(out.get_body()); if (start_graph.empty()) { std::cerr << "error: initial graph '" << static_cast(load.get_body()) << "' does not exist\n"; return EXIT_FAILURE; } // Load modules ingen_try(world->load_module("server"), "Unable to load server module"); // Initialise engine ingen_try(!!world->engine(), "Unable to create engine"); world->engine()->init(48000.0, 4096, 4096); world->engine()->activate(); // Load graph if (!world->parser()->parse_file(*world, *world->interface(), start_graph)) { std::cerr << "error: failed to load initial graph " << start_graph << "\n"; return EXIT_FAILURE; } world->engine()->flush_events(std::chrono::milliseconds(20)); // Run benchmark // TODO: Set up real-time scheduling for this and worker threads const ingen::Clock clock; const uint32_t n_test_frames = 1 << 20; const uint32_t block_length = 4096; const uint64_t t_start = clock.now_microseconds(); for (uint32_t i = 0; i < n_test_frames; i += block_length) { world->engine()->advance(block_length); world->engine()->run(block_length); //world->engine()->main_iteration(); } const uint64_t t_end = clock.now_microseconds(); // Write log output const std::unique_ptr log{fopen(out_file.c_str(), "a"), &fclose}; if (ftell(log.get()) == 0) { fprintf(log.get(), "# n_threads\trun_time\treal_time\n"); } fprintf(log.get(), "%u\t%f\t%f\n", world->conf().option("threads").get(), static_cast(t_end - t_start) / 1000000.0, (n_test_frames / 48000.0)); // Shut down world->engine()->deactivate(); return EXIT_SUCCESS; } } // namespace } // namespace ingen::bench int main(int argc, char** argv) { ingen::set_bundle_path_from_code( reinterpret_cast(&ingen::bench::ingen_try)); return ingen::bench::run(argc, argv); }