1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <linux/ceph/ceph_debug.h>
4 #include <linux/types.h>
5 #include <linux/percpu_counter.h>
6 #include <linux/math64.h>
9 #include "mds_client.h"
11 static bool ceph_mdsc_send_metrics(struct ceph_mds_client
*mdsc
,
12 struct ceph_mds_session
*s
)
14 struct ceph_metric_head
*head
;
15 struct ceph_metric_cap
*cap
;
16 struct ceph_metric_read_latency
*read
;
17 struct ceph_metric_write_latency
*write
;
18 struct ceph_metric_metadata_latency
*meta
;
19 struct ceph_metric_dlease
*dlease
;
20 struct ceph_client_metric
*m
= &mdsc
->metric
;
21 u64 nr_caps
= atomic64_read(&m
->total_caps
);
28 len
= sizeof(*head
) + sizeof(*cap
) + sizeof(*read
) + sizeof(*write
)
29 + sizeof(*meta
) + sizeof(*dlease
);
31 msg
= ceph_msg_new(CEPH_MSG_CLIENT_METRICS
, len
, GFP_NOFS
, true);
33 pr_err("send metrics to mds%d, failed to allocate message\n",
38 head
= msg
->front
.iov_base
;
40 /* encode the cap metric */
41 cap
= (struct ceph_metric_cap
*)(head
+ 1);
42 cap
->type
= cpu_to_le32(CLIENT_METRIC_TYPE_CAP_INFO
);
45 cap
->data_len
= cpu_to_le32(sizeof(*cap
) - 10);
46 cap
->hit
= cpu_to_le64(percpu_counter_sum(&m
->i_caps_hit
));
47 cap
->mis
= cpu_to_le64(percpu_counter_sum(&m
->i_caps_mis
));
48 cap
->total
= cpu_to_le64(nr_caps
);
51 /* encode the read latency metric */
52 read
= (struct ceph_metric_read_latency
*)(cap
+ 1);
53 read
->type
= cpu_to_le32(CLIENT_METRIC_TYPE_READ_LATENCY
);
56 read
->data_len
= cpu_to_le32(sizeof(*read
) - 10);
57 sum
= m
->read_latency_sum
;
58 jiffies_to_timespec64(sum
, &ts
);
59 read
->sec
= cpu_to_le32(ts
.tv_sec
);
60 read
->nsec
= cpu_to_le32(ts
.tv_nsec
);
63 /* encode the write latency metric */
64 write
= (struct ceph_metric_write_latency
*)(read
+ 1);
65 write
->type
= cpu_to_le32(CLIENT_METRIC_TYPE_WRITE_LATENCY
);
68 write
->data_len
= cpu_to_le32(sizeof(*write
) - 10);
69 sum
= m
->write_latency_sum
;
70 jiffies_to_timespec64(sum
, &ts
);
71 write
->sec
= cpu_to_le32(ts
.tv_sec
);
72 write
->nsec
= cpu_to_le32(ts
.tv_nsec
);
75 /* encode the metadata latency metric */
76 meta
= (struct ceph_metric_metadata_latency
*)(write
+ 1);
77 meta
->type
= cpu_to_le32(CLIENT_METRIC_TYPE_METADATA_LATENCY
);
80 meta
->data_len
= cpu_to_le32(sizeof(*meta
) - 10);
81 sum
= m
->metadata_latency_sum
;
82 jiffies_to_timespec64(sum
, &ts
);
83 meta
->sec
= cpu_to_le32(ts
.tv_sec
);
84 meta
->nsec
= cpu_to_le32(ts
.tv_nsec
);
87 /* encode the dentry lease metric */
88 dlease
= (struct ceph_metric_dlease
*)(meta
+ 1);
89 dlease
->type
= cpu_to_le32(CLIENT_METRIC_TYPE_DENTRY_LEASE
);
92 dlease
->data_len
= cpu_to_le32(sizeof(*dlease
) - 10);
93 dlease
->hit
= cpu_to_le64(percpu_counter_sum(&m
->d_lease_hit
));
94 dlease
->mis
= cpu_to_le64(percpu_counter_sum(&m
->d_lease_mis
));
95 dlease
->total
= cpu_to_le64(atomic64_read(&m
->total_dentries
));
98 put_unaligned_le32(items
, &head
->num
);
99 msg
->front
.iov_len
= len
;
100 msg
->hdr
.version
= cpu_to_le16(1);
101 msg
->hdr
.compat_version
= cpu_to_le16(1);
102 msg
->hdr
.front_len
= cpu_to_le32(msg
->front
.iov_len
);
103 dout("client%llu send metrics to mds%d\n",
104 ceph_client_gid(mdsc
->fsc
->client
), s
->s_mds
);
105 ceph_con_send(&s
->s_con
, msg
);
111 static void metric_get_session(struct ceph_mds_client
*mdsc
)
113 struct ceph_mds_session
*s
;
116 mutex_lock(&mdsc
->mutex
);
117 for (i
= 0; i
< mdsc
->max_sessions
; i
++) {
118 s
= __ceph_lookup_mds_session(mdsc
, i
);
123 * Skip it if MDS doesn't support the metric collection,
124 * or the MDS will close the session's socket connection
125 * directly when it get this message.
127 if (check_session_state(s
) &&
128 test_bit(CEPHFS_FEATURE_METRIC_COLLECT
, &s
->s_features
)) {
129 mdsc
->metric
.session
= s
;
133 ceph_put_mds_session(s
);
135 mutex_unlock(&mdsc
->mutex
);
138 static void metric_delayed_work(struct work_struct
*work
)
140 struct ceph_client_metric
*m
=
141 container_of(work
, struct ceph_client_metric
, delayed_work
.work
);
142 struct ceph_mds_client
*mdsc
=
143 container_of(m
, struct ceph_mds_client
, metric
);
148 if (!m
->session
|| !check_session_state(m
->session
)) {
150 ceph_put_mds_session(m
->session
);
153 metric_get_session(mdsc
);
156 ceph_mdsc_send_metrics(mdsc
, m
->session
);
157 metric_schedule_delayed(m
);
161 int ceph_metric_init(struct ceph_client_metric
*m
)
168 atomic64_set(&m
->total_dentries
, 0);
169 ret
= percpu_counter_init(&m
->d_lease_hit
, 0, GFP_KERNEL
);
173 ret
= percpu_counter_init(&m
->d_lease_mis
, 0, GFP_KERNEL
);
175 goto err_d_lease_mis
;
177 atomic64_set(&m
->total_caps
, 0);
178 ret
= percpu_counter_init(&m
->i_caps_hit
, 0, GFP_KERNEL
);
182 ret
= percpu_counter_init(&m
->i_caps_mis
, 0, GFP_KERNEL
);
186 spin_lock_init(&m
->read_latency_lock
);
187 m
->read_latency_sq_sum
= 0;
188 m
->read_latency_min
= KTIME_MAX
;
189 m
->read_latency_max
= 0;
191 m
->read_latency_sum
= 0;
193 spin_lock_init(&m
->write_latency_lock
);
194 m
->write_latency_sq_sum
= 0;
195 m
->write_latency_min
= KTIME_MAX
;
196 m
->write_latency_max
= 0;
198 m
->write_latency_sum
= 0;
200 spin_lock_init(&m
->metadata_latency_lock
);
201 m
->metadata_latency_sq_sum
= 0;
202 m
->metadata_latency_min
= KTIME_MAX
;
203 m
->metadata_latency_max
= 0;
204 m
->total_metadatas
= 0;
205 m
->metadata_latency_sum
= 0;
207 atomic64_set(&m
->opened_files
, 0);
208 ret
= percpu_counter_init(&m
->opened_inodes
, 0, GFP_KERNEL
);
210 goto err_opened_inodes
;
211 ret
= percpu_counter_init(&m
->total_inodes
, 0, GFP_KERNEL
);
213 goto err_total_inodes
;
216 INIT_DELAYED_WORK(&m
->delayed_work
, metric_delayed_work
);
221 percpu_counter_destroy(&m
->opened_inodes
);
223 percpu_counter_destroy(&m
->i_caps_mis
);
225 percpu_counter_destroy(&m
->i_caps_hit
);
227 percpu_counter_destroy(&m
->d_lease_mis
);
229 percpu_counter_destroy(&m
->d_lease_hit
);
234 void ceph_metric_destroy(struct ceph_client_metric
*m
)
239 percpu_counter_destroy(&m
->total_inodes
);
240 percpu_counter_destroy(&m
->opened_inodes
);
241 percpu_counter_destroy(&m
->i_caps_mis
);
242 percpu_counter_destroy(&m
->i_caps_hit
);
243 percpu_counter_destroy(&m
->d_lease_mis
);
244 percpu_counter_destroy(&m
->d_lease_hit
);
246 cancel_delayed_work_sync(&m
->delayed_work
);
249 ceph_put_mds_session(m
->session
);
252 static inline void __update_latency(ktime_t
*totalp
, ktime_t
*lsump
,
253 ktime_t
*min
, ktime_t
*max
,
254 ktime_t
*sq_sump
, ktime_t lat
)
256 ktime_t total
, avg
, sq
, lsum
;
259 lsum
= (*lsump
+= lat
);
261 if (unlikely(lat
< *min
))
263 if (unlikely(lat
> *max
))
266 if (unlikely(total
== 1))
269 /* the sq is (lat - old_avg) * (lat - new_avg) */
270 avg
= DIV64_U64_ROUND_CLOSEST((lsum
- lat
), (total
- 1));
272 avg
= DIV64_U64_ROUND_CLOSEST(lsum
, total
);
273 sq
= sq
* (lat
- avg
);
277 void ceph_update_read_latency(struct ceph_client_metric
*m
,
278 ktime_t r_start
, ktime_t r_end
,
281 ktime_t lat
= ktime_sub(r_end
, r_start
);
283 if (unlikely(rc
< 0 && rc
!= -ENOENT
&& rc
!= -ETIMEDOUT
))
286 spin_lock(&m
->read_latency_lock
);
287 __update_latency(&m
->total_reads
, &m
->read_latency_sum
,
288 &m
->read_latency_min
, &m
->read_latency_max
,
289 &m
->read_latency_sq_sum
, lat
);
290 spin_unlock(&m
->read_latency_lock
);
293 void ceph_update_write_latency(struct ceph_client_metric
*m
,
294 ktime_t r_start
, ktime_t r_end
,
297 ktime_t lat
= ktime_sub(r_end
, r_start
);
299 if (unlikely(rc
&& rc
!= -ETIMEDOUT
))
302 spin_lock(&m
->write_latency_lock
);
303 __update_latency(&m
->total_writes
, &m
->write_latency_sum
,
304 &m
->write_latency_min
, &m
->write_latency_max
,
305 &m
->write_latency_sq_sum
, lat
);
306 spin_unlock(&m
->write_latency_lock
);
309 void ceph_update_metadata_latency(struct ceph_client_metric
*m
,
310 ktime_t r_start
, ktime_t r_end
,
313 ktime_t lat
= ktime_sub(r_end
, r_start
);
315 if (unlikely(rc
&& rc
!= -ENOENT
))
318 spin_lock(&m
->metadata_latency_lock
);
319 __update_latency(&m
->total_metadatas
, &m
->metadata_latency_sum
,
320 &m
->metadata_latency_min
, &m
->metadata_latency_max
,
321 &m
->metadata_latency_sq_sum
, lat
);
322 spin_unlock(&m
->metadata_latency_lock
);