Commit aa5e97ce authored by Martin Schwidefsky's avatar Martin Schwidefsky
Browse files

[PATCH] improve precision of process accounting.



The unit of the cputime accouting values that are stored per process is
currently a microsecond. The CPU timer has a maximum granularity of
2**-12 microseconds. There is no benefit in storing the per process values
in the lesser precision and there is the disadvantage that the backend
has to do the rounding to microseconds. The better solution is to use
the maximum granularity of the CPU timer as cputime unit.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 79741dd3
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <asm/div64.h> #include <asm/div64.h>
/* We want to use micro-second resolution. */ /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */
typedef unsigned long long cputime_t; typedef unsigned long long cputime_t;
typedef unsigned long long cputime64_t; typedef unsigned long long cputime64_t;
...@@ -53,9 +53,9 @@ __div(unsigned long long n, unsigned int base) ...@@ -53,9 +53,9 @@ __div(unsigned long long n, unsigned int base)
#define cputime_ge(__a, __b) ((__a) >= (__b)) #define cputime_ge(__a, __b) ((__a) >= (__b))
#define cputime_lt(__a, __b) ((__a) < (__b)) #define cputime_lt(__a, __b) ((__a) < (__b))
#define cputime_le(__a, __b) ((__a) <= (__b)) #define cputime_le(__a, __b) ((__a) <= (__b))
#define cputime_to_jiffies(__ct) (__div((__ct), 1000000 / HZ)) #define cputime_to_jiffies(__ct) (__div((__ct), 4096000000ULL / HZ))
#define cputime_to_scaled(__ct) (__ct) #define cputime_to_scaled(__ct) (__ct)
#define jiffies_to_cputime(__hz) ((cputime_t)(__hz) * (1000000 / HZ)) #define jiffies_to_cputime(__hz) ((cputime_t)(__hz) * (4096000000ULL / HZ))
#define cputime64_zero (0ULL) #define cputime64_zero (0ULL)
#define cputime64_add(__a, __b) ((__a) + (__b)) #define cputime64_add(__a, __b) ((__a) + (__b))
...@@ -64,7 +64,7 @@ __div(unsigned long long n, unsigned int base) ...@@ -64,7 +64,7 @@ __div(unsigned long long n, unsigned int base)
static inline u64 static inline u64
cputime64_to_jiffies64(cputime64_t cputime) cputime64_to_jiffies64(cputime64_t cputime)
{ {
do_div(cputime, 1000000 / HZ); do_div(cputime, 4096000000ULL / HZ);
return cputime; return cputime;
} }
...@@ -74,13 +74,13 @@ cputime64_to_jiffies64(cputime64_t cputime) ...@@ -74,13 +74,13 @@ cputime64_to_jiffies64(cputime64_t cputime)
static inline unsigned int static inline unsigned int
cputime_to_msecs(const cputime_t cputime) cputime_to_msecs(const cputime_t cputime)
{ {
return __div(cputime, 1000); return __div(cputime, 4096000);
} }
static inline cputime_t static inline cputime_t
msecs_to_cputime(const unsigned int m) msecs_to_cputime(const unsigned int m)
{ {
return (cputime_t) m * 1000; return (cputime_t) m * 4096000;
} }
/* /*
...@@ -89,13 +89,13 @@ msecs_to_cputime(const unsigned int m) ...@@ -89,13 +89,13 @@ msecs_to_cputime(const unsigned int m)
static inline unsigned int static inline unsigned int
cputime_to_secs(const cputime_t cputime) cputime_to_secs(const cputime_t cputime)
{ {
return __div(cputime, 1000000); return __div(cputime, 2048000000) >> 1;
} }
static inline cputime_t static inline cputime_t
secs_to_cputime(const unsigned int s) secs_to_cputime(const unsigned int s)
{ {
return (cputime_t) s * 1000000; return (cputime_t) s * 4096000000ULL;
} }
/* /*
...@@ -104,7 +104,7 @@ secs_to_cputime(const unsigned int s) ...@@ -104,7 +104,7 @@ secs_to_cputime(const unsigned int s)
static inline cputime_t static inline cputime_t
timespec_to_cputime(const struct timespec *value) timespec_to_cputime(const struct timespec *value)
{ {
return value->tv_nsec / 1000 + (u64) value->tv_sec * 1000000; return value->tv_nsec * 4096 / 1000 + (u64) value->tv_sec * 4096000000ULL;
} }
static inline void static inline void
...@@ -114,12 +114,12 @@ cputime_to_timespec(const cputime_t cputime, struct timespec *value) ...@@ -114,12 +114,12 @@ cputime_to_timespec(const cputime_t cputime, struct timespec *value)
register_pair rp; register_pair rp;
rp.pair = cputime >> 1; rp.pair = cputime >> 1;
asm ("dr %0,%1" : "+d" (rp) : "d" (1000000 >> 1)); asm ("dr %0,%1" : "+d" (rp) : "d" (2048000000UL));
value->tv_nsec = rp.subreg.even * 1000; value->tv_nsec = rp.subreg.even * 1000 / 4096;
value->tv_sec = rp.subreg.odd; value->tv_sec = rp.subreg.odd;
#else #else
value->tv_nsec = (cputime % 1000000) * 1000; value->tv_nsec = (cputime % 4096000000ULL) * 1000 / 4096;
value->tv_sec = cputime / 1000000; value->tv_sec = cputime / 4096000000ULL;
#endif #endif
} }
...@@ -131,7 +131,7 @@ cputime_to_timespec(const cputime_t cputime, struct timespec *value) ...@@ -131,7 +131,7 @@ cputime_to_timespec(const cputime_t cputime, struct timespec *value)
static inline cputime_t static inline cputime_t
timeval_to_cputime(const struct timeval *value) timeval_to_cputime(const struct timeval *value)
{ {
return value->tv_usec + (u64) value->tv_sec * 1000000; return value->tv_usec * 4096 + (u64) value->tv_sec * 4096000000ULL;
} }
static inline void static inline void
...@@ -141,12 +141,12 @@ cputime_to_timeval(const cputime_t cputime, struct timeval *value) ...@@ -141,12 +141,12 @@ cputime_to_timeval(const cputime_t cputime, struct timeval *value)
register_pair rp; register_pair rp;
rp.pair = cputime >> 1; rp.pair = cputime >> 1;
asm ("dr %0,%1" : "+d" (rp) : "d" (1000000 >> 1)); asm ("dr %0,%1" : "+d" (rp) : "d" (2048000000UL));
value->tv_usec = rp.subreg.even; value->tv_usec = rp.subreg.even / 4096;
value->tv_sec = rp.subreg.odd; value->tv_sec = rp.subreg.odd;
#else #else
value->tv_usec = cputime % 1000000; value->tv_usec = cputime % 4096000000ULL;
value->tv_sec = cputime / 1000000; value->tv_sec = cputime / 4096000000ULL;
#endif #endif
} }
...@@ -156,13 +156,13 @@ cputime_to_timeval(const cputime_t cputime, struct timeval *value) ...@@ -156,13 +156,13 @@ cputime_to_timeval(const cputime_t cputime, struct timeval *value)
static inline clock_t static inline clock_t
cputime_to_clock_t(cputime_t cputime) cputime_to_clock_t(cputime_t cputime)
{ {
return __div(cputime, 1000000 / USER_HZ); return __div(cputime, 4096000000ULL / USER_HZ);
} }
static inline cputime_t static inline cputime_t
clock_t_to_cputime(unsigned long x) clock_t_to_cputime(unsigned long x)
{ {
return (cputime_t) x * (1000000 / USER_HZ); return (cputime_t) x * (4096000000ULL / USER_HZ);
} }
/* /*
...@@ -171,7 +171,7 @@ clock_t_to_cputime(unsigned long x) ...@@ -171,7 +171,7 @@ clock_t_to_cputime(unsigned long x)
static inline clock_t static inline clock_t
cputime64_to_clock_t(cputime64_t cputime) cputime64_to_clock_t(cputime64_t cputime)
{ {
return __div(cputime, 1000000 / USER_HZ); return __div(cputime, 4096000000ULL / USER_HZ);
} }
#endif /* _S390_CPUTIME_H */ #endif /* _S390_CPUTIME_H */
...@@ -67,11 +67,11 @@ ...@@ -67,11 +67,11 @@
#define __LC_SYNC_ENTER_TIMER 0x248 #define __LC_SYNC_ENTER_TIMER 0x248
#define __LC_ASYNC_ENTER_TIMER 0x250 #define __LC_ASYNC_ENTER_TIMER 0x250
#define __LC_EXIT_TIMER 0x258 #define __LC_EXIT_TIMER 0x258
#define __LC_LAST_UPDATE_TIMER 0x260 #define __LC_USER_TIMER 0x260
#define __LC_USER_TIMER 0x268 #define __LC_SYSTEM_TIMER 0x268
#define __LC_SYSTEM_TIMER 0x270 #define __LC_STEAL_TIMER 0x270
#define __LC_LAST_UPDATE_CLOCK 0x278 #define __LC_LAST_UPDATE_TIMER 0x278
#define __LC_STEAL_CLOCK 0x280 #define __LC_LAST_UPDATE_CLOCK 0x280
#define __LC_RETURN_MCCK_PSW 0x288 #define __LC_RETURN_MCCK_PSW 0x288
#define __LC_KERNEL_STACK 0xC40 #define __LC_KERNEL_STACK 0xC40
#define __LC_THREAD_INFO 0xC44 #define __LC_THREAD_INFO 0xC44
...@@ -89,11 +89,11 @@ ...@@ -89,11 +89,11 @@
#define __LC_SYNC_ENTER_TIMER 0x250 #define __LC_SYNC_ENTER_TIMER 0x250
#define __LC_ASYNC_ENTER_TIMER 0x258 #define __LC_ASYNC_ENTER_TIMER 0x258
#define __LC_EXIT_TIMER 0x260 #define __LC_EXIT_TIMER 0x260
#define __LC_LAST_UPDATE_TIMER 0x268 #define __LC_USER_TIMER 0x268
#define __LC_USER_TIMER 0x270 #define __LC_SYSTEM_TIMER 0x270
#define __LC_SYSTEM_TIMER 0x278 #define __LC_STEAL_TIMER 0x278
#define __LC_LAST_UPDATE_CLOCK 0x280 #define __LC_LAST_UPDATE_TIMER 0x280
#define __LC_STEAL_CLOCK 0x288 #define __LC_LAST_UPDATE_CLOCK 0x288
#define __LC_RETURN_MCCK_PSW 0x290 #define __LC_RETURN_MCCK_PSW 0x290
#define __LC_KERNEL_STACK 0xD40 #define __LC_KERNEL_STACK 0xD40
#define __LC_THREAD_INFO 0xD48 #define __LC_THREAD_INFO 0xD48
...@@ -252,11 +252,11 @@ struct _lowcore ...@@ -252,11 +252,11 @@ struct _lowcore
__u64 sync_enter_timer; /* 0x248 */ __u64 sync_enter_timer; /* 0x248 */
__u64 async_enter_timer; /* 0x250 */ __u64 async_enter_timer; /* 0x250 */
__u64 exit_timer; /* 0x258 */ __u64 exit_timer; /* 0x258 */
__u64 last_update_timer; /* 0x260 */ __u64 user_timer; /* 0x260 */
__u64 user_timer; /* 0x268 */ __u64 system_timer; /* 0x268 */
__u64 system_timer; /* 0x270 */ __u64 steal_timer; /* 0x270 */
__u64 last_update_clock; /* 0x278 */ __u64 last_update_timer; /* 0x278 */
__u64 steal_clock; /* 0x280 */ __u64 last_update_clock; /* 0x280 */
psw_t return_mcck_psw; /* 0x288 */ psw_t return_mcck_psw; /* 0x288 */
__u8 pad8[0xc00-0x290]; /* 0x290 */ __u8 pad8[0xc00-0x290]; /* 0x290 */
...@@ -343,11 +343,11 @@ struct _lowcore ...@@ -343,11 +343,11 @@ struct _lowcore
__u64 sync_enter_timer; /* 0x250 */ __u64 sync_enter_timer; /* 0x250 */
__u64 async_enter_timer; /* 0x258 */ __u64 async_enter_timer; /* 0x258 */
__u64 exit_timer; /* 0x260 */ __u64 exit_timer; /* 0x260 */
__u64 last_update_timer; /* 0x268 */ __u64 user_timer; /* 0x268 */
__u64 user_timer; /* 0x270 */ __u64 system_timer; /* 0x270 */
__u64 system_timer; /* 0x278 */ __u64 steal_timer; /* 0x278 */
__u64 last_update_clock; /* 0x280 */ __u64 last_update_timer; /* 0x280 */
__u64 steal_clock; /* 0x288 */ __u64 last_update_clock; /* 0x288 */
psw_t return_mcck_psw; /* 0x290 */ psw_t return_mcck_psw; /* 0x290 */
__u8 pad8[0xc00-0x2a0]; /* 0x2a0 */ __u8 pad8[0xc00-0x2a0]; /* 0x2a0 */
/* System info area */ /* System info area */
......
...@@ -99,7 +99,7 @@ static inline void restore_access_regs(unsigned int *acrs) ...@@ -99,7 +99,7 @@ static inline void restore_access_regs(unsigned int *acrs)
prev = __switch_to(prev,next); \ prev = __switch_to(prev,next); \
} while (0) } while (0)
extern void account_vtime(struct task_struct *); extern void account_vtime(struct task_struct *, struct task_struct *);
extern void account_tick_vtime(struct task_struct *); extern void account_tick_vtime(struct task_struct *);
extern void account_system_vtime(struct task_struct *); extern void account_system_vtime(struct task_struct *);
...@@ -121,7 +121,7 @@ static inline void cmma_init(void) { } ...@@ -121,7 +121,7 @@ static inline void cmma_init(void) { }
#define finish_arch_switch(prev) do { \ #define finish_arch_switch(prev) do { \
set_fs(current->thread.mm_segment); \ set_fs(current->thread.mm_segment); \
account_vtime(prev); \ account_vtime(prev, current); \
} while (0) } while (0)
#define nop() asm volatile("nop") #define nop() asm volatile("nop")
......
...@@ -47,6 +47,8 @@ struct thread_info { ...@@ -47,6 +47,8 @@ struct thread_info {
unsigned int cpu; /* current CPU */ unsigned int cpu; /* current CPU */
int preempt_count; /* 0 => preemptable, <0 => BUG */ int preempt_count; /* 0 => preemptable, <0 => BUG */
struct restart_block restart_block; struct restart_block restart_block;
__u64 user_timer;
__u64 system_timer;
}; };
/* /*
......
...@@ -31,11 +31,10 @@ static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); ...@@ -31,11 +31,10 @@ static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
* Update process times based on virtual cpu times stored by entry.S * Update process times based on virtual cpu times stored by entry.S
* to the lowcore fields user_timer, system_timer & steal_clock. * to the lowcore fields user_timer, system_timer & steal_clock.
*/ */
void account_process_tick(struct task_struct *tsk, int user_tick) static void do_account_vtime(struct task_struct *tsk, int hardirq_offset)
{ {
cputime_t cputime; struct thread_info *ti = task_thread_info(tsk);
__u64 timer, clock; __u64 timer, clock, user, system, steal;
int rcu_user_flag;
timer = S390_lowcore.last_update_timer; timer = S390_lowcore.last_update_timer;
clock = S390_lowcore.last_update_clock; clock = S390_lowcore.last_update_clock;
...@@ -44,59 +43,47 @@ void account_process_tick(struct task_struct *tsk, int user_tick) ...@@ -44,59 +43,47 @@ void account_process_tick(struct task_struct *tsk, int user_tick)
: "=m" (S390_lowcore.last_update_timer), : "=m" (S390_lowcore.last_update_timer),
"=m" (S390_lowcore.last_update_clock) ); "=m" (S390_lowcore.last_update_clock) );
S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
S390_lowcore.steal_clock += S390_lowcore.last_update_clock - clock; S390_lowcore.steal_timer += S390_lowcore.last_update_clock - clock;
cputime = S390_lowcore.user_timer >> 12; user = S390_lowcore.user_timer - ti->user_timer;
rcu_user_flag = cputime != 0; S390_lowcore.steal_timer -= user;
S390_lowcore.user_timer -= cputime << 12; ti->user_timer = S390_lowcore.user_timer;
S390_lowcore.steal_clock -= cputime << 12; account_user_time(tsk, user, user);
account_user_time(tsk, cputime, cputime);
cputime = S390_lowcore.system_timer >> 12; system = S390_lowcore.system_timer - ti->system_timer;
S390_lowcore.system_timer -= cputime << 12; S390_lowcore.steal_timer -= system;
S390_lowcore.steal_clock -= cputime << 12; ti->system_timer = S390_lowcore.system_timer;
if (idle_task(smp_processor_id()) != current) if (idle_task(smp_processor_id()) != current)
account_system_time(tsk, HARDIRQ_OFFSET, cputime, cputime); account_system_time(tsk, hardirq_offset, system, system);
else else
account_idle_time(cputime); account_idle_time(system);
cputime = S390_lowcore.steal_clock; steal = S390_lowcore.steal_timer;
if ((__s64) cputime > 0) { if ((s64) steal > 0) {
cputime >>= 12; S390_lowcore.steal_timer = 0;
S390_lowcore.steal_clock -= cputime << 12;
if (idle_task(smp_processor_id()) != current) if (idle_task(smp_processor_id()) != current)
account_steal_time(cputime); account_steal_time(steal);
else else
account_idle_time(cputime); account_idle_time(steal);
} }
} }
/* void account_vtime(struct task_struct *prev, struct task_struct *next)
* Update process times based on virtual cpu times stored by entry.S
* to the lowcore fields user_timer, system_timer & steal_clock.
*/
void account_vtime(struct task_struct *tsk)
{ {
cputime_t cputime; struct thread_info *ti;
__u64 timer;
do_account_vtime(prev, 0);
timer = S390_lowcore.last_update_timer; ti = task_thread_info(prev);
asm volatile (" STPT %0" /* Store current cpu timer value */ ti->user_timer = S390_lowcore.user_timer;
: "=m" (S390_lowcore.last_update_timer) ); ti->system_timer = S390_lowcore.system_timer;
S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; ti = task_thread_info(next);
S390_lowcore.user_timer = ti->user_timer;
cputime = S390_lowcore.user_timer >> 12; S390_lowcore.system_timer = ti->system_timer;
S390_lowcore.user_timer -= cputime << 12; }
S390_lowcore.steal_clock -= cputime << 12;
account_user_time(tsk, cputime, cputime);
cputime = S390_lowcore.system_timer >> 12; void account_process_tick(struct task_struct *tsk, int user_tick)
S390_lowcore.system_timer -= cputime << 12; {
S390_lowcore.steal_clock -= cputime << 12; do_account_vtime(tsk, HARDIRQ_OFFSET);
if (idle_task(smp_processor_id()) != current)
account_system_time(tsk, 0, cputime, cputime);
else
account_idle_time(cputime);
} }
/* /*
...@@ -105,21 +92,21 @@ void account_vtime(struct task_struct *tsk) ...@@ -105,21 +92,21 @@ void account_vtime(struct task_struct *tsk)
*/ */
void account_system_vtime(struct task_struct *tsk) void account_system_vtime(struct task_struct *tsk)
{ {
cputime_t cputime; struct thread_info *ti = task_thread_info(tsk);
__u64 timer; __u64 timer, system;
timer = S390_lowcore.last_update_timer; timer = S390_lowcore.last_update_timer;
asm volatile (" STPT %0" /* Store current cpu timer value */ asm volatile (" STPT %0" /* Store current cpu timer value */
: "=m" (S390_lowcore.last_update_timer) ); : "=m" (S390_lowcore.last_update_timer) );
S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
cputime = S390_lowcore.system_timer >> 12; system = S390_lowcore.system_timer - ti->system_timer;
S390_lowcore.system_timer -= cputime << 12; S390_lowcore.steal_timer -= system;
S390_lowcore.steal_clock -= cputime << 12; ti->system_timer = S390_lowcore.system_timer;
if (in_irq() || idle_task(smp_processor_id()) != current) if (in_irq() || idle_task(smp_processor_id()) != current)
account_system_time(tsk, 0, cputime, cputime); account_system_time(tsk, 0, system, system);
else else
account_idle_time(cputime); account_idle_time(system);
} }
EXPORT_SYMBOL_GPL(account_system_vtime); EXPORT_SYMBOL_GPL(account_system_vtime);
...@@ -490,8 +477,8 @@ void init_cpu_vtimer(void) ...@@ -490,8 +477,8 @@ void init_cpu_vtimer(void)
/* kick the virtual timer */ /* kick the virtual timer */
S390_lowcore.exit_timer = VTIMER_MAX_SLICE; S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
S390_lowcore.last_update_timer = VTIMER_MAX_SLICE; S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock)); asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
/* enable cpu timer interrupts */ /* enable cpu timer interrupts */
__ctl_set_bit(0,10); __ctl_set_bit(0,10);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment