aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/include
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2010-08-26 15:56:43 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-09-02 00:07:31 -0400
commitcf9efce0ce3136fa076f53e53154e98455229514 (patch)
tree0e110018b160aff4813b81e0e8c3a43a364edd48 /arch/powerpc/include
parent93c22703efa72c7527dbd586d1951c1f4a85fd70 (diff)
powerpc: Account time using timebase rather than PURR
Currently, when CONFIG_VIRT_CPU_ACCOUNTING is enabled, we use the PURR register for measuring the user and system time used by processes, as well as other related times such as hardirq and softirq times. This turns out to be quite confusing for users because it means that a program will often be measured as taking less time when run on a multi-threaded processor (SMT2 or SMT4 mode) than it does when run on a single-threaded processor (ST mode), even though the program takes longer to finish. The discrepancy is accounted for as stolen time, which is also confusing, particularly when there are no other partitions running. This changes the accounting to use the timebase instead, meaning that the reported user and system times are the actual number of real-time seconds that the program was executing on the processor thread, regardless of which SMT mode the processor is in. Thus a program will generally show greater user and system times when run on a multi-threaded processor than on a single-threaded processor. On pSeries systems on POWER5 or later processors, we measure the stolen time (time when this partition wasn't running) using the hypervisor dispatch trace log. We check for new entries in the log on every entry from user mode and on every transition from kernel process context to soft or hard IRQ context (i.e. when account_system_vtime() gets called). So that we can correctly distinguish time stolen from user time and time stolen from system time, without having to check the log on every exit to user mode, we store separate timestamps for exit to user mode and entry from user mode. On systems that have a SPURR (POWER6 and POWER7), we read the SPURR in account_system_vtime() (as before), and then apportion the SPURR ticks since the last time we read it between scaled user time and scaled system time according to the relative proportions of user time and system time over the same interval. This avoids having to read the SPURR on every kernel entry and exit. On systems that have PURR but not SPURR (i.e., POWER5), we do the same using the PURR rather than the SPURR. This disables the DTL user interface in /sys/debug/kernel/powerpc/dtl for now since it conflicts with the use of the dispatch trace log by the time accounting code. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/include')
-rw-r--r--arch/powerpc/include/asm/exception-64s.h3
-rw-r--r--arch/powerpc/include/asm/lppaca.h19
-rw-r--r--arch/powerpc/include/asm/paca.h10
-rw-r--r--arch/powerpc/include/asm/ppc_asm.h50
-rw-r--r--arch/powerpc/include/asm/time.h5
5 files changed, 61 insertions, 26 deletions
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 57c400071995..7778d6f0c878 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -137,7 +137,8 @@
137 li r10,0; \ 137 li r10,0; \
138 ld r11,exception_marker@toc(r2); \ 138 ld r11,exception_marker@toc(r2); \
139 std r10,RESULT(r1); /* clear regs->result */ \ 139 std r10,RESULT(r1); /* clear regs->result */ \
140 std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ 140 std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ \
141 ACCOUNT_STOLEN_TIME
141 142
142/* 143/*
143 * Exception vectors. 144 * Exception vectors.
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index 6d02624b622c..cfb85ec85750 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -172,6 +172,25 @@ struct slb_shadow {
172 172
173extern struct slb_shadow slb_shadow[]; 173extern struct slb_shadow slb_shadow[];
174 174
175/*
176 * Layout of entries in the hypervisor's dispatch trace log buffer.
177 */
178struct dtl_entry {
179 u8 dispatch_reason;
180 u8 preempt_reason;
181 u16 processor_id;
182 u32 enqueue_to_dispatch_time;
183 u32 ready_to_enqueue_time;
184 u32 waiting_to_ready_time;
185 u64 timebase;
186 u64 fault_addr;
187 u64 srr0;
188 u64 srr1;
189};
190
191#define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */
192#define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry))
193
175#endif /* CONFIG_PPC_BOOK3S */ 194#endif /* CONFIG_PPC_BOOK3S */
176#endif /* __KERNEL__ */ 195#endif /* __KERNEL__ */
177#endif /* _ASM_POWERPC_LPPACA_H */ 196#endif /* _ASM_POWERPC_LPPACA_H */
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 1ff6662f7faf..6af6c1613409 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -85,6 +85,8 @@ struct paca_struct {
85 u8 kexec_state; /* set when kexec down has irqs off */ 85 u8 kexec_state; /* set when kexec down has irqs off */
86#ifdef CONFIG_PPC_STD_MMU_64 86#ifdef CONFIG_PPC_STD_MMU_64
87 struct slb_shadow *slb_shadow_ptr; 87 struct slb_shadow *slb_shadow_ptr;
88 struct dtl_entry *dispatch_log;
89 struct dtl_entry *dispatch_log_end;
88 90
89 /* 91 /*
90 * Now, starting in cacheline 2, the exception save areas 92 * Now, starting in cacheline 2, the exception save areas
@@ -134,8 +136,14 @@ struct paca_struct {
134 /* Stuff for accurate time accounting */ 136 /* Stuff for accurate time accounting */
135 u64 user_time; /* accumulated usermode TB ticks */ 137 u64 user_time; /* accumulated usermode TB ticks */
136 u64 system_time; /* accumulated system TB ticks */ 138 u64 system_time; /* accumulated system TB ticks */
137 u64 startpurr; /* PURR/TB value snapshot */ 139 u64 user_time_scaled; /* accumulated usermode SPURR ticks */
140 u64 starttime; /* TB value snapshot */
141 u64 starttime_user; /* TB value on exit to usermode */
138 u64 startspurr; /* SPURR value snapshot */ 142 u64 startspurr; /* SPURR value snapshot */
143 u64 utime_sspurr; /* ->user_time when ->startspurr set */
144 u64 stolen_time; /* TB ticks taken by hypervisor */
145 u64 dtl_ridx; /* read index in dispatch log */
146 struct dtl_entry *dtl_curr; /* pointer corresponding to dtl_ridx */
139 147
140#ifdef CONFIG_KVM_BOOK3S_HANDLER 148#ifdef CONFIG_KVM_BOOK3S_HANDLER
141 /* We use this to store guest state in */ 149 /* We use this to store guest state in */
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index 498fe09263d3..98210067c1cc 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -9,6 +9,7 @@
9#include <asm/asm-compat.h> 9#include <asm/asm-compat.h>
10#include <asm/processor.h> 10#include <asm/processor.h>
11#include <asm/ppc-opcode.h> 11#include <asm/ppc-opcode.h>
12#include <asm/firmware.h>
12 13
13#ifndef __ASSEMBLY__ 14#ifndef __ASSEMBLY__
14#error __FILE__ should only be used in assembler files 15#error __FILE__ should only be used in assembler files
@@ -26,17 +27,13 @@
26#ifndef CONFIG_VIRT_CPU_ACCOUNTING 27#ifndef CONFIG_VIRT_CPU_ACCOUNTING
27#define ACCOUNT_CPU_USER_ENTRY(ra, rb) 28#define ACCOUNT_CPU_USER_ENTRY(ra, rb)
28#define ACCOUNT_CPU_USER_EXIT(ra, rb) 29#define ACCOUNT_CPU_USER_EXIT(ra, rb)
30#define ACCOUNT_STOLEN_TIME
29#else 31#else
30#define ACCOUNT_CPU_USER_ENTRY(ra, rb) \ 32#define ACCOUNT_CPU_USER_ENTRY(ra, rb) \
31 beq 2f; /* if from kernel mode */ \ 33 beq 2f; /* if from kernel mode */ \
32BEGIN_FTR_SECTION; \ 34 MFTB(ra); /* get timebase */ \
33 mfspr ra,SPRN_PURR; /* get processor util. reg */ \ 35 ld rb,PACA_STARTTIME_USER(r13); \
34END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ 36 std ra,PACA_STARTTIME(r13); \
35BEGIN_FTR_SECTION; \
36 MFTB(ra); /* or get TB if no PURR */ \
37END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
38 ld rb,PACA_STARTPURR(r13); \
39 std ra,PACA_STARTPURR(r13); \
40 subf rb,rb,ra; /* subtract start value */ \ 37 subf rb,rb,ra; /* subtract start value */ \
41 ld ra,PACA_USER_TIME(r13); \ 38 ld ra,PACA_USER_TIME(r13); \
42 add ra,ra,rb; /* add on to user time */ \ 39 add ra,ra,rb; /* add on to user time */ \
@@ -44,19 +41,34 @@ END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
442: 412:
45 42
46#define ACCOUNT_CPU_USER_EXIT(ra, rb) \ 43#define ACCOUNT_CPU_USER_EXIT(ra, rb) \
47BEGIN_FTR_SECTION; \ 44 MFTB(ra); /* get timebase */ \
48 mfspr ra,SPRN_PURR; /* get processor util. reg */ \ 45 ld rb,PACA_STARTTIME(r13); \
49END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ 46 std ra,PACA_STARTTIME_USER(r13); \
50BEGIN_FTR_SECTION; \
51 MFTB(ra); /* or get TB if no PURR */ \
52END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
53 ld rb,PACA_STARTPURR(r13); \
54 std ra,PACA_STARTPURR(r13); \
55 subf rb,rb,ra; /* subtract start value */ \ 47 subf rb,rb,ra; /* subtract start value */ \
56 ld ra,PACA_SYSTEM_TIME(r13); \ 48 ld ra,PACA_SYSTEM_TIME(r13); \
57 add ra,ra,rb; /* add on to user time */ \ 49 add ra,ra,rb; /* add on to system time */ \
58 std ra,PACA_SYSTEM_TIME(r13); 50 std ra,PACA_SYSTEM_TIME(r13)
59#endif 51
52#ifdef CONFIG_PPC_SPLPAR
53#define ACCOUNT_STOLEN_TIME \
54BEGIN_FW_FTR_SECTION; \
55 beq 33f; \
56 /* from user - see if there are any DTL entries to process */ \
57 ld r10,PACALPPACAPTR(r13); /* get ptr to VPA */ \
58 ld r11,PACA_DTL_RIDX(r13); /* get log read index */ \
59 ld r10,LPPACA_DTLIDX(r10); /* get log write index */ \
60 cmpd cr1,r11,r10; \
61 beq+ cr1,33f; \
62 bl .accumulate_stolen_time; \
6333: \
64END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
65
66#else /* CONFIG_PPC_SPLPAR */
67#define ACCOUNT_STOLEN_TIME
68
69#endif /* CONFIG_PPC_SPLPAR */
70
71#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
60 72
61/* 73/*
62 * Macros for storing registers into and loading registers from 74 * Macros for storing registers into and loading registers from
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index dc779dfcf258..fe6f7c2c9c68 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -34,7 +34,6 @@ extern void to_tm(int tim, struct rtc_time * tm);
34extern void GregorianDay(struct rtc_time *tm); 34extern void GregorianDay(struct rtc_time *tm);
35 35
36extern void generic_calibrate_decr(void); 36extern void generic_calibrate_decr(void);
37extern void snapshot_timebase(void);
38 37
39extern void set_dec_cpu6(unsigned int val); 38extern void set_dec_cpu6(unsigned int val);
40 39
@@ -212,12 +211,8 @@ struct cpu_usage {
212DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array); 211DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);
213 212
214#if defined(CONFIG_VIRT_CPU_ACCOUNTING) 213#if defined(CONFIG_VIRT_CPU_ACCOUNTING)
215extern void calculate_steal_time(void);
216extern void snapshot_timebases(void);
217#define account_process_vtime(tsk) account_process_tick(tsk, 0) 214#define account_process_vtime(tsk) account_process_tick(tsk, 0)
218#else 215#else
219#define calculate_steal_time() do { } while (0)
220#define snapshot_timebases() do { } while (0)
221#define account_process_vtime(tsk) do { } while (0) 216#define account_process_vtime(tsk) do { } while (0)
222#endif 217#endif
223 218