[PATCH v2] powerpc 32: Provides VIRT_CPU_ACCOUNTING

Benjamin Herrenschmidt benh at kernel.crashing.org
Wed Apr 30 14:57:32 EST 2014


On Mon, 2014-04-07 at 09:31 +0200, Christophe Leroy wrote:
> This patch provides VIRT_CPU_ACCOUTING to PPC32 architecture.
> Unlike PPC64, PPC32 doesn't use the PACA convention. Therefore the
> implementation is taken from the IA64 architecture.
> It is based on additional information added to the Task Info structure.
> 
> Signed-off-by: Christophe Leroy <christophe.leroy at c-s.fr>

Scott, Can you review/ack this (or get somebody to) ?

It looks like a great idea but I really don't have the bandwidth to
review in detail and test right now.

(Adding Alister as well who maintains our 4xx 32-bit stuff nowadays).

Cheers,
Ben.

> Index: b/arch/powerpc/Kconfig
> ===================================================================
> --- a/arch/powerpc/Kconfig	(revision 5607)
> +++ b/arch/powerpc/Kconfig	(revision 5611)
> @@ -138,6 +138,7 @@
>  	select OLD_SIGSUSPEND
>  	select OLD_SIGACTION if PPC32
>  	select HAVE_DEBUG_STACKOVERFLOW
> +	select HAVE_VIRT_CPU_ACCOUNTING
>  
>  config EARLY_PRINTK
>  	bool
> Index: a/arch/powerpc/kernel/time.c
> ===================================================================
> --- a/arch/powerpc/kernel/time.c	(revision 5607)
> +++ b/arch/powerpc/kernel/time.c	(revision 5611)
> @@ -162,7 +162,9 @@
>  
>  cputime_t cputime_one_jiffy;
>  
> +#ifdef CONFIG_PPC_SPLPAR
>  void (*dtl_consumer)(struct dtl_entry *, u64);
> +#endif
>  
>  static void calc_cputime_factors(void)
>  {
> @@ -178,6 +180,7 @@
>  	__cputime_clockt_factor = res.result_low;
>  }
>  
> +#ifdef CONFIG_PPC64
>  /*
>   * Read the SPURR on systems that have it, otherwise the PURR,
>   * or if that doesn't exist return the timebase value passed in.
> @@ -190,6 +193,7 @@
>  		return mfspr(SPRN_PURR);
>  	return tb;
>  }
> +#endif
>  
>  #ifdef CONFIG_PPC_SPLPAR
>  
> @@ -291,6 +295,7 @@
>   * Account time for a transition between system, hard irq
>   * or soft irq state.
>   */
> +#ifdef CONFIG_PPC64
>  static u64 vtime_delta(struct task_struct *tsk,
>  			u64 *sys_scaled, u64 *stolen)
>  {
> @@ -377,7 +382,70 @@
>  	get_paca()->utime_sspurr = 0;
>  	account_user_time(tsk, utime, utimescaled);
>  }
> +#else
>  
> +void vtime_account_user(struct task_struct *tsk)
> +{
> +	cputime_t delta_utime;
> +	struct thread_info *ti = task_thread_info(tsk);
> +
> +	if (ti->ac_utime) {
> +		delta_utime = ti->ac_utime;
> +		account_user_time(tsk, delta_utime, delta_utime);
> +		ti->ac_utime = 0;
> +	}
> +}
> +
> +/*
> + * Called from the context switch with interrupts disabled, to charge all
> + * accumulated times to the current process, and to prepare accounting on
> + * the next process.
> + */
> +void arch_vtime_task_switch(struct task_struct *prev)
> +{
> +	struct thread_info *pi = task_thread_info(prev);
> +	struct thread_info *ni = task_thread_info(current);
> +
> +	ni->ac_stamp = pi->ac_stamp;
> +	ni->ac_stime = ni->ac_utime = 0;
> +}
> +
> +/*
> + * Account time for a transition between system, hard irq or soft irq state.
> + * Note that this function is called with interrupts enabled.
> + */
> +static cputime_t vtime_delta(struct task_struct *tsk)
> +{
> +	struct thread_info *ti = task_thread_info(tsk);
> +	__u32 delta_stime;
> +	__u32 now;
> +
> +	WARN_ON_ONCE(!irqs_disabled());
> +
> +	now = mftbl();
> +
> +	delta_stime = ti->ac_stime + (now - ti->ac_stamp);
> +	ti->ac_stime = 0;
> +	ti->ac_stamp = now;
> +
> +	return (cputime_t)delta_stime;
> +}
> +
> +void vtime_account_system(struct task_struct *tsk)
> +{
> +	cputime_t delta = vtime_delta(tsk);
> +
> +	account_system_time(tsk, 0, delta, delta);
> +}
> +EXPORT_SYMBOL_GPL(vtime_account_system);
> +
> +void vtime_account_idle(struct task_struct *tsk)
> +{
> +	account_idle_time(vtime_delta(tsk));
> +}
> +
> +#endif
> +
>  #else /* ! CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
>  #define calc_cputime_factors()
>  #endif
> @@ -871,6 +939,8 @@
>  		       ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
>  	}
>  
> +	mttbl(0);
> +	mttbu(0);
>  	tb_ticks_per_jiffy = ppc_tb_freq / HZ;
>  	tb_ticks_per_sec = ppc_tb_freq;
>  	tb_ticks_per_usec = ppc_tb_freq / 1000000;
> Index: b/arch/powerpc/kernel/entry_32.S
> ===================================================================
> --- a/arch/powerpc/kernel/entry_32.S	(revision 5607)
> +++ b/arch/powerpc/kernel/entry_32.S	(revision 5611)
> @@ -177,6 +177,12 @@
>  	addi	r12,r12,-1
>  	stw	r12,4(r11)
>  #endif
> +#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
> +	CURRENT_THREAD_INFO(r9, r1)
> +	tophys(r9, r9)
> +	ACCOUNT_CPU_USER_ENTRY(r9, r11, r12)
> +#endif
> +
>  	b	3f
>  
>  2:	/* if from kernel, check interrupted DOZE/NAP mode and
> @@ -406,6 +412,13 @@
>  	lwarx	r7,0,r1
>  END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
>  	stwcx.	r0,0,r1			/* to clear the reservation */
> +#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
> +	andi.	r4,r8,MSR_PR
> +	beq	3f
> +	CURRENT_THREAD_INFO(r4, r1)
> +	ACCOUNT_CPU_USER_EXIT(r4, r5, r7)
> +3:
> +#endif
>  	lwz	r4,_LINK(r1)
>  	lwz	r5,_CCR(r1)
>  	mtlr	r4
> @@ -841,6 +854,10 @@
>  	andis.	r10,r0,DBCR0_IDM at h
>  	bnel-	load_dbcr0
>  #endif
> +#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
> +	CURRENT_THREAD_INFO(r9, r1)
> +	ACCOUNT_CPU_USER_EXIT(r9, r10, r11)
> +#endif
>  
>  	b	restore
>  
> Index: b/arch/powerpc/kernel/asm-offsets.c
> ===================================================================
> --- a/arch/powerpc/kernel/asm-offsets.c	(revision 5607)
> +++ b/arch/powerpc/kernel/asm-offsets.c	(revision 5611)
> @@ -167,6 +167,12 @@
>  	DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
>  	DEFINE(TI_TASK, offsetof(struct thread_info, task));
>  	DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
> +#if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(CONFIG_PPC32)
> +	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
>  
>  #ifdef CONFIG_PPC64
>  	DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size));
> Index: b/arch/powerpc/include/asm/thread_info.h
> ===================================================================
> --- a/arch/powerpc/include/asm/thread_info.h	(revision 5607)
> +++ b/arch/powerpc/include/asm/thread_info.h	(revision 5611)
> @@ -43,6 +43,12 @@
>  	int		cpu;			/* cpu we're on */
>  	int		preempt_count;		/* 0 => preemptable,
>  						   <0 => BUG */
> +#if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(CONFIG_PPC32)
> +	u32 ac_stamp;
> +	u32 ac_leave;
> +	u32 ac_stime;
> +	u32 ac_utime;
> +#endif
>  	struct restart_block restart_block;
>  	unsigned long	local_flags;		/* private flags for thread */
>  
> Index: b/arch/powerpc/include/asm/cputime.h
> ===================================================================
> --- a/arch/powerpc/include/asm/cputime.h	(revision 5607)
> +++ b/arch/powerpc/include/asm/cputime.h	(revision 5611)
> @@ -228,7 +228,11 @@
>  
>  #define cputime64_to_clock_t(ct)	cputime_to_clock_t((cputime_t)(ct))
>  
> +#ifdef CONFIG_PPC64
>  static inline void arch_vtime_task_switch(struct task_struct *tsk) { }
> +#else
> +extern void arch_vtime_task_switch(struct task_struct *tsk);
> +#endif
>  
>  #endif /* __KERNEL__ */
>  #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
> Index: b/arch/powerpc/include/asm/ppc_asm.h
> ===================================================================
> --- a/arch/powerpc/include/asm/ppc_asm.h	(revision 5607)
> +++ b/arch/powerpc/include/asm/ppc_asm.h	(revision 5611)
> @@ -25,10 +25,16 @@
>   */
>  
>  #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
> +#ifdef CONFIG_PPC64
>  #define ACCOUNT_CPU_USER_ENTRY(ra, rb)
>  #define ACCOUNT_CPU_USER_EXIT(ra, rb)
> +#else /* CONFIG_PPC64 */
> +#define ACCOUNT_CPU_USER_ENTRY(ti, ra, rb)
> +#define ACCOUNT_CPU_USER_EXIT(ti, ra, rb)
> +#endif /* CONFIG_PPC64 */
>  #define ACCOUNT_STOLEN_TIME
> -#else
> +#else /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
> +#ifdef CONFIG_PPC64
>  #define ACCOUNT_CPU_USER_ENTRY(ra, rb)					\
>  	MFTB(ra);			/* get timebase */		\
>  	ld	rb,PACA_STARTTIME_USER(r13);				\
> @@ -68,7 +74,27 @@
>  #define ACCOUNT_STOLEN_TIME
>  
>  #endif /* CONFIG_PPC_SPLPAR */
> +#else /* CONFIG_PPC64 */
> +#define ACCOUNT_CPU_USER_ENTRY(ti, ra, rb)				\
> +	MFTB(ra);							\
> +	lwz rb, TI_AC_LEAVE(ti);					\
> +	stw ra, TI_AC_STAMP(ti);	/* AC_STAMP = NOW */		\
> +	subf rb, rb, ra;		/* R = NOW - AC_LEAVE */	\
> +	lwz ra, TI_AC_UTIME(ti);					\
> +	add ra, rb, ra;			/* AC_UTIME += R */		\
> +	stw ra, TI_AC_UTIME(ti);					\
>  
> +#define ACCOUNT_CPU_USER_EXIT(ti, ra, rb)				\
> +	MFTB(ra);							\
> +	lwz rb, TI_AC_STAMP(ti);					\
> +	stw ra, TI_AC_LEAVE(ti);					\
> +	subf rb, rb, ra;		/* R = NOW - AC_STAMP */	\
> +	lwz ra, TI_AC_STIME(ti);					\
> +	add ra, rb, ra;			/* AC_STIME += R */		\
> +	stw ra, TI_AC_STIME(ti);					\
> +
> +#endif /* CONFIG_PPC64 */
> +
>  #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
>  
>  /*
> Index: b/arch/powerpc/platforms/Kconfig.cputype
> ===================================================================
> --- a/arch/powerpc/platforms/Kconfig.cputype	(revision 5607)
> +++ b/arch/powerpc/platforms/Kconfig.cputype	(revision 5611)
> @@ -1,7 +1,6 @@
>  config PPC64
>  	bool "64-bit kernel"
>  	default n
> -	select HAVE_VIRT_CPU_ACCOUNTING
>  	help
>  	  This option selects whether a 32-bit or a 64-bit kernel
>  	  will be built.




More information about the Linuxppc-dev mailing list