Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

powerpc/pseries: Move dtl scanning and steal time accounting to pseries platform

dtl is the PAPR Dispatch Trace Log, which is entirely a pseries feature.
The pseries platform alrady has a file dealing with the dtl, so move
scanning for stolen time accounting there from kernel/time.c.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220902085316.2071519-5-npiggin@gmail.com

authored by

Nicholas Piggin and committed by
Michael Ellerman
6ba5aa54 02382aff

+90 -98
+1 -1
arch/powerpc/include/asm/cputime.h
··· 95 95 struct lppaca *lp = local_paca->lppaca_ptr; 96 96 97 97 if (unlikely(local_paca->dtl_ridx != be64_to_cpu(lp->dtl_idx))) 98 - accumulate_stolen_time(); 98 + pseries_accumulate_stolen_time(); 99 99 } 100 100 #endif 101 101 }
-8
arch/powerpc/include/asm/dtl.h
··· 37 37 extern struct kmem_cache *dtl_cache; 38 38 extern rwlock_t dtl_access_lock; 39 39 40 - /* 41 - * When CONFIG_VIRT_CPU_ACCOUNTING_NATIVE = y, the cpu accounting code controls 42 - * reading from the dispatch trace log. If other code wants to consume 43 - * DTL entries, it can set this pointer to a function that will get 44 - * called once for each DTL entry that gets processed. 45 - */ 46 - extern void (*dtl_consumer)(struct dtl_entry *entry, u64 index); 47 - 48 40 extern void register_dtl_buffer(int cpu); 49 41 extern void alloc_dtl_buffers(unsigned long *time_limit); 50 42 extern long hcall_vphn(unsigned long cpu, u64 flags, __be32 *associativity);
+3 -2
arch/powerpc/include/asm/time.h
··· 116 116 117 117 void timer_broadcast_interrupt(void); 118 118 119 - /* SPLPAR */ 120 - void accumulate_stolen_time(void); 119 + /* SPLPAR and VIRT_CPU_ACCOUNTING_NATIVE */ 120 + void pseries_accumulate_stolen_time(void); 121 + u64 pseries_calculate_stolen_time(u64 stop_tb); 121 122 122 123 #endif /* __KERNEL__ */ 123 124 #endif /* __POWERPC_TIME_H */
+5 -87
arch/powerpc/kernel/time.c
··· 178 178 return tb; 179 179 } 180 180 181 - #ifdef CONFIG_PPC_SPLPAR 182 - 183 - #include <asm/dtl.h> 184 - 185 - void (*dtl_consumer)(struct dtl_entry *, u64); 186 - 187 - /* 188 - * Scan the dispatch trace log and count up the stolen time. 189 - * Should be called with interrupts disabled. 190 - */ 191 - static u64 scan_dispatch_log(u64 stop_tb) 192 - { 193 - u64 i = local_paca->dtl_ridx; 194 - struct dtl_entry *dtl = local_paca->dtl_curr; 195 - struct dtl_entry *dtl_end = local_paca->dispatch_log_end; 196 - struct lppaca *vpa = local_paca->lppaca_ptr; 197 - u64 tb_delta; 198 - u64 stolen = 0; 199 - u64 dtb; 200 - 201 - if (!dtl) 202 - return 0; 203 - 204 - if (i == be64_to_cpu(vpa->dtl_idx)) 205 - return 0; 206 - while (i < be64_to_cpu(vpa->dtl_idx)) { 207 - dtb = be64_to_cpu(dtl->timebase); 208 - tb_delta = be32_to_cpu(dtl->enqueue_to_dispatch_time) + 209 - be32_to_cpu(dtl->ready_to_enqueue_time); 210 - barrier(); 211 - if (i + N_DISPATCH_LOG < be64_to_cpu(vpa->dtl_idx)) { 212 - /* buffer has overflowed */ 213 - i = be64_to_cpu(vpa->dtl_idx) - N_DISPATCH_LOG; 214 - dtl = local_paca->dispatch_log + (i % N_DISPATCH_LOG); 215 - continue; 216 - } 217 - if (dtb > stop_tb) 218 - break; 219 - if (dtl_consumer) 220 - dtl_consumer(dtl, i); 221 - stolen += tb_delta; 222 - ++i; 223 - ++dtl; 224 - if (dtl == dtl_end) 225 - dtl = local_paca->dispatch_log; 226 - } 227 - local_paca->dtl_ridx = i; 228 - local_paca->dtl_curr = dtl; 229 - return stolen; 230 - } 231 - 232 - /* 233 - * Accumulate stolen time by scanning the dispatch trace log. 234 - * Called on entry from user mode. 235 - */ 236 - void notrace accumulate_stolen_time(void) 237 - { 238 - u64 sst, ust; 239 - struct cpu_accounting_data *acct = &local_paca->accounting; 240 - 241 - sst = scan_dispatch_log(acct->starttime_user); 242 - ust = scan_dispatch_log(acct->starttime); 243 - acct->stime -= sst; 244 - acct->utime -= ust; 245 - acct->steal_time += ust + sst; 246 - } 247 - 248 - static inline u64 calculate_stolen_time(u64 stop_tb) 249 - { 250 - if (!firmware_has_feature(FW_FEATURE_SPLPAR)) 251 - return 0; 252 - 253 - if (get_paca()->dtl_ridx != be64_to_cpu(get_lppaca()->dtl_idx)) 254 - return scan_dispatch_log(stop_tb); 255 - 256 - return 0; 257 - } 258 - 259 - #else /* CONFIG_PPC_SPLPAR */ 260 - static inline u64 calculate_stolen_time(u64 stop_tb) 261 - { 262 - return 0; 263 - } 264 - 265 - #endif /* CONFIG_PPC_SPLPAR */ 266 - 267 181 /* 268 182 * Account time for a transition between system, hard irq 269 183 * or soft irq state. ··· 236 322 237 323 *stime_scaled = vtime_delta_scaled(acct, now, stime); 238 324 239 - *steal_time = calculate_stolen_time(now); 325 + if (IS_ENABLED(CONFIG_PPC_SPLPAR) && 326 + firmware_has_feature(FW_FEATURE_SPLPAR)) 327 + *steal_time = pseries_calculate_stolen_time(now); 328 + else 329 + *steal_time = 0; 240 330 241 331 return stime; 242 332 }
+81
arch/powerpc/platforms/pseries/dtl.c
··· 37 37 static int dtl_buf_entries = N_DISPATCH_LOG; 38 38 39 39 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 40 + 41 + /* 42 + * When CONFIG_VIRT_CPU_ACCOUNTING_NATIVE = y, the cpu accounting code controls 43 + * reading from the dispatch trace log. If other code wants to consume 44 + * DTL entries, it can set this pointer to a function that will get 45 + * called once for each DTL entry that gets processed. 46 + */ 47 + static void (*dtl_consumer)(struct dtl_entry *entry, u64 index); 48 + 40 49 struct dtl_ring { 41 50 u64 write_index; 42 51 struct dtl_entry *write_ptr; ··· 56 47 static DEFINE_PER_CPU(struct dtl_ring, dtl_rings); 57 48 58 49 static atomic_t dtl_count; 50 + 51 + /* 52 + * Scan the dispatch trace log and count up the stolen time. 53 + * Should be called with interrupts disabled. 54 + */ 55 + static notrace u64 scan_dispatch_log(u64 stop_tb) 56 + { 57 + u64 i = local_paca->dtl_ridx; 58 + struct dtl_entry *dtl = local_paca->dtl_curr; 59 + struct dtl_entry *dtl_end = local_paca->dispatch_log_end; 60 + struct lppaca *vpa = local_paca->lppaca_ptr; 61 + u64 tb_delta; 62 + u64 stolen = 0; 63 + u64 dtb; 64 + 65 + if (!dtl) 66 + return 0; 67 + 68 + if (i == be64_to_cpu(vpa->dtl_idx)) 69 + return 0; 70 + while (i < be64_to_cpu(vpa->dtl_idx)) { 71 + dtb = be64_to_cpu(dtl->timebase); 72 + tb_delta = be32_to_cpu(dtl->enqueue_to_dispatch_time) + 73 + be32_to_cpu(dtl->ready_to_enqueue_time); 74 + barrier(); 75 + if (i + N_DISPATCH_LOG < be64_to_cpu(vpa->dtl_idx)) { 76 + /* buffer has overflowed */ 77 + i = be64_to_cpu(vpa->dtl_idx) - N_DISPATCH_LOG; 78 + dtl = local_paca->dispatch_log + (i % N_DISPATCH_LOG); 79 + continue; 80 + } 81 + if (dtb > stop_tb) 82 + break; 83 + if (dtl_consumer) 84 + dtl_consumer(dtl, i); 85 + stolen += tb_delta; 86 + ++i; 87 + ++dtl; 88 + if (dtl == dtl_end) 89 + dtl = local_paca->dispatch_log; 90 + } 91 + local_paca->dtl_ridx = i; 92 + local_paca->dtl_curr = dtl; 93 + return stolen; 94 + } 95 + 96 + /* 97 + * Accumulate stolen time by scanning the dispatch trace log. 98 + * Called on entry from user mode. 99 + */ 100 + void notrace pseries_accumulate_stolen_time(void) 101 + { 102 + u64 sst, ust; 103 + struct cpu_accounting_data *acct = &local_paca->accounting; 104 + 105 + sst = scan_dispatch_log(acct->starttime_user); 106 + ust = scan_dispatch_log(acct->starttime); 107 + acct->stime -= sst; 108 + acct->utime -= ust; 109 + acct->steal_time += ust + sst; 110 + } 111 + 112 + u64 pseries_calculate_stolen_time(u64 stop_tb) 113 + { 114 + if (!firmware_has_feature(FW_FEATURE_SPLPAR)) 115 + return 0; 116 + 117 + if (get_paca()->dtl_ridx != be64_to_cpu(get_lppaca()->dtl_idx)) 118 + return scan_dispatch_log(stop_tb); 119 + 120 + return 0; 121 + } 59 122 60 123 /* 61 124 * The cpu accounting code controls the DTL ring buffer, and we get