diff --git a/src/builtin_jobs.cpp b/src/builtin_jobs.cpp index 8b12f4e8d..4071daec4 100644 --- a/src/builtin_jobs.cpp +++ b/src/builtin_jobs.cpp @@ -29,24 +29,13 @@ enum { /// Calculates the cpu usage (in percent) of the specified job. static int cpu_use(const job_t *j) { double u = 0; - for (const process_ptr_t &p : j->processes) { - struct timeval t; - unsigned long jiffies; - gettimeofday(&t, nullptr); - jiffies = proc_get_jiffies(p->pid); - - double t1 = 1000000.0 * p->last_time.tv_sec + p->last_time.tv_usec; - double t2 = 1000000.0 * t.tv_sec + t.tv_usec; - - // Check for a race condition that can cause negative CPU usage to be reported (#7066) - unsigned long cached_last_jiffies = p->last_jiffies; - if (t2 < t1 || jiffies < cached_last_jiffies) { - continue; + timepoint_t now = timef(); + unsigned long jiffies = proc_get_jiffies(p->pid); + double since = now - p->last_time; + if (since > 0 && jiffies > p->last_jiffies) { + u += (jiffies - p->last_jiffies) / since; } - - // std::fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n", t1, t2, jiffies, p->last_jiffies ); - u += (static_cast(jiffies - cached_last_jiffies)) / (t2 - t1); } return u * 1000000; } diff --git a/src/common.cpp b/src/common.cpp index 8be857c3a..82390c9d7 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -1723,13 +1723,10 @@ void format_size_safe(char buff[128], unsigned long long sz) { } } -/// Return the number of seconds from the UNIX epoch, with subsecond precision. This function uses -/// the gettimeofday function and will have the same precision as that function. double timef() { struct timeval tv; assert_with_errno(gettimeofday(&tv, nullptr) != -1); - // return (double)tv.tv_sec + 0.000001 * tv.tv_usec; - return static_cast(tv.tv_sec) + 1e-6 * tv.tv_usec; + return static_cast(tv.tv_sec) + 1e-6 * tv.tv_usec; } void exit_without_destructors(int code) { _exit(code); } diff --git a/src/common.h b/src/common.h index 4aa8675e4..28567d2e8 100644 --- a/src/common.h +++ b/src/common.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -516,7 +517,8 @@ void bugreport(); /// Return the number of seconds from the UNIX epoch, with subsecond precision. This function uses /// the gettimeofday function and will have the same precision as that function. -double timef(); +using timepoint_t = double; +timepoint_t timef(); /// Call the following function early in main to set the main thread. This is our replacement for /// pthread_main_np(). diff --git a/src/proc.cpp b/src/proc.cpp index 3bc902210..e9bc23355 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -765,7 +765,7 @@ unsigned long proc_get_jiffies(pid_t inpid) { void proc_update_jiffies(parser_t &parser) { for (const auto &job : parser.jobs()) { for (process_ptr_t &p : job->processes) { - gettimeofday(&p->last_time, nullptr); + p->last_time = timef(); p->last_jiffies = proc_get_jiffies(p->pid); } } diff --git a/src/proc.h b/src/proc.h index 7d977c13e..27bfb4d34 100644 --- a/src/proc.h +++ b/src/proc.h @@ -277,8 +277,8 @@ class process_t : noncopyable_t { /// Reported status value. proc_status_t status{}; - /// Last time of cpu time check. - struct timeval last_time {}; + /// Last time of cpu time check, in seconds (per timef). + timepoint_t last_time{0}; /// Number of jiffies spent in process at last cpu time check. unsigned long last_jiffies{0}; diff --git a/src/reader.cpp b/src/reader.cpp index 87cb935df..0c34ecc64 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2408,23 +2408,9 @@ void reader_data_t::set_buffer_maintaining_pager(const wcstring &b, size_t pos, history_search.reset(); } -static void set_env_cmd_duration(struct timeval *after, struct timeval *before, env_stack_t &vars) { - time_t secs = after->tv_sec - before->tv_sec; - suseconds_t usecs = after->tv_usec - before->tv_usec; - - if (after->tv_usec < before->tv_usec) { - usecs += 1000000; - secs -= 1; - } - - vars.set_one(ENV_CMD_DURATION, ENV_UNEXPORT, std::to_wstring((secs * 1000) + (usecs / 1000))); -} - /// Run the specified command with the correct terminal modes, and while taking care to perform job /// notification, set the title, etc. static eval_res_t reader_run_command(parser_t &parser, const wcstring &cmd) { - struct timeval time_before, time_after; - wcstring ft = tok_command(cmd); // For compatibility with fish 2.0's $_, now replaced with `status current-command` @@ -2435,16 +2421,18 @@ static eval_res_t reader_run_command(parser_t &parser, const wcstring &cmd) { outp.set_color(rgb_color_t::normal(), rgb_color_t::normal()); term_donate(); - gettimeofday(&time_before, nullptr); - + timepoint_t time_before = timef(); auto eval_res = parser.eval(cmd, io_chain_t{}); job_reap(parser, true); - gettimeofday(&time_after, nullptr); - // update the execution duration iff a command is requested for execution // issue - #4926 - if (!ft.empty()) set_env_cmd_duration(&time_after, &time_before, parser.vars()); + if (!ft.empty()) { + timepoint_t time_after = timef(); + double duration = time_after - time_before; + long duration_ms = std::round(duration * 1000); + parser.vars().set_one(ENV_CMD_DURATION, ENV_UNEXPORT, to_string(duration_ms)); + } term_steal();