aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/time.c
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2007-10-18 06:06:37 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:28 -0400
commit4603ac180a824197c2262747948d0179eb076e9c (patch)
tree975f9a88b95f69e1099ad22c58717b182e6416fc /arch/powerpc/kernel/time.c
parentf494f8fcb18e962839a82d542fbe6bed9cf5be07 (diff)
powerpc: add scaled time accounting
This adds POWERPC specific hooks for scaled time accounting. POWER6 includes a SPURR register. The SPURR is based off the PURR register but is scaled based on CPU frequency and issue rates. This gives a more accurate account of the instructions used per task. The PURR and timebase will be constant relative to the wall clock, irrespective of the CPU frequency. This implementation reads the SPURR register in account_system_vtime which is only call called on context witch and hard and soft irq entry and exit. The percentage of user and system time is then estimated using the ratio of these accounted by the PURR. If the SPURR is not present, the PURR read. An earlier implementation of this patch read the SPURR whenever the PURR was read, which included the system call entry and exit path. Unfortunately this showed a performance regression on lmbench runs, so was re-implemented. I've included the lmbench results here when run bare metal on POWER6. 1st column is the unpatch results. 2nd column is the results using the below patch and the 3rd is the % diff of these results from the base. 4th and 5th columns are the results and % differnce from the base using the older patch (SPURR read in syscall entry/exit path). Base Scaled-Acct SPURR-in-syscall Result Result % diff Result % diff Simple syscall: 0.3086 0.3086 0.0000 0.3452 11.8600 Simple read: 0.4591 0.4671 1.7425 0.5044 9.86713 Simple write: 0.4364 0.4366 0.0458 0.4731 8.40971 Simple stat: 2.0055 2.0295 1.1967 2.0669 3.06158 Simple fstat: 0.5962 0.5876 -1.442 0.6368 6.80979 Simple open/close: 3.1283 3.1009 -0.875 3.2088 2.57328 Select on 10 fd's: 0.8554 0.8457 -1.133 0.8667 1.32101 Select on 100 fd's: 3.5292 3.6329 2.9383 3.6664 3.88756 Select on 250 fd's: 7.9097 8.1881 3.5197 8.2242 3.97613 Select on 500 fd's: 15.2659 15.836 3.7357 15.873 3.97814 Select on 10 tcp fd's: 0.9576 0.9416 -1.670 0.9752 1.83792 Select on 100 tcp fd's: 7.248 7.2254 -0.311 7.2685 0.28283 Select on 250 tcp fd's: 17.7742 17.707 -0.375 17.749 -0.1406 Select on 500 tcp fd's: 35.4258 35.25 -0.496 35.286 -0.3929 Signal handler installation: 0.6131 0.6075 -0.913 0.647 5.52927 Signal handler overhead: 2.0919 2.1078 0.7600 2.1831 4.35967 Protection fault: 0.7345 0.7478 1.8107 0.8031 9.33968 Pipe latency: 33.006 16.398 -50.31 33.475 1.42368 AF_UNIX sock stream latency: 14.5093 30.910 113.03 30.715 111.692 Process fork+exit: 219.8 222.8 1.3648 229.37 4.35623 Process fork+execve: 876.14 873.28 -0.32 868.66 -0.8533 Process fork+/bin/sh -c: 2830 2876.5 1.6431 2958 4.52296 File /var/tmp/XXX write bw: 1193497 1195536 0.1708 118657 -0.5799 Pagefaults on /var/tmp/XXX: 3.1272 3.2117 2.7020 3.2521 3.99398 Also, kernel compile times show no difference with this patch applied. [pbadari@us.ibm.com: Avoid unnecessary PURR reading] Signed-off-by: Michael Neuling <mikey@neuling.org> Cc: Balbir Singh <balbir@in.ibm.com> Cc: Jay Lan <jlan@engr.sgi.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/powerpc/kernel/time.c')
-rw-r--r--arch/powerpc/kernel/time.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 863a5d6d9b1..9eb3284deac 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -212,23 +212,44 @@ static u64 read_purr(void)
212} 212}
213 213
214/* 214/*
215 * Read the SPURR on systems that have it, otherwise the purr
216 */
217static u64 read_spurr(u64 purr)
218{
219 if (cpu_has_feature(CPU_FTR_SPURR))
220 return mfspr(SPRN_SPURR);
221 return purr;
222}
223
224/*
215 * Account time for a transition between system, hard irq 225 * Account time for a transition between system, hard irq
216 * or soft irq state. 226 * or soft irq state.
217 */ 227 */
218void account_system_vtime(struct task_struct *tsk) 228void account_system_vtime(struct task_struct *tsk)
219{ 229{
220 u64 now, delta; 230 u64 now, nowscaled, delta, deltascaled;
221 unsigned long flags; 231 unsigned long flags;
222 232
223 local_irq_save(flags); 233 local_irq_save(flags);
224 now = read_purr(); 234 now = read_purr();
225 delta = now - get_paca()->startpurr; 235 delta = now - get_paca()->startpurr;
226 get_paca()->startpurr = now; 236 get_paca()->startpurr = now;
237 nowscaled = read_spurr(now);
238 deltascaled = nowscaled - get_paca()->startspurr;
239 get_paca()->startspurr = nowscaled;
227 if (!in_interrupt()) { 240 if (!in_interrupt()) {
241 /* deltascaled includes both user and system time.
242 * Hence scale it based on the purr ratio to estimate
243 * the system time */
244 deltascaled = deltascaled * get_paca()->system_time /
245 (get_paca()->system_time + get_paca()->user_time);
228 delta += get_paca()->system_time; 246 delta += get_paca()->system_time;
229 get_paca()->system_time = 0; 247 get_paca()->system_time = 0;
230 } 248 }
231 account_system_time(tsk, 0, delta); 249 account_system_time(tsk, 0, delta);
250 get_paca()->purrdelta = delta;
251 account_system_time_scaled(tsk, deltascaled);
252 get_paca()->spurrdelta = deltascaled;
232 local_irq_restore(flags); 253 local_irq_restore(flags);
233} 254}
234 255
@@ -240,11 +261,17 @@ void account_system_vtime(struct task_struct *tsk)
240 */ 261 */
241void account_process_vtime(struct task_struct *tsk) 262void account_process_vtime(struct task_struct *tsk)
242{ 263{
243 cputime_t utime; 264 cputime_t utime, utimescaled;
244 265
245 utime = get_paca()->user_time; 266 utime = get_paca()->user_time;
246 get_paca()->user_time = 0; 267 get_paca()->user_time = 0;
247 account_user_time(tsk, utime); 268 account_user_time(tsk, utime);
269
270 /* Estimate the scaled utime by scaling the real utime based
271 * on the last spurr to purr ratio */
272 utimescaled = utime * get_paca()->spurrdelta / get_paca()->purrdelta;
273 get_paca()->spurrdelta = get_paca()->purrdelta = 0;
274 account_user_time_scaled(tsk, utimescaled);
248} 275}
249 276
250static void account_process_time(struct pt_regs *regs) 277static void account_process_time(struct pt_regs *regs)
@@ -266,6 +293,7 @@ struct cpu_purr_data {
266 int initialized; /* thread is running */ 293 int initialized; /* thread is running */
267 u64 tb; /* last TB value read */ 294 u64 tb; /* last TB value read */
268 u64 purr; /* last PURR value read */ 295 u64 purr; /* last PURR value read */
296 u64 spurr; /* last SPURR value read */
269}; 297};
270 298
271/* 299/*