0001
0002
0003
0004
0005
0006
0007
0008 #include "bcache.h"
0009 #include "stats.h"
0010 #include "btree.h"
0011 #include "sysfs.h"
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 static const unsigned int DAY_RESCALE = 288;
0037 static const unsigned int HOUR_RESCALE = 12;
0038 static const unsigned int FIVE_MINUTE_RESCALE = 1;
0039 static const unsigned int accounting_delay = (HZ * 300) / 22;
0040 static const unsigned int accounting_weight = 32;
0041
0042
0043
0044 read_attribute(cache_hits);
0045 read_attribute(cache_misses);
0046 read_attribute(cache_bypass_hits);
0047 read_attribute(cache_bypass_misses);
0048 read_attribute(cache_hit_ratio);
0049 read_attribute(cache_miss_collisions);
0050 read_attribute(bypassed);
0051
0052 SHOW(bch_stats)
0053 {
0054 struct cache_stats *s =
0055 container_of(kobj, struct cache_stats, kobj);
0056 #define var(stat) (s->stat >> 16)
0057 var_print(cache_hits);
0058 var_print(cache_misses);
0059 var_print(cache_bypass_hits);
0060 var_print(cache_bypass_misses);
0061
0062 sysfs_print(cache_hit_ratio,
0063 DIV_SAFE(var(cache_hits) * 100,
0064 var(cache_hits) + var(cache_misses)));
0065
0066 var_print(cache_miss_collisions);
0067 sysfs_hprint(bypassed, var(sectors_bypassed) << 9);
0068 #undef var
0069 return 0;
0070 }
0071
0072 STORE(bch_stats)
0073 {
0074 return size;
0075 }
0076
0077 static void bch_stats_release(struct kobject *k)
0078 {
0079 }
0080
0081 static struct attribute *bch_stats_attrs[] = {
0082 &sysfs_cache_hits,
0083 &sysfs_cache_misses,
0084 &sysfs_cache_bypass_hits,
0085 &sysfs_cache_bypass_misses,
0086 &sysfs_cache_hit_ratio,
0087 &sysfs_cache_miss_collisions,
0088 &sysfs_bypassed,
0089 NULL
0090 };
0091 ATTRIBUTE_GROUPS(bch_stats);
0092 static KTYPE(bch_stats);
0093
0094 int bch_cache_accounting_add_kobjs(struct cache_accounting *acc,
0095 struct kobject *parent)
0096 {
0097 int ret = kobject_add(&acc->total.kobj, parent,
0098 "stats_total");
0099 ret = ret ?: kobject_add(&acc->five_minute.kobj, parent,
0100 "stats_five_minute");
0101 ret = ret ?: kobject_add(&acc->hour.kobj, parent,
0102 "stats_hour");
0103 ret = ret ?: kobject_add(&acc->day.kobj, parent,
0104 "stats_day");
0105 return ret;
0106 }
0107
0108 void bch_cache_accounting_clear(struct cache_accounting *acc)
0109 {
0110 acc->total.cache_hits = 0;
0111 acc->total.cache_misses = 0;
0112 acc->total.cache_bypass_hits = 0;
0113 acc->total.cache_bypass_misses = 0;
0114 acc->total.cache_miss_collisions = 0;
0115 acc->total.sectors_bypassed = 0;
0116 }
0117
0118 void bch_cache_accounting_destroy(struct cache_accounting *acc)
0119 {
0120 kobject_put(&acc->total.kobj);
0121 kobject_put(&acc->five_minute.kobj);
0122 kobject_put(&acc->hour.kobj);
0123 kobject_put(&acc->day.kobj);
0124
0125 atomic_set(&acc->closing, 1);
0126 if (del_timer_sync(&acc->timer))
0127 closure_return(&acc->cl);
0128 }
0129
0130
0131
0132 static void scale_stat(unsigned long *stat)
0133 {
0134 *stat = ewma_add(*stat, 0, accounting_weight, 0);
0135 }
0136
0137 static void scale_stats(struct cache_stats *stats, unsigned long rescale_at)
0138 {
0139 if (++stats->rescale == rescale_at) {
0140 stats->rescale = 0;
0141 scale_stat(&stats->cache_hits);
0142 scale_stat(&stats->cache_misses);
0143 scale_stat(&stats->cache_bypass_hits);
0144 scale_stat(&stats->cache_bypass_misses);
0145 scale_stat(&stats->cache_miss_collisions);
0146 scale_stat(&stats->sectors_bypassed);
0147 }
0148 }
0149
0150 static void scale_accounting(struct timer_list *t)
0151 {
0152 struct cache_accounting *acc = from_timer(acc, t, timer);
0153
0154 #define move_stat(name) do { \
0155 unsigned int t = atomic_xchg(&acc->collector.name, 0); \
0156 t <<= 16; \
0157 acc->five_minute.name += t; \
0158 acc->hour.name += t; \
0159 acc->day.name += t; \
0160 acc->total.name += t; \
0161 } while (0)
0162
0163 move_stat(cache_hits);
0164 move_stat(cache_misses);
0165 move_stat(cache_bypass_hits);
0166 move_stat(cache_bypass_misses);
0167 move_stat(cache_miss_collisions);
0168 move_stat(sectors_bypassed);
0169
0170 scale_stats(&acc->total, 0);
0171 scale_stats(&acc->day, DAY_RESCALE);
0172 scale_stats(&acc->hour, HOUR_RESCALE);
0173 scale_stats(&acc->five_minute, FIVE_MINUTE_RESCALE);
0174
0175 acc->timer.expires += accounting_delay;
0176
0177 if (!atomic_read(&acc->closing))
0178 add_timer(&acc->timer);
0179 else
0180 closure_return(&acc->cl);
0181 }
0182
0183 static void mark_cache_stats(struct cache_stat_collector *stats,
0184 bool hit, bool bypass)
0185 {
0186 if (!bypass)
0187 if (hit)
0188 atomic_inc(&stats->cache_hits);
0189 else
0190 atomic_inc(&stats->cache_misses);
0191 else
0192 if (hit)
0193 atomic_inc(&stats->cache_bypass_hits);
0194 else
0195 atomic_inc(&stats->cache_bypass_misses);
0196 }
0197
0198 void bch_mark_cache_accounting(struct cache_set *c, struct bcache_device *d,
0199 bool hit, bool bypass)
0200 {
0201 struct cached_dev *dc = container_of(d, struct cached_dev, disk);
0202
0203 mark_cache_stats(&dc->accounting.collector, hit, bypass);
0204 mark_cache_stats(&c->accounting.collector, hit, bypass);
0205 }
0206
0207 void bch_mark_cache_miss_collision(struct cache_set *c, struct bcache_device *d)
0208 {
0209 struct cached_dev *dc = container_of(d, struct cached_dev, disk);
0210
0211 atomic_inc(&dc->accounting.collector.cache_miss_collisions);
0212 atomic_inc(&c->accounting.collector.cache_miss_collisions);
0213 }
0214
0215 void bch_mark_sectors_bypassed(struct cache_set *c, struct cached_dev *dc,
0216 int sectors)
0217 {
0218 atomic_add(sectors, &dc->accounting.collector.sectors_bypassed);
0219 atomic_add(sectors, &c->accounting.collector.sectors_bypassed);
0220 }
0221
0222 void bch_cache_accounting_init(struct cache_accounting *acc,
0223 struct closure *parent)
0224 {
0225 kobject_init(&acc->total.kobj, &bch_stats_ktype);
0226 kobject_init(&acc->five_minute.kobj, &bch_stats_ktype);
0227 kobject_init(&acc->hour.kobj, &bch_stats_ktype);
0228 kobject_init(&acc->day.kobj, &bch_stats_ktype);
0229
0230 closure_init(&acc->cl, parent);
0231 timer_setup(&acc->timer, scale_accounting, 0);
0232 acc->timer.expires = jiffies + accounting_delay;
0233 add_timer(&acc->timer);
0234 }