summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2016-07-13 13:16:59 -0400
committerIngo Molnar <mingo@kernel.org>2016-07-15 04:41:42 -0400
commite722d8daafb974b9ad1bbaf42f384a5ea5929f5f (patch)
tree4606da52182007488af7086c1ff4867ef8f0093f
parent24f73b99716a9cd8cbb345c41ced6b3b5ed94006 (diff)
profile: Convert to hotplug state machine
Install the callbacks via the state machine and let the core invoke the callbacks on the already online CPUs. A lot of code is removed because the for-loop is used and create_hash_tables() is removed since its purpose is covered by the startup / teardown hooks. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mel Gorman <mgorman@techsingularity.net> Cc: Michal Hocko <mhocko@suse.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160713153337.649867675@linutronix.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/linux/cpuhotplug.h1
-rw-r--r--kernel/profile.c181
2 files changed, 66 insertions, 116 deletions
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 15d46d2a1d16..ace5ad0fc3ec 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -16,6 +16,7 @@ enum cpuhp_state {
16 CPUHP_X86_APB_DEAD, 16 CPUHP_X86_APB_DEAD,
17 CPUHP_WORKQUEUE_PREP, 17 CPUHP_WORKQUEUE_PREP,
18 CPUHP_HRTIMERS_PREPARE, 18 CPUHP_HRTIMERS_PREPARE,
19 CPUHP_PROFILE_PREPARE,
19 CPUHP_TIMERS_DEAD, 20 CPUHP_TIMERS_DEAD,
20 CPUHP_NOTIFY_PREPARE, 21 CPUHP_NOTIFY_PREPARE,
21 CPUHP_BRINGUP_CPU, 22 CPUHP_BRINGUP_CPU,
diff --git a/kernel/profile.c b/kernel/profile.c
index c2199e9901c9..2dbccf2d806c 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -328,68 +328,57 @@ out:
328 put_cpu(); 328 put_cpu();
329} 329}
330 330
331static int profile_cpu_callback(struct notifier_block *info, 331static int profile_dead_cpu(unsigned int cpu)
332 unsigned long action, void *__cpu)
333{ 332{
334 int node, cpu = (unsigned long)__cpu;
335 struct page *page; 333 struct page *page;
334 int i;
336 335
337 switch (action) { 336 if (prof_cpu_mask != NULL)
338 case CPU_UP_PREPARE: 337 cpumask_clear_cpu(cpu, prof_cpu_mask);
339 case CPU_UP_PREPARE_FROZEN: 338
340 node = cpu_to_mem(cpu); 339 for (i = 0; i < 2; i++) {
341 per_cpu(cpu_profile_flip, cpu) = 0; 340 if (per_cpu(cpu_profile_hits, cpu)[i]) {
342 if (!per_cpu(cpu_profile_hits, cpu)[1]) { 341 page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[i]);
343 page = __alloc_pages_node(node, 342 per_cpu(cpu_profile_hits, cpu)[i] = NULL;
344 GFP_KERNEL | __GFP_ZERO,
345 0);
346 if (!page)
347 return notifier_from_errno(-ENOMEM);
348 per_cpu(cpu_profile_hits, cpu)[1] = page_address(page);
349 }
350 if (!per_cpu(cpu_profile_hits, cpu)[0]) {
351 page = __alloc_pages_node(node,
352 GFP_KERNEL | __GFP_ZERO,
353 0);
354 if (!page)
355 goto out_free;
356 per_cpu(cpu_profile_hits, cpu)[0] = page_address(page);
357 }
358 break;
359out_free:
360 page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
361 per_cpu(cpu_profile_hits, cpu)[1] = NULL;
362 __free_page(page);
363 return notifier_from_errno(-ENOMEM);
364 case CPU_ONLINE:
365 case CPU_ONLINE_FROZEN:
366 if (prof_cpu_mask != NULL)
367 cpumask_set_cpu(cpu, prof_cpu_mask);
368 break;
369 case CPU_UP_CANCELED:
370 case CPU_UP_CANCELED_FROZEN:
371 case CPU_DEAD:
372 case CPU_DEAD_FROZEN:
373 if (prof_cpu_mask != NULL)
374 cpumask_clear_cpu(cpu, prof_cpu_mask);
375 if (per_cpu(cpu_profile_hits, cpu)[0]) {
376 page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
377 per_cpu(cpu_profile_hits, cpu)[0] = NULL;
378 __free_page(page); 343 __free_page(page);
379 } 344 }
380 if (per_cpu(cpu_profile_hits, cpu)[1]) { 345 }
381 page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]); 346 return 0;
382 per_cpu(cpu_profile_hits, cpu)[1] = NULL; 347}
383 __free_page(page); 348
349static int profile_prepare_cpu(unsigned int cpu)
350{
351 int i, node = cpu_to_mem(cpu);
352 struct page *page;
353
354 per_cpu(cpu_profile_flip, cpu) = 0;
355
356 for (i = 0; i < 2; i++) {
357 if (per_cpu(cpu_profile_hits, cpu)[i])
358 continue;
359
360 page = __alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
361 if (!page) {
362 profile_dead_cpu(cpu);
363 return -ENOMEM;
384 } 364 }
385 break; 365 per_cpu(cpu_profile_hits, cpu)[i] = page_address(page);
366
386 } 367 }
387 return NOTIFY_OK; 368 return 0;
369}
370
371static int profile_online_cpu(unsigned int cpu)
372{
373 if (prof_cpu_mask != NULL)
374 cpumask_set_cpu(cpu, prof_cpu_mask);
375
376 return 0;
388} 377}
378
389#else /* !CONFIG_SMP */ 379#else /* !CONFIG_SMP */
390#define profile_flip_buffers() do { } while (0) 380#define profile_flip_buffers() do { } while (0)
391#define profile_discard_flip_buffers() do { } while (0) 381#define profile_discard_flip_buffers() do { } while (0)
392#define profile_cpu_callback NULL
393 382
394static void do_profile_hits(int type, void *__pc, unsigned int nr_hits) 383static void do_profile_hits(int type, void *__pc, unsigned int nr_hits)
395{ 384{
@@ -531,83 +520,43 @@ static const struct file_operations proc_profile_operations = {
531 .llseek = default_llseek, 520 .llseek = default_llseek,
532}; 521};
533 522
534#ifdef CONFIG_SMP 523int __ref create_proc_profile(void)
535static void profile_nop(void *unused)
536{
537}
538
539static int create_hash_tables(void)
540{ 524{
541 int cpu; 525 struct proc_dir_entry *entry;
542 526#ifdef CONFIG_SMP
543 for_each_online_cpu(cpu) { 527 enum cpuhp_state online_state;
544 int node = cpu_to_mem(cpu);
545 struct page *page;
546
547 page = __alloc_pages_node(node,
548 GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
549 0);
550 if (!page)
551 goto out_cleanup;
552 per_cpu(cpu_profile_hits, cpu)[1]
553 = (struct profile_hit *)page_address(page);
554 page = __alloc_pages_node(node,
555 GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
556 0);
557 if (!page)
558 goto out_cleanup;
559 per_cpu(cpu_profile_hits, cpu)[0]
560 = (struct profile_hit *)page_address(page);
561 }
562 return 0;
563out_cleanup:
564 prof_on = 0;
565 smp_mb();
566 on_each_cpu(profile_nop, NULL, 1);
567 for_each_online_cpu(cpu) {
568 struct page *page;
569
570 if (per_cpu(cpu_profile_hits, cpu)[0]) {
571 page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
572 per_cpu(cpu_profile_hits, cpu)[0] = NULL;
573 __free_page(page);
574 }
575 if (per_cpu(cpu_profile_hits, cpu)[1]) {
576 page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
577 per_cpu(cpu_profile_hits, cpu)[1] = NULL;
578 __free_page(page);
579 }
580 }
581 return -1;
582}
583#else
584#define create_hash_tables() ({ 0; })
585#endif 528#endif
586 529
587int __ref create_proc_profile(void) /* false positive from hotcpu_notifier */
588{
589 struct proc_dir_entry *entry;
590 int err = 0; 530 int err = 0;
591 531
592 if (!prof_on) 532 if (!prof_on)
593 return 0; 533 return 0;
594 534#ifdef CONFIG_SMP
595 cpu_notifier_register_begin(); 535 err = cpuhp_setup_state(CPUHP_PROFILE_PREPARE, "PROFILE_PREPARE",
596 536 profile_prepare_cpu, profile_dead_cpu);
597 if (create_hash_tables()) { 537 if (err)
598 err = -ENOMEM; 538 return err;
599 goto out; 539
600 } 540 err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "AP_PROFILE_ONLINE",
601 541 profile_online_cpu, NULL);
542 if (err < 0)
543 goto err_state_prep;
544 online_state = err;
545 err = 0;
546#endif
602 entry = proc_create("profile", S_IWUSR | S_IRUGO, 547 entry = proc_create("profile", S_IWUSR | S_IRUGO,
603 NULL, &proc_profile_operations); 548 NULL, &proc_profile_operations);
604 if (!entry) 549 if (!entry)
605 goto out; 550 goto err_state_onl;
606 proc_set_size(entry, (1 + prof_len) * sizeof(atomic_t)); 551 proc_set_size(entry, (1 + prof_len) * sizeof(atomic_t));
607 __hotcpu_notifier(profile_cpu_callback, 0);
608 552
609out: 553 return err;
610 cpu_notifier_register_done(); 554err_state_onl:
555#ifdef CONFIG_SMP
556 cpuhp_remove_state(online_state);
557err_state_prep:
558 cpuhp_remove_state(CPUHP_PROFILE_PREPARE);
559#endif
611 return err; 560 return err;
612} 561}
613subsys_initcall(create_proc_profile); 562subsys_initcall(create_proc_profile);