From a877624b6f46199d9f817fce5f4dfd264d815b78 Mon Sep 17 00:00:00 2001 From: Chuck Yount Date: Wed, 21 Aug 2019 15:01:28 -0700 Subject: [PATCH] Add option to set min auto-tuner trial time. --- src/common/common_utils.cpp | 2 +- src/kernel/lib/auto_tuner.cpp | 48 +++++++++++++++++++---------------- src/kernel/lib/auto_tuner.hpp | 1 - src/kernel/lib/settings.cpp | 5 ++++ src/kernel/lib/settings.hpp | 1 + src/kernel/lib/utils.cpp | 42 +++++++++++++++++++++++++++++- src/kernel/lib/utils.hpp | 19 ++++++++++++++ src/kernel/yask_main.cpp | 2 +- 8 files changed, 94 insertions(+), 26 deletions(-) diff --git a/src/common/common_utils.cpp b/src/common/common_utils.cpp index cde8dec0..6cb82a63 100644 --- a/src/common/common_utils.cpp +++ b/src/common/common_utils.cpp @@ -43,7 +43,7 @@ namespace yask { // for numbers above 9 (at least up to 99). // Format: "major.minor.patch". - const string version = "3.01.05"; + const string version = "3.02.00"; string yask_get_version_string() { return version; diff --git a/src/kernel/lib/auto_tuner.cpp b/src/kernel/lib/auto_tuner.cpp index dfea19ae..778a4e72 100644 --- a/src/kernel/lib/auto_tuner.cpp +++ b/src/kernel/lib/auto_tuner.cpp @@ -150,14 +150,14 @@ namespace yask { STATE_VARS(this); if (tune_mini_blks()) DEBUG_MSG(_name << ": best-mini-block-size: " << - target_sizes().makeDimValStr(" * ")); + target_sizes().removeDim(step_posn).makeDimValStr(" * ")); else DEBUG_MSG(_name << ": best-block-size: " << - target_sizes().makeDimValStr(" * ") << endl << + target_sizes().removeDim(step_posn).makeDimValStr(" * ") << endl << _name << ": mini-block-size: " << - _settings->_mini_block_sizes.makeDimValStr(" * ")); + _settings->_mini_block_sizes.removeDim(step_posn).makeDimValStr(" * ")); DEBUG_MSG(_name << ": sub-block-size: " << - _settings->_sub_block_sizes.makeDimValStr(" * ")); + _settings->_sub_block_sizes.removeDim(step_posn).makeDimValStr(" * ")); } // Access settings. @@ -238,7 +238,7 @@ namespace yask { timer.clear(); idx_t steps = steps_done; steps_done = 0; - + // Leave if done. if (done) return; @@ -247,15 +247,22 @@ namespace yask { if (!nullop) return; - // Cumulative stats. + // Cumulative stats and rate. csteps += steps; ctime += etime; - + double rate = (ctime > 0.) ? (double(csteps) / ctime) : 0.; + double min_secs = _settings->_tuner_min_secs; + TRACE_MSG(_name << " eval() callback: " << steps << " step(s) in " << + etime << " secs; " << csteps << " step(s) in " << + ctime << " secs (" << rate << + " steps/sec) cumulative; best-rate = " << best_rate << + "; min-secs = " << min_secs); + // Still in warmup? if (in_warmup) { // Warmup not done? - if (ctime < warmup_secs && csteps < warmup_steps) + if (ctime < max(warmup_secs, min_secs) && csteps < warmup_steps) return; // Done. @@ -294,12 +301,7 @@ namespace yask { return; } - // Calc perf. - double rate = (ctime > 0.) ? (double(csteps) / ctime) : 0.; - TRACE_MSG(_name << ": " << - makeNumStr(rate) << " steps/sec (" << - csteps << " steps(s) in " << makeNumStr(ctime) << - " secs)"); + // Determine whether we've done enough. bool rate_ok = false; // If the current rate is much less than the best, @@ -315,14 +317,6 @@ namespace yask { if (!rate_ok) return; - // Print progress and reset vars for next time. - DEBUG_MSG(_name << ": search-dist=" << radius << ": " << - makeNumStr(rate) << " steps/sec (" << - csteps << " steps(s) in " << makeNumStr(ctime) << - " secs) with size " << target_sizes().makeDimValStr(" * ")); - csteps = 0; - ctime = 0.; - // Save result. results[target_sizes()] = rate; bool is_better = rate > best_rate; @@ -332,6 +326,16 @@ namespace yask { better_neigh_found = true; } + // Print progress and reset vars for next time. + DEBUG_MSG(_name << ": search-dist=" << radius << ": " << + makeNumStr(rate) << " steps/sec (" << + csteps << " steps(s) in " << makeNumStr(ctime) << + " secs) with size " << + target_sizes().removeDim(step_posn).makeDimValStr(" * ") << + (is_better ? " -- best so far" : "")); + csteps = 0; + ctime = 0.; + // At this point, we have gathered perf info on the current settings. // Now, we need to determine next unevaluated point in search space. while (true) { diff --git a/src/kernel/lib/auto_tuner.hpp b/src/kernel/lib/auto_tuner.hpp index 2c28169b..a01edae7 100644 --- a/src/kernel/lib/auto_tuner.hpp +++ b/src/kernel/lib/auto_tuner.hpp @@ -51,7 +51,6 @@ namespace yask { double warmup_steps = 100; double warmup_secs = 0.5; // end warmup when either warmup_steps OR warmup_secs is reached. idx_t min_steps = 100; - double min_secs = 0.25; // eval when either min_steps OR min_secs is reached. double cutoff = 0.8; // can stop eval if current rate < best rate * cutoff; idx_t max_radius = 8; // starting search radius. idx_t min_dist = 4; // min distance to move in any direction per eval. diff --git a/src/kernel/lib/settings.cpp b/src/kernel/lib/settings.cpp index bb265eb0..6ff9f65b 100644 --- a/src/kernel/lib/settings.cpp +++ b/src/kernel/lib/settings.cpp @@ -424,6 +424,11 @@ namespace yask { "Adjust block sizes *during* normal operation to tune for performance. " "May cause varying performance between steps.", _do_auto_tune)); + parser.add_option(new CommandLineParser::DoubleOption + ("auto_tune_min_secs", + "Minimum seconds to run trial during auto-tuning for trial settings to be " + "considered better than the existing best.", + _tuner_min_secs)); parser.add_option(new CommandLineParser::BoolOption ("auto_tune_mini_blocks", "Apply the auto-tuner to mini-block sizes instead of block sizes. " diff --git a/src/kernel/lib/settings.hpp b/src/kernel/lib/settings.hpp index 0e5a25cb..a4304462 100644 --- a/src/kernel/lib/settings.hpp +++ b/src/kernel/lib/settings.hpp @@ -260,6 +260,7 @@ namespace yask { bool _do_auto_tune = false; // whether to do auto-tuning. bool _tune_mini_blks = false; // auto-tune mini-blks instead of blks. bool _allow_pack_tuners = false; // allow per-pack tuners when possible. + double _tuner_min_secs = 0.25; // min time to run tuner for new better setting. // Debug. bool force_scalar = false; // Do only scalar ops. diff --git a/src/kernel/lib/utils.cpp b/src/kernel/lib/utils.cpp index ec16749d..e9d05f6f 100644 --- a/src/kernel/lib/utils.cpp +++ b/src/kernel/lib/utils.cpp @@ -428,6 +428,28 @@ namespace yask { return false; } + // Get one double value from args[argi]. + // On failure, print msg using string from args[argi-1] and exit. + // On success, increment argi and return value. + double CommandLineParser::OptionBase::_double_val(const vector& args, + int& argi) + { + if (size_t(argi) >= args.size() || args[argi].length() == 0) { + THROW_YASK_EXCEPTION("Error: no argument for option '" + args[argi - 1] + "'"); + } + + const char* nptr = args[argi].c_str(); + char* endptr = 0; + double val = strtod(nptr, &endptr); + if (val == HUGE_VAL || val == -HUGE_VAL || *endptr != '\0') { + THROW_YASK_EXCEPTION("Error: argument for option '" + args[argi - 1] + + "' is not a valid floating-point number"); + } + + argi++; + return val; + } + // Get one idx_t value from args[argi]. // On failure, print msg using string from args[argi-1] and exit. // On success, increment argi and return value. @@ -472,11 +494,29 @@ namespace yask { (_val ? "true" : "false") << "." << endl; } + // Check for a double option. + bool CommandLineParser::DoubleOption::check_arg(const std::vector& args, + int& argi) { + if (_check_arg(args, argi, _name)) { + _val = _double_val(args, argi); + return true; + } + return false; + } + + // Print help on a double option. + void CommandLineParser::DoubleOption::print_help(ostream& os, + int width) const { + _print_help(os, _name + " ", width); + os << _help_leader << _current_value_str << + _val << "." << endl; + } + // Check for an int option. bool CommandLineParser::IntOption::check_arg(const std::vector& args, int& argi) { if (_check_arg(args, argi, _name)) { - _val = (int)_idx_val(args, argi); // TODO: check for under/overflow. + _val = (int)_idx_val(args, argi); // TODO: check for over/underflow. return true; } return false; diff --git a/src/kernel/lib/utils.hpp b/src/kernel/lib/utils.hpp index 97155684..1ad2be10 100644 --- a/src/kernel/lib/utils.hpp +++ b/src/kernel/lib/utils.hpp @@ -345,6 +345,10 @@ namespace yask { virtual bool _check_arg(const std::vector& args, int& argi, const std::string& str) const; + // Get one double value from args[argi++]. + // Exit on failure. + virtual double _double_val(const std::vector& args, int& argi); + // Get one idx_t value from args[argi++]. // Exit on failure. virtual idx_t _idx_val(const std::vector& args, int& argi); @@ -407,6 +411,21 @@ namespace yask { virtual bool check_arg(const std::vector& args, int& argi); }; + // An allowed double option. + class DoubleOption : public OptionBase { + double& _val; + + public: + DoubleOption(const std::string& name, + const std::string& help_msg, + double& val) : + OptionBase(name, help_msg), _val(val) { } + + virtual void print_help(std::ostream& os, + int width) const; + virtual bool check_arg(const std::vector& args, int& argi); + }; + // An allowed idx_t option. class IdxOption : public OptionBase { idx_t& _val; diff --git a/src/kernel/yask_main.cpp b/src/kernel/yask_main.cpp index 0970e3b7..fda56817 100644 --- a/src/kernel/yask_main.cpp +++ b/src/kernel/yask_main.cpp @@ -272,7 +272,7 @@ int main(int argc, char** argv) yk_factory kfac; yask_output_factory yof; - // Parse options once just to get vars needed for env. + // Parse custom options once just to get vars needed for env. MySettings opts1(nullptr); opts1.parse(argc, argv);