diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index f99bddf16b8b0e4a234472eda0ba7ab3c828ed2a..4cffa4a5a2b715f416746164fb05c84572e75d58 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -267,6 +267,13 @@ CPU	  PRF_CTRL
 
 .fi
 
+.SH INPUT
+
+For interval-mode, turbostat will immediately end the current interval
+when it sees a newline on standard input.
+turbostat will then start the next interval.
+Control-C will be send a SIGINT to turbostat,
+which will immediately abort the program with no further processing.
 .SH SIGNALS
 
 SIGINT will interrupt interval-mode.
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index dd9b2efbbb2ad0bdef553ed7e67d5aa4b942030a..1d4ba4ade6fa101ac6fbb06134cadb407e763520 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
+#include <sys/select.h>
 #include <sys/resource.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -47,7 +48,8 @@
 char *proc_stat = "/proc/stat";
 FILE *outf;
 int *fd_percpu;
-struct timespec interval_ts = {5, 0};
+struct timeval interval_tv = {5, 0};
+struct timespec one_msec = {0, 1000000};
 unsigned int debug;
 unsigned int quiet;
 unsigned int shown;
@@ -478,7 +480,7 @@ void help(void)
 	"--cpu	cpu-set	limit output to summary plus cpu-set:\n"
 	"		{core | package | j,k,l..m,n-p }\n"
 	"--quiet	skip decoding system configuration header\n"
-	"--interval sec	Override default 5-second measurement interval\n"
+	"--interval sec.subsec	Override default 5-second measurement interval\n"
 	"--help		print this help message\n"
 	"--list		list column headers only\n"
 	"--out file	create or truncate \"file\" for all output\n"
@@ -2615,6 +2617,8 @@ static void signal_handler (int signal)
 			fprintf(stderr, "SIGUSR1\n");
 		break;
 	}
+	/* make sure this manually-invoked interval is at least 1ms long */
+	nanosleep(&one_msec, NULL);
 }
 
 void setup_signal_handler(void)
@@ -2630,6 +2634,33 @@ void setup_signal_handler(void)
 	if (sigaction(SIGUSR1, &sa, NULL) < 0)
 		err(1, "sigaction SIGUSR1");
 }
+
+int do_sleep(void)
+{
+	struct timeval select_timeout;
+	fd_set readfds;
+	int retval;
+
+	FD_ZERO(&readfds);
+	FD_SET(0, &readfds);
+
+	select_timeout = interval_tv;
+
+	retval = select(1, &readfds, NULL, NULL, &select_timeout);
+
+	if (retval == 1) {
+
+		switch (getc(stdin)) {
+		case 'q':
+			exit_requested = 1;
+			break;
+		}
+		/* make sure this manually-invoked interval is at least 1ms long */
+		nanosleep(&one_msec, NULL);
+	}
+
+	return retval;
+}
 void turbostat_loop()
 {
 	int retval;
@@ -2659,7 +2690,7 @@ void turbostat_loop()
 			re_initialize();
 			goto restart;
 		}
-		nanosleep(&interval_ts, NULL);
+		do_sleep();
 		if (snapshot_proc_sysfs_files())
 			goto restart;
 		retval = for_all_cpus(get_counters, ODD_COUNTERS);
@@ -2680,7 +2711,7 @@ void turbostat_loop()
 		flush_output_stdout();
 		if (exit_requested)
 			break;
-		nanosleep(&interval_ts, NULL);
+		do_sleep();
 		if (snapshot_proc_sysfs_files())
 			goto restart;
 		retval = for_all_cpus(get_counters, EVEN_COUNTERS);
@@ -5103,8 +5134,8 @@ void cmdline(int argc, char **argv)
 					exit(2);
 				}
 
-				interval_ts.tv_sec = interval;
-				interval_ts.tv_nsec = (interval - interval_ts.tv_sec) * 1000000000;
+				interval_tv.tv_sec = interval;
+				interval_tv.tv_usec = (interval - interval_tv.tv_sec) * 1000000;
 			}
 			break;
 		case 'J':