diff --git a/NEWS b/NEWS
index 3d5b6268a8b5589aa3074e90a7eed31b53b02e1f..0f46e44bb0ae5dcf8ce562b6400aea4263a09066 100644
--- a/NEWS
+++ b/NEWS
@@ -182,6 +182,12 @@ documents those changes that are of interest to users and administrators.
  -- cgroup plugins - fix two minor memory leaks.
  -- If a node is booting for some job, don't allocate additional jobs to the
     node until the boot completes.
+ -- testsuite - fix job id output in test17.39.
+ -- Modify backfill algorithm to improve performance with large numbers of
+    running jobs. Group running jobs that end in a "similar" time frame using a
+    time window that grows exponentially rather than linearly. After one second
+    of wall time, simulate the termination of all remaining running jobs in
+    order to respond in a reasonable time frame.
 
 * Changes in Slurm 16.05.6
 ==========================
diff --git a/src/plugins/select/cons_res/select_cons_res.c b/src/plugins/select/cons_res/select_cons_res.c
index bc08e2eea5a0c723db873287d4acbce96d096291..6874698c404bd3fbbdb38efe9373399dcef74d9e 100644
--- a/src/plugins/select/cons_res/select_cons_res.c
+++ b/src/plugins/select/cons_res/select_cons_res.c
@@ -1881,15 +1881,20 @@ static int _will_run_test(struct job_record *job_ptr, bitstr_t *bitmap,
 	 * pending job after each one (or a few jobs that end close in time). */
 	if ((rc != SLURM_SUCCESS) &&
 	    ((job_ptr->bit_flags & TEST_NOW_ONLY) == 0)) {
-		int time_window = 0;
+		int time_window = 30;
 		bool more_jobs = true;
+		bool timed_out = false;
+		DEF_TIMERS;
+
 		list_sort(cr_job_list, _cr_job_list_sort);
+		START_TIMER;
 		job_iterator = list_iterator_create(cr_job_list);
 		while (more_jobs) {
 			struct job_record *first_job_ptr = NULL;
 			struct job_record *last_job_ptr = NULL;
 			struct job_record *next_job_ptr = NULL;
 			int overlap, rm_job_cnt = 0;
+
 			while (true) {
 				tmp_job_ptr = list_next(job_iterator);
 				if (!tmp_job_ptr) {
@@ -1908,21 +1913,23 @@ static int _will_run_test(struct job_record *job_ptr, bitstr_t *bitmap,
 				last_job_ptr = tmp_job_ptr;
 				_rm_job_from_res(future_part, future_usage,
 						 tmp_job_ptr, 0);
-				if (rm_job_cnt++ > 20)
+				if ((rm_job_cnt++ > 200) && !timed_out)
 					break;
 				next_job_ptr = list_peek_next(job_iterator);
 				if (!next_job_ptr) {
 					more_jobs = false;
 					break;
+				} else if (timed_out) {
+					continue;
 				} else if (next_job_ptr->end_time >
 				 	   (first_job_ptr->end_time +
 					    time_window)) {
 					break;
 				}
 			}
-			if (!last_job_ptr)
+			if (!last_job_ptr)	/* Should never happen */
 				break;
-			time_window += 60;
+			time_window *= 2;
 			rc = cr_job_test(job_ptr, bitmap, min_nodes,
 					 max_nodes, req_nodes,
 					 SELECT_MODE_WILL_RUN, tmp_cr_type,
@@ -1941,6 +1948,12 @@ static int _will_run_test(struct job_record *job_ptr, bitstr_t *bitmap,
 				}
 				break;
 			}
+			/* After 1 second of iterating over groups of running
+			 * jobs, simulate the termination of all remaining jobs
+			 * in order to determine if pending job can ever run */
+			END_TIMER;
+			if (DELTA_TIMER >= 1000000)
+				timed_out = true;
 		}
 		list_iterator_destroy(job_iterator);
 	}
diff --git a/testsuite/expect/test17.39 b/testsuite/expect/test17.39
index b612fcb136a4a7839c4da59371936d7d19d6b222..29ecde943ebf5326c0f3fa2d2f87302d36525954 100755
--- a/testsuite/expect/test17.39
+++ b/testsuite/expect/test17.39
@@ -182,7 +182,7 @@ wait_for_job $fast_id DONE
 
 # Wait for dependency job to start once the fast job is complete
 if {[wait_for_job $dep_id RUNNING]} {
-	send_user "\nFAILURE: job $dep_job should be running\n"
+	send_user "\nFAILURE: job $dep_id should be running\n"
 	set exit_code 1
 }