xfs_rtgroup_rele(rtg);
}
+/* XXX Should probably go in as a helper somewhere else */
+static const char xfs_write_hint_shorthand[6][16] = {
+ "NOT_SET", "NONE", "SHORT", "MEDIUM", "LONG", "EXTREME"};
+
+static inline const char *
+xfs_write_hint_to_str(
+ uint8_t write_hint)
+{
+ if (write_hint > WRITE_LIFE_EXTREME)
+ return "UNKNOWN";
+
+ return xfs_write_hint_shorthand[write_hint];
+}
+
+/*
+ * Calculate a simple data placement score based on utilization
+ */
+static unsigned long long
+xfs_zone_data_separation_score(
+ struct xfs_rtgroup *rtg)
+{
+ unsigned long long d;
+
+ /*
+ * The data separation score does not really
+ * make much sense until we've filled the zone
+ * so return 50 (~ neither here nor there)
+ */
+
+ if (rtg->rtg_write_pointer != rtg->rtg_extents)
+ return 50;
+
+ /*
+ * Data placement was good if the zone is nearly full (high utilization)
+ * nearly empty (cheap to reclaim), so calculate a composite score based on
+ * distance to utilization "mid point"
+ */
+ d = abs((signed long long)(*xfs_zone_used_counter(rtg)) -
+ (signed long long)(rtg->rtg_extents >> 1));
+
+ /* (100 * d) / (rtg->rtg_extents / 2) */
+ return div64_ul(2 * 100 * d, rtg->rtg_extents);
+}
+
+static unsigned long long
+xfs_average_zone_data_separation_score(
+ struct xfs_mount *mp)
+{
+ struct xfs_rtgroup *rtg;
+ unsigned long index;
+ unsigned long long sum = 0;
+ unsigned long long count = 0;
+
+ xa_for_each_marked(&mp->m_groups[XG_TYPE_RTG].xa, index, rtg,
+ XFS_RTG_RECLAIMABLE) {
+ sum += xfs_zone_data_separation_score(rtg);
+ count++;
+ }
+
+ /*
+ * If we have no reclaimable zones, we probably did a good data
+ * placement job, so return the optimal number (100%)
+ */
+ if (count == 0)
+ return 100;
+
+ return div64_long(sum, count);
+}
+
static void
xfs_show_zone(
struct seq_file *m,
struct xfs_rtgroup *rtg)
{
- seq_printf(m, "\t zone %d, wp %u, written %u, used %llu\n",
+ seq_printf(m, "\t zone %d, wp %u, written %u, used %llu, hint %s, active %u dss %llu\n",
rtg_rgno(rtg),
rtg->rtg_write_pointer, rtg->rtg_written,
- *xfs_zone_used_counter(rtg));
+ *xfs_zone_used_counter(rtg),
+ xfs_write_hint_to_str(rtg->rtg_write_hint),
+ atomic_read(&rtg->rtg_group.xg_active_ref),
+ xfs_zone_data_separation_score(rtg));
}
void
!list_empty_careful(&mp->m_reclaim_reservations));
seq_printf(m, "\tGC required: %d\n",
xfs_zoned_need_gc(mp));
+ seq_printf(m, "\tavg data separation score: %llu\n",
+ xfs_average_zone_data_separation_score(mp));
spin_lock(&mp->m_zone_list_lock);
seq_printf(m, "\tfree zones: %d\n", atomic_read(&mp->m_nr_free_zones));