aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2015-08-18 17:55:21 -0400
committerJens Axboe <axboe@fb.com>2015-08-18 18:49:17 -0400
commite6269c44546755094979ab53609e6e203a68c8ff (patch)
treefc083e47b6ea842e5d260084542a2ed5f76a86ea
parentae11889636111199dbcf47283b4167f578b69472 (diff)
blkcg: add blkg_[rw]stat->aux_cnt and replace cfq_group->dead_stats with it
cgroup stats are local to each cgroup and doesn't propagate to ancestors by default. When recursive stats are necessary, the sum is calculated over all the descendants. This initially was for backward compatibility to support both group-local and recursive stats but this mode of operation makes general sense as stat update is much hotter thafn reporting those stats. This however ends up losing recursive stats when a child is removed. To work around this, cfq-iosched adds its stats to its parent cfq_group->dead_stats which is summed up together when calculating recursive stats. It's planned that the core stats will be moved to blkcg_gq, so we want to move the mechanism for keeping track of the stats of dead children from cfq to blkcg core. This patch adds blkg_[rw]stat->aux_cnt which are atomic64_t's keeping track of auxiliary counts which are excluded when reading local counts but included for recursive. blkg_[rw]stat_merge() which were used by cfq to implement dead_stats are replaced by blkg_[rw]stat_add_aux(), and cfq now forwards stats of a dead cgroup to the aux counts of parent->stats instead of separate ->dead_stats. This will also help making blkg_[rw]stats per-cpu. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--block/blk-cgroup.c10
-rw-r--r--block/cfq-iosched.c67
-rw-r--r--include/linux/blk-cgroup.h46
3 files changed, 57 insertions, 66 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 097c4a670fa4..ff79b52d1a0e 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -584,7 +584,7 @@ EXPORT_SYMBOL_GPL(blkg_prfill_rwstat);
584 * @off: offset to the blkg_stat in @pd 584 * @off: offset to the blkg_stat in @pd
585 * 585 *
586 * Collect the blkg_stat specified by @off from @pd and all its online 586 * Collect the blkg_stat specified by @off from @pd and all its online
587 * descendants and return the sum. The caller must be holding the queue 587 * descendants and their aux counts. The caller must be holding the queue
588 * lock for online tests. 588 * lock for online tests.
589 */ 589 */
590u64 blkg_stat_recursive_sum(struct blkg_policy_data *pd, int off) 590u64 blkg_stat_recursive_sum(struct blkg_policy_data *pd, int off)
@@ -602,7 +602,8 @@ u64 blkg_stat_recursive_sum(struct blkg_policy_data *pd, int off)
602 struct blkg_stat *stat = (void *)pos_pd + off; 602 struct blkg_stat *stat = (void *)pos_pd + off;
603 603
604 if (pos_blkg->online) 604 if (pos_blkg->online)
605 sum += blkg_stat_read(stat); 605 sum += blkg_stat_read(stat) +
606 atomic64_read(&stat->aux_cnt);
606 } 607 }
607 rcu_read_unlock(); 608 rcu_read_unlock();
608 609
@@ -616,7 +617,7 @@ EXPORT_SYMBOL_GPL(blkg_stat_recursive_sum);
616 * @off: offset to the blkg_stat in @pd 617 * @off: offset to the blkg_stat in @pd
617 * 618 *
618 * Collect the blkg_rwstat specified by @off from @pd and all its online 619 * Collect the blkg_rwstat specified by @off from @pd and all its online
619 * descendants and return the sum. The caller must be holding the queue 620 * descendants and their aux counts. The caller must be holding the queue
620 * lock for online tests. 621 * lock for online tests.
621 */ 622 */
622struct blkg_rwstat blkg_rwstat_recursive_sum(struct blkg_policy_data *pd, 623struct blkg_rwstat blkg_rwstat_recursive_sum(struct blkg_policy_data *pd,
@@ -642,7 +643,8 @@ struct blkg_rwstat blkg_rwstat_recursive_sum(struct blkg_policy_data *pd,
642 tmp = blkg_rwstat_read(rwstat); 643 tmp = blkg_rwstat_read(rwstat);
643 644
644 for (i = 0; i < BLKG_RWSTAT_NR; i++) 645 for (i = 0; i < BLKG_RWSTAT_NR; i++)
645 sum.cnt[i] += tmp.cnt[i]; 646 sum.cnt[i] += tmp.cnt[i] +
647 atomic64_read(&rwstat->aux_cnt[i]);
646 } 648 }
647 rcu_read_unlock(); 649 rcu_read_unlock();
648 650
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 0994f3b523a8..b272cfff7364 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -304,7 +304,6 @@ struct cfq_group {
304 int dispatched; 304 int dispatched;
305 struct cfq_ttime ttime; 305 struct cfq_ttime ttime;
306 struct cfqg_stats stats; /* stats for this cfqg */ 306 struct cfqg_stats stats; /* stats for this cfqg */
307 struct cfqg_stats dead_stats; /* stats pushed from dead children */
308 307
309 /* async queue for each priority case */ 308 /* async queue for each priority case */
310 struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR]; 309 struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR];
@@ -736,28 +735,28 @@ static void cfqg_stats_reset(struct cfqg_stats *stats)
736} 735}
737 736
738/* @to += @from */ 737/* @to += @from */
739static void cfqg_stats_merge(struct cfqg_stats *to, struct cfqg_stats *from) 738static void cfqg_stats_add_aux(struct cfqg_stats *to, struct cfqg_stats *from)
740{ 739{
741 /* queued stats shouldn't be cleared */ 740 /* queued stats shouldn't be cleared */
742 blkg_rwstat_merge(&to->service_bytes, &from->service_bytes); 741 blkg_rwstat_add_aux(&to->service_bytes, &from->service_bytes);
743 blkg_rwstat_merge(&to->serviced, &from->serviced); 742 blkg_rwstat_add_aux(&to->serviced, &from->serviced);
744 blkg_rwstat_merge(&to->merged, &from->merged); 743 blkg_rwstat_add_aux(&to->merged, &from->merged);
745 blkg_rwstat_merge(&to->service_time, &from->service_time); 744 blkg_rwstat_add_aux(&to->service_time, &from->service_time);
746 blkg_rwstat_merge(&to->wait_time, &from->wait_time); 745 blkg_rwstat_add_aux(&to->wait_time, &from->wait_time);
747 blkg_stat_merge(&from->time, &from->time); 746 blkg_stat_add_aux(&from->time, &from->time);
748#ifdef CONFIG_DEBUG_BLK_CGROUP 747#ifdef CONFIG_DEBUG_BLK_CGROUP
749 blkg_stat_merge(&to->unaccounted_time, &from->unaccounted_time); 748 blkg_stat_add_aux(&to->unaccounted_time, &from->unaccounted_time);
750 blkg_stat_merge(&to->avg_queue_size_sum, &from->avg_queue_size_sum); 749 blkg_stat_add_aux(&to->avg_queue_size_sum, &from->avg_queue_size_sum);
751 blkg_stat_merge(&to->avg_queue_size_samples, &from->avg_queue_size_samples); 750 blkg_stat_add_aux(&to->avg_queue_size_samples, &from->avg_queue_size_samples);
752 blkg_stat_merge(&to->dequeue, &from->dequeue); 751 blkg_stat_add_aux(&to->dequeue, &from->dequeue);
753 blkg_stat_merge(&to->group_wait_time, &from->group_wait_time); 752 blkg_stat_add_aux(&to->group_wait_time, &from->group_wait_time);
754 blkg_stat_merge(&to->idle_time, &from->idle_time); 753 blkg_stat_add_aux(&to->idle_time, &from->idle_time);
755 blkg_stat_merge(&to->empty_time, &from->empty_time); 754 blkg_stat_add_aux(&to->empty_time, &from->empty_time);
756#endif 755#endif
757} 756}
758 757
759/* 758/*
760 * Transfer @cfqg's stats to its parent's dead_stats so that the ancestors' 759 * Transfer @cfqg's stats to its parent's aux counts so that the ancestors'
761 * recursive stats can still account for the amount used by this cfqg after 760 * recursive stats can still account for the amount used by this cfqg after
762 * it's gone. 761 * it's gone.
763 */ 762 */
@@ -770,10 +769,8 @@ static void cfqg_stats_xfer_dead(struct cfq_group *cfqg)
770 if (unlikely(!parent)) 769 if (unlikely(!parent))
771 return; 770 return;
772 771
773 cfqg_stats_merge(&parent->dead_stats, &cfqg->stats); 772 cfqg_stats_add_aux(&parent->stats, &cfqg->stats);
774 cfqg_stats_merge(&parent->dead_stats, &cfqg->dead_stats);
775 cfqg_stats_reset(&cfqg->stats); 773 cfqg_stats_reset(&cfqg->stats);
776 cfqg_stats_reset(&cfqg->dead_stats);
777} 774}
778 775
779#else /* CONFIG_CFQ_GROUP_IOSCHED */ 776#else /* CONFIG_CFQ_GROUP_IOSCHED */
@@ -1606,7 +1603,6 @@ static struct blkg_policy_data *cfq_pd_alloc(gfp_t gfp, int node)
1606 1603
1607 cfq_init_cfqg_base(cfqg); 1604 cfq_init_cfqg_base(cfqg);
1608 cfqg_stats_init(&cfqg->stats); 1605 cfqg_stats_init(&cfqg->stats);
1609 cfqg_stats_init(&cfqg->dead_stats);
1610 1606
1611 return &cfqg->pd; 1607 return &cfqg->pd;
1612} 1608}
@@ -1649,38 +1645,11 @@ static void cfq_pd_free(struct blkg_policy_data *pd)
1649 return kfree(pd); 1645 return kfree(pd);
1650} 1646}
1651 1647
1652/* offset delta from cfqg->stats to cfqg->dead_stats */
1653static const int dead_stats_off_delta = offsetof(struct cfq_group, dead_stats) -
1654 offsetof(struct cfq_group, stats);
1655
1656/* to be used by recursive prfill, sums live and dead stats recursively */
1657static u64 cfqg_stat_pd_recursive_sum(struct blkg_policy_data *pd, int off)
1658{
1659 u64 sum = 0;
1660
1661 sum += blkg_stat_recursive_sum(pd, off);
1662 sum += blkg_stat_recursive_sum(pd, off + dead_stats_off_delta);
1663 return sum;
1664}
1665
1666/* to be used by recursive prfill, sums live and dead rwstats recursively */
1667static struct blkg_rwstat cfqg_rwstat_pd_recursive_sum(struct blkg_policy_data *pd,
1668 int off)
1669{
1670 struct blkg_rwstat a, b;
1671
1672 a = blkg_rwstat_recursive_sum(pd, off);
1673 b = blkg_rwstat_recursive_sum(pd, off + dead_stats_off_delta);
1674 blkg_rwstat_merge(&a, &b);
1675 return a;
1676}
1677
1678static void cfq_pd_reset_stats(struct blkg_policy_data *pd) 1648static void cfq_pd_reset_stats(struct blkg_policy_data *pd)
1679{ 1649{
1680 struct cfq_group *cfqg = pd_to_cfqg(pd); 1650 struct cfq_group *cfqg = pd_to_cfqg(pd);
1681 1651
1682 cfqg_stats_reset(&cfqg->stats); 1652 cfqg_stats_reset(&cfqg->stats);
1683 cfqg_stats_reset(&cfqg->dead_stats);
1684} 1653}
1685 1654
1686static struct cfq_group *cfq_lookup_cfqg(struct cfq_data *cfqd, 1655static struct cfq_group *cfq_lookup_cfqg(struct cfq_data *cfqd,
@@ -1883,7 +1852,7 @@ static int cfqg_print_rwstat(struct seq_file *sf, void *v)
1883static u64 cfqg_prfill_stat_recursive(struct seq_file *sf, 1852static u64 cfqg_prfill_stat_recursive(struct seq_file *sf,
1884 struct blkg_policy_data *pd, int off) 1853 struct blkg_policy_data *pd, int off)
1885{ 1854{
1886 u64 sum = cfqg_stat_pd_recursive_sum(pd, off); 1855 u64 sum = blkg_stat_recursive_sum(pd, off);
1887 1856
1888 return __blkg_prfill_u64(sf, pd, sum); 1857 return __blkg_prfill_u64(sf, pd, sum);
1889} 1858}
@@ -1891,7 +1860,7 @@ static u64 cfqg_prfill_stat_recursive(struct seq_file *sf,
1891static u64 cfqg_prfill_rwstat_recursive(struct seq_file *sf, 1860static u64 cfqg_prfill_rwstat_recursive(struct seq_file *sf,
1892 struct blkg_policy_data *pd, int off) 1861 struct blkg_policy_data *pd, int off)
1893{ 1862{
1894 struct blkg_rwstat sum = cfqg_rwstat_pd_recursive_sum(pd, off); 1863 struct blkg_rwstat sum = blkg_rwstat_recursive_sum(pd, off);
1895 1864
1896 return __blkg_prfill_rwstat(sf, pd, &sum); 1865 return __blkg_prfill_rwstat(sf, pd, &sum);
1897} 1866}
diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h
index 4d1659c7f84b..e8092276af58 100644
--- a/include/linux/blk-cgroup.h
+++ b/include/linux/blk-cgroup.h
@@ -53,14 +53,20 @@ struct blkcg {
53#endif 53#endif
54}; 54};
55 55
56/*
57 * blkg_[rw]stat->aux_cnt is excluded for local stats but included for
58 * recursive. Used to carry stats of dead children.
59 */
56struct blkg_stat { 60struct blkg_stat {
57 struct u64_stats_sync syncp; 61 struct u64_stats_sync syncp;
58 uint64_t cnt; 62 uint64_t cnt;
63 atomic64_t aux_cnt;
59}; 64};
60 65
61struct blkg_rwstat { 66struct blkg_rwstat {
62 struct u64_stats_sync syncp; 67 struct u64_stats_sync syncp;
63 uint64_t cnt[BLKG_RWSTAT_NR]; 68 uint64_t cnt[BLKG_RWSTAT_NR];
69 atomic64_t aux_cnt[BLKG_RWSTAT_NR];
64}; 70};
65 71
66/* 72/*
@@ -483,6 +489,7 @@ struct request_list *__blk_queue_next_rl(struct request_list *rl,
483static inline void blkg_stat_init(struct blkg_stat *stat) 489static inline void blkg_stat_init(struct blkg_stat *stat)
484{ 490{
485 u64_stats_init(&stat->syncp); 491 u64_stats_init(&stat->syncp);
492 atomic64_set(&stat->aux_cnt, 0);
486} 493}
487 494
488/** 495/**
@@ -504,8 +511,9 @@ static inline void blkg_stat_add(struct blkg_stat *stat, uint64_t val)
504 * blkg_stat_read - read the current value of a blkg_stat 511 * blkg_stat_read - read the current value of a blkg_stat
505 * @stat: blkg_stat to read 512 * @stat: blkg_stat to read
506 * 513 *
507 * Read the current value of @stat. This function can be called without 514 * Read the current value of @stat. The returned value doesn't include the
508 * synchroniztion and takes care of u64 atomicity. 515 * aux count. This function can be called without synchroniztion and takes
516 * care of u64 atomicity.
509 */ 517 */
510static inline uint64_t blkg_stat_read(struct blkg_stat *stat) 518static inline uint64_t blkg_stat_read(struct blkg_stat *stat)
511{ 519{
@@ -527,23 +535,31 @@ static inline uint64_t blkg_stat_read(struct blkg_stat *stat)
527static inline void blkg_stat_reset(struct blkg_stat *stat) 535static inline void blkg_stat_reset(struct blkg_stat *stat)
528{ 536{
529 stat->cnt = 0; 537 stat->cnt = 0;
538 atomic64_set(&stat->aux_cnt, 0);
530} 539}
531 540
532/** 541/**
533 * blkg_stat_merge - merge a blkg_stat into another 542 * blkg_stat_add_aux - add a blkg_stat into another's aux count
534 * @to: the destination blkg_stat 543 * @to: the destination blkg_stat
535 * @from: the source 544 * @from: the source
536 * 545 *
537 * Add @from's count to @to. 546 * Add @from's count including the aux one to @to's aux count.
538 */ 547 */
539static inline void blkg_stat_merge(struct blkg_stat *to, struct blkg_stat *from) 548static inline void blkg_stat_add_aux(struct blkg_stat *to,
549 struct blkg_stat *from)
540{ 550{
541 blkg_stat_add(to, blkg_stat_read(from)); 551 atomic64_add(blkg_stat_read(from) + atomic64_read(&from->aux_cnt),
552 &to->aux_cnt);
542} 553}
543 554
544static inline void blkg_rwstat_init(struct blkg_rwstat *rwstat) 555static inline void blkg_rwstat_init(struct blkg_rwstat *rwstat)
545{ 556{
557 int i;
558
546 u64_stats_init(&rwstat->syncp); 559 u64_stats_init(&rwstat->syncp);
560
561 for (i = 0; i < BLKG_RWSTAT_NR; i++)
562 atomic64_set(&rwstat->aux_cnt[i], 0);
547} 563}
548 564
549/** 565/**
@@ -614,26 +630,30 @@ static inline uint64_t blkg_rwstat_total(struct blkg_rwstat *rwstat)
614 */ 630 */
615static inline void blkg_rwstat_reset(struct blkg_rwstat *rwstat) 631static inline void blkg_rwstat_reset(struct blkg_rwstat *rwstat)
616{ 632{
633 int i;
634
617 memset(rwstat->cnt, 0, sizeof(rwstat->cnt)); 635 memset(rwstat->cnt, 0, sizeof(rwstat->cnt));
636
637 for (i = 0; i < BLKG_RWSTAT_NR; i++)
638 atomic64_set(&rwstat->aux_cnt[i], 0);
618} 639}
619 640
620/** 641/**
621 * blkg_rwstat_merge - merge a blkg_rwstat into another 642 * blkg_rwstat_add_aux - add a blkg_rwstat into another's aux count
622 * @to: the destination blkg_rwstat 643 * @to: the destination blkg_rwstat
623 * @from: the source 644 * @from: the source
624 * 645 *
625 * Add @from's counts to @to. 646 * Add @from's count including the aux one to @to's aux count.
626 */ 647 */
627static inline void blkg_rwstat_merge(struct blkg_rwstat *to, 648static inline void blkg_rwstat_add_aux(struct blkg_rwstat *to,
628 struct blkg_rwstat *from) 649 struct blkg_rwstat *from)
629{ 650{
630 struct blkg_rwstat v = blkg_rwstat_read(from); 651 struct blkg_rwstat v = blkg_rwstat_read(from);
631 int i; 652 int i;
632 653
633 u64_stats_update_begin(&to->syncp);
634 for (i = 0; i < BLKG_RWSTAT_NR; i++) 654 for (i = 0; i < BLKG_RWSTAT_NR; i++)
635 to->cnt[i] += v.cnt[i]; 655 atomic64_add(v.cnt[i] + atomic64_read(&from->aux_cnt[i]),
636 u64_stats_update_end(&to->syncp); 656 &to->aux_cnt[i]);
637} 657}
638 658
639#ifdef CONFIG_BLK_DEV_THROTTLING 659#ifdef CONFIG_BLK_DEV_THROTTLING