Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b64f34cd authored by Hidetoshi Seto's avatar Hidetoshi Seto Committed by Tony Luck
Browse files

[IA64] VIRT_CPU_ACCOUNTING (accurate cpu time accounting)



This patch implements VIRT_CPU_ACCOUNTING for ia64,
which enable us to use more accurate cpu time accounting.

The VIRT_CPU_ACCOUNTING is an item of kernel config, which s390
and powerpc arch have.  By turning this config on, these archs
change the mechanism of cpu time accounting from tick-sampling
based one to state-transition based one.

The state-transition based accounting is done by checking time
(cycle counter in processor) at every state-transition point,
such as entrance/exit of kernel, interrupt, softirq etc.
The difference between point to point is the actual time consumed
during in the state. There is no doubt about that this value is
more accurate than that of tick-sampling based accounting.

Signed-off-by: default avatarHidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 5d9c4a7d
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -280,6 +280,17 @@ config FORCE_MAX_ZONEORDER
	default "17" if HUGETLB_PAGE
	default "11"

config VIRT_CPU_ACCOUNTING
	bool "Deterministic task and CPU time accounting"
	default n
	help
	  Select this option to enable more accurate task and CPU time
	  accounting.  This is done by reading a CPU counter on each
	  kernel entry and exit and on transitions within the kernel
	  between system, softirq and hardirq state, so there is a
	  small performance impact.
	  If in doubt, say N here.

config SMP
	bool "Symmetric multi-processing support"
	help
+13 −1
Original line number Diff line number Diff line
@@ -30,7 +30,19 @@ struct elf_siginfo
	int	si_errno;			/* errno */
};

#define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0)
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
/*
 * Hacks are here since types between compat_timeval (= pair of s32) and
 * ia64-native timeval (= pair of s64) are not compatible, at least a file
 * arch/ia64/ia32/../../../fs/binfmt_elf.c will get warnings from compiler on
 * use of cputime_to_timeval(), which usually an alias of jiffies_to_timeval().
 */
#define cputime_to_timeval(a,b) \
	do { (b)->tv_usec = 0; (b)->tv_sec = (a)/NSEC_PER_SEC; } while(0)
#else
#define jiffies_to_timeval(a,b) \
	do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; } while(0)
#endif

struct elf_prstatus
{
+6 −0
Original line number Diff line number Diff line
@@ -39,6 +39,12 @@ void foo(void)
	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
	DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
	DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	DEFINE(TI_AC_STAMP, offsetof(struct thread_info, ac_stamp));
	DEFINE(TI_AC_LEAVE, offsetof(struct thread_info, ac_leave));
	DEFINE(TI_AC_STIME, offsetof(struct thread_info, ac_stime));
	DEFINE(TI_AC_UTIME, offsetof(struct thread_info, ac_utime));
#endif

	BLANK();

+65 −0
Original line number Diff line number Diff line
@@ -710,6 +710,16 @@ ENTRY(ia64_leave_syscall)
(pUStk)	cmp.eq.unc p6,p0=r0,r0		// p6 <- pUStk
#endif
.work_processed_syscall:
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	adds r2=PT(LOADRS)+16,r12
(pUStk)	mov.m r22=ar.itc			// fetch time at leave
	adds r18=TI_FLAGS+IA64_TASK_SIZE,r13
	;;
(p6)	ld4 r31=[r18]				// load current_thread_info()->flags
	ld8 r19=[r2],PT(B6)-PT(LOADRS)		// load ar.rsc value for "loadrs"
	adds r3=PT(AR_BSPSTORE)+16,r12		// deferred
	;;
#else
	adds r2=PT(LOADRS)+16,r12
	adds r3=PT(AR_BSPSTORE)+16,r12
	adds r18=TI_FLAGS+IA64_TASK_SIZE,r13
@@ -718,6 +728,7 @@ ENTRY(ia64_leave_syscall)
	ld8 r19=[r2],PT(B6)-PT(LOADRS)		// load ar.rsc value for "loadrs"
	nop.i 0
	;;
#endif
	mov r16=ar.bsp				// M2  get existing backing store pointer
	ld8 r18=[r2],PT(R9)-PT(B6)		// load b6
(p6)	and r15=TIF_WORK_MASK,r31		// any work other than TIF_SYSCALL_TRACE?
@@ -737,12 +748,21 @@ ENTRY(ia64_leave_syscall)

	ld8 r29=[r2],16		// M0|1 load cr.ipsr
	ld8 r28=[r3],16		// M0|1 load cr.iip
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
(pUStk) add r14=TI_AC_LEAVE+IA64_TASK_SIZE,r13
	;;
	ld8 r30=[r2],16		// M0|1 load cr.ifs
	ld8 r25=[r3],16		// M0|1 load ar.unat
(pUStk) add r15=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13
	;;
#else
	mov r22=r0		// A    clear r22
	;;
	ld8 r30=[r2],16		// M0|1 load cr.ifs
	ld8 r25=[r3],16		// M0|1 load ar.unat
(pUStk) add r14=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13
	;;
#endif
	ld8 r26=[r2],PT(B0)-PT(AR_PFS)	// M0|1 load ar.pfs
(pKStk)	mov r22=psr			// M2   read PSR now that interrupts are disabled
	nop 0
@@ -759,7 +779,11 @@ ENTRY(ia64_leave_syscall)
	ld8.fill r1=[r3],16			// M0|1 load r1
(pUStk) mov r17=1				// A
	;;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
(pUStk) st1 [r15]=r17				// M2|3
#else
(pUStk) st1 [r14]=r17				// M2|3
#endif
	ld8.fill r13=[r3],16			// M0|1
	mov f8=f0				// F    clear f8
	;;
@@ -775,12 +799,22 @@ ENTRY(ia64_leave_syscall)
	shr.u r18=r19,16		// I0|1 get byte size of existing "dirty" partition
	cover				// B    add current frame into dirty partition & set cr.ifs
	;;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	mov r19=ar.bsp			// M2   get new backing store pointer
	st8 [r14]=r22			// M	save time at leave
	mov f10=f0			// F    clear f10

	mov r22=r0			// A	clear r22
	movl r14=__kernel_syscall_via_epc // X
	;;
#else
	mov r19=ar.bsp			// M2   get new backing store pointer
	mov f10=f0			// F    clear f10

	nop.m 0
	movl r14=__kernel_syscall_via_epc // X
	;;
#endif
	mov.m ar.csd=r0			// M2   clear ar.csd
	mov.m ar.ccv=r0			// M2   clear ar.ccv
	mov b7=r14			// I0   clear b7 (hint with __kernel_syscall_via_epc)
@@ -913,10 +947,18 @@ GLOBAL_ENTRY(ia64_leave_kernel)
	adds r16=PT(CR_IPSR)+16,r12
	adds r17=PT(CR_IIP)+16,r12

#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	.pred.rel.mutex pUStk,pKStk
(pKStk)	mov r22=psr		// M2 read PSR now that interrupts are disabled
(pUStk)	mov.m r22=ar.itc	// M  fetch time at leave
	nop.i 0
	;;
#else
(pKStk)	mov r22=psr		// M2 read PSR now that interrupts are disabled
	nop.i 0
	nop.i 0
	;;
#endif
	ld8 r29=[r16],16	// load cr.ipsr
	ld8 r28=[r17],16	// load cr.iip
	;;
@@ -938,15 +980,37 @@ GLOBAL_ENTRY(ia64_leave_kernel)
	;;
	ld8.fill r12=[r16],16
	ld8.fill r13=[r17],16
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
(pUStk)	adds r3=TI_AC_LEAVE+IA64_TASK_SIZE,r18
#else
(pUStk)	adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18
#endif
	;;
	ld8 r20=[r16],16	// ar.fpsr
	ld8.fill r15=[r17],16
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
(pUStk)	adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18	// deferred
#endif
	;;
	ld8.fill r14=[r16],16
	ld8.fill r2=[r17]
(pUStk)	mov r17=1
	;;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	//  mmi_ :  ld8 st1 shr;;         mmi_ : st8 st1 shr;;
	//  mib  :  mov add br        ->  mib  : ld8 add br
	//  bbb_ :  br  nop cover;;       mbb_ : mov br  cover;;
	//
	//  no one require bsp in r16 if (pKStk) branch is selected.
(pUStk)	st8 [r3]=r22		// save time at leave
(pUStk)	st1 [r18]=r17		// restore current->thread.on_ustack
	shr.u r18=r19,16	// get byte size of existing "dirty" partition
	;;
	ld8.fill r3=[r16]	// deferred
	LOAD_PHYS_STACK_REG_SIZE(r17)
(pKStk)	br.cond.dpnt skip_rbs_switch
	mov r16=ar.bsp		// get existing backing store pointer
#else
	ld8.fill r3=[r16]
(pUStk)	st1 [r18]=r17		// restore current->thread.on_ustack
	shr.u r18=r19,16	// get byte size of existing "dirty" partition
@@ -954,6 +1018,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
	mov r16=ar.bsp		// get existing backing store pointer
	LOAD_PHYS_STACK_REG_SIZE(r17)
(pKStk)	br.cond.dpnt skip_rbs_switch
#endif

	/*
	 * Restore user backing store.
+26 −0
Original line number Diff line number Diff line
@@ -660,7 +660,11 @@ GLOBAL_ENTRY(fsys_bubble_down)
	nop.i 0
	;;
	mov ar.rsc=0				// M2   set enforced lazy mode, pl 0, LE, loadrs=0
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	mov.m r30=ar.itc			// M    get cycle for accounting
#else
	nop.m 0
#endif
	nop.i 0
	;;
	mov r23=ar.bspstore			// M2 (12 cyc) save ar.bspstore
@@ -682,6 +686,28 @@ GLOBAL_ENTRY(fsys_bubble_down)
	cmp.ne pKStk,pUStk=r0,r0		// A    set pKStk <- 0, pUStk <- 1
	br.call.sptk.many b7=ia64_syscall_setup	// B
	;;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	// mov.m r30=ar.itc is called in advance
	add r16=TI_AC_STAMP+IA64_TASK_SIZE,r2
	add r17=TI_AC_LEAVE+IA64_TASK_SIZE,r2
	;;
	ld8 r18=[r16],TI_AC_STIME-TI_AC_STAMP	// time at last check in kernel
	ld8 r19=[r17],TI_AC_UTIME-TI_AC_LEAVE	// time at leave kernel
	;;
	ld8 r20=[r16],TI_AC_STAMP-TI_AC_STIME	// cumulated stime
	ld8 r21=[r17]				// cumulated utime
	sub r22=r19,r18				// stime before leave kernel
	;;
	st8 [r16]=r30,TI_AC_STIME-TI_AC_STAMP	// update stamp
	sub r18=r30,r19				// elapsed time in user mode
	;;
	add r20=r20,r22				// sum stime
	add r21=r21,r18				// sum utime
	;;
	st8 [r16]=r20				// update stime
	st8 [r17]=r21				// update utime
	;;
#endif
	mov ar.rsc=0x3				// M2   set eager mode, pl 0, LE, loadrs=0
	mov rp=r14				// I0   set the real return addr
	and r3=_TIF_SYSCALL_TRACEAUDIT,r3	// A
Loading