diff --git a/README.md b/README.md index d065ff7..1186a61 100644 --- a/README.md +++ b/README.md @@ -545,8 +545,11 @@ Command Line Options * --loadavg-target (-g) LOADAVG * Specify load average target for dynamic worker threads. Threads will be started or stopped subject to the upper limit imposed - by thread-factor and thread-count until the load average is within - +/- 0.5 of LOADAVG. + by thread-factor, thread-min and thread-count until the load average + is within +/- 0.5 of LOADAVG. +* --thread-min (-G) COUNT + * Specify minimum number of worker threads for scanning. + Ignored unless -g option is used to specify a target load. * --scan-mode (-m) MODE * Specify extent scanning algorithm. Default mode is 0. diff --git a/include/crucible/task.h b/include/crucible/task.h index 755eae2..ed60181 100644 --- a/include/crucible/task.h +++ b/include/crucible/task.h @@ -58,6 +58,9 @@ namespace crucible { // Blocks until the running thread count reaches this number static void set_thread_count(size_t threads); + // Sets minimum thread count when load average tracking enabled + static void set_thread_min_count(size_t min_threads); + // Calls set_thread_count with default static void set_thread_count(); diff --git a/lib/task.cc b/lib/task.cc index 8a981e4..4bdaeec 100644 --- a/lib/task.cc +++ b/lib/task.cc @@ -43,6 +43,7 @@ namespace crucible { condition_variable m_condvar; list> m_queue; size_t m_thread_max; + size_t m_thread_min = 0; set> m_threads; shared_ptr m_load_tracking_thread; double m_load_target = 0; @@ -56,6 +57,7 @@ namespace crucible { void start_threads_nolock(); void start_stop_threads(); void set_thread_count(size_t thread_max); + void set_thread_min_count(size_t thread_min); void adjust_thread_count(); size_t calculate_thread_count_nolock(); void set_loadavg_target(double target); @@ -269,7 +271,7 @@ namespace crucible { m_thread_target = min(max(0.0, m_thread_target), double(m_configured_thread_max)); // Convert to integer but keep within range - const size_t rv = min(size_t(ceil(m_thread_target)), m_configured_thread_max); + const size_t rv = max(m_thread_min, min(size_t(ceil(m_thread_target)), m_configured_thread_max)); return rv; } @@ -306,6 +308,22 @@ namespace crucible { s_tms->set_thread_count(thread_max); } + void + TaskMasterState::set_thread_min_count(size_t thread_min) + { + unique_lock lock(m_mutex); + m_thread_min = thread_min; + lock.unlock(); + adjust_thread_count(); + start_stop_threads(); + } + + void + TaskMaster::set_thread_min_count(size_t thread_min) + { + s_tms->set_thread_min_count(thread_min); + } + void TaskMasterState::loadavg_thread_fn() { diff --git a/src/bees.cc b/src/bees.cc index 2bf4914..08c3fd7 100644 --- a/src/bees.cc +++ b/src/bees.cc @@ -45,6 +45,7 @@ do_cmd_help(char *argv[]) "\t-h, --help\t\tShow this help\n" "\t-c, --thread-count\tWorker thread count (default CPU count * factor)\n" "\t-C, --thread-factor\tWorker thread factor (default " << BEES_DEFAULT_THREAD_FACTOR << ")\n" + "\t-G, --thread-min\t\tMinimum worker thread count with load average target (default 0)\n" "\t-g, --loadavg-target\t\tTarget load average for worker threads (default is no target)\n" "\t-m, --scan-mode\t\tScanning mode (0..2, default 0)\n" "\t-t, --timestamps\tShow timestamps in log output (default)\n" @@ -653,6 +654,7 @@ bees_main(int argc, char *argv[]) bool chatter_prefix_timestamp = true; double thread_factor = 0; unsigned thread_count = 0; + unsigned thread_min = 0; double load_target = 0; // Parse options @@ -661,18 +663,19 @@ bees_main(int argc, char *argv[]) int option_index = 0; static const struct option long_options[] = { { "thread-factor", required_argument, NULL, 'C' }, + { "thread-min", required_argument, NULL, 'G' }, { "strip-paths", no_argument, NULL, 'P' }, { "no-timestamps", no_argument, NULL, 'T' }, { "thread-count", required_argument, NULL, 'c' }, - { "help", no_argument, NULL, 'h' }, { "loadavg-target", required_argument, NULL, 'g' }, + { "help", no_argument, NULL, 'h' }, { "scan-mode", required_argument, NULL, 'm' }, { "absolute-paths", no_argument, NULL, 'p' }, { "timestamps", no_argument, NULL, 't' }, { "verbose", required_argument, NULL, 'v' }, }; - c = getopt_long(argc, argv, "C:PTc:hg:m:ptv:", long_options, &option_index); + c = getopt_long(argc, argv, "C:G:PTc:hg:m:ptv:", long_options, &option_index); if (-1 == c) { break; } @@ -682,6 +685,9 @@ bees_main(int argc, char *argv[]) case 'C': thread_factor = stod(optarg); break; + case 'G': + thread_min = stoul(optarg); + break; case 'P': crucible::set_relative_path(cwd); break; @@ -748,10 +754,12 @@ bees_main(int argc, char *argv[]) if (load_target != 0) { BEESLOGNOTICE("setting load average target to " << load_target); + BEESLOGNOTICE("setting worker thread pool minimum size to " << thread_min); + TaskMaster::set_thread_min_count(thread_min); } TaskMaster::set_loadavg_target(load_target); - BEESLOGNOTICE("setting worker thread pool maximum size to " << load_target); + BEESLOGNOTICE("setting worker thread pool maximum size to " << thread_count); TaskMaster::set_thread_count(thread_count); // Create a context and start crawlers