1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2023 Red Hat
9 #include "memory-alloc.h"
10 #include "message-stats.h"
11 #include "statistics.h"
12 #include "thread-device.h"
15 static void write_u64(char *prefix
, u64 value
, char *suffix
, char **buf
,
20 count
= scnprintf(*buf
, *maxlen
, "%s%llu%s", prefix
== NULL
? "" : prefix
,
21 value
, suffix
== NULL
? "" : suffix
);
26 static void write_u32(char *prefix
, u32 value
, char *suffix
, char **buf
,
31 count
= scnprintf(*buf
, *maxlen
, "%s%u%s", prefix
== NULL
? "" : prefix
,
32 value
, suffix
== NULL
? "" : suffix
);
37 static void write_block_count_t(char *prefix
, block_count_t value
, char *suffix
,
38 char **buf
, unsigned int *maxlen
)
42 count
= scnprintf(*buf
, *maxlen
, "%s%llu%s", prefix
== NULL
? "" : prefix
,
43 value
, suffix
== NULL
? "" : suffix
);
48 static void write_string(char *prefix
, char *value
, char *suffix
, char **buf
,
53 count
= scnprintf(*buf
, *maxlen
, "%s%s%s", prefix
== NULL
? "" : prefix
,
54 value
, suffix
== NULL
? "" : suffix
);
59 static void write_bool(char *prefix
, bool value
, char *suffix
, char **buf
,
64 count
= scnprintf(*buf
, *maxlen
, "%s%d%s", prefix
== NULL
? "" : prefix
,
65 value
, suffix
== NULL
? "" : suffix
);
70 static void write_u8(char *prefix
, u8 value
, char *suffix
, char **buf
,
75 count
= scnprintf(*buf
, *maxlen
, "%s%u%s", prefix
== NULL
? "" : prefix
,
76 value
, suffix
== NULL
? "" : suffix
);
81 static void write_block_allocator_statistics(char *prefix
,
82 struct block_allocator_statistics
*stats
,
83 char *suffix
, char **buf
,
86 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
87 /* The total number of slabs from which blocks may be allocated */
88 write_u64("slabCount : ", stats
->slab_count
, ", ", buf
, maxlen
);
89 /* The total number of slabs from which blocks have ever been allocated */
90 write_u64("slabsOpened : ", stats
->slabs_opened
, ", ", buf
, maxlen
);
91 /* The number of times since loading that a slab has been re-opened */
92 write_u64("slabsReopened : ", stats
->slabs_reopened
, ", ", buf
, maxlen
);
93 write_string(NULL
, "}", suffix
, buf
, maxlen
);
96 static void write_commit_statistics(char *prefix
, struct commit_statistics
*stats
,
97 char *suffix
, char **buf
, unsigned int *maxlen
)
99 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
100 /* The total number of items on which processing has started */
101 write_u64("started : ", stats
->started
, ", ", buf
, maxlen
);
102 /* The total number of items for which a write operation has been issued */
103 write_u64("written : ", stats
->written
, ", ", buf
, maxlen
);
104 /* The total number of items for which a write operation has completed */
105 write_u64("committed : ", stats
->committed
, ", ", buf
, maxlen
);
106 write_string(NULL
, "}", suffix
, buf
, maxlen
);
109 static void write_recovery_journal_statistics(char *prefix
,
110 struct recovery_journal_statistics
*stats
,
111 char *suffix
, char **buf
,
112 unsigned int *maxlen
)
114 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
115 /* Number of times the on-disk journal was full */
116 write_u64("diskFull : ", stats
->disk_full
, ", ", buf
, maxlen
);
117 /* Number of times the recovery journal requested slab journal commits. */
118 write_u64("slabJournalCommitsRequested : ",
119 stats
->slab_journal_commits_requested
, ", ", buf
, maxlen
);
120 /* Write/Commit totals for individual journal entries */
121 write_commit_statistics("entries : ", &stats
->entries
, ", ", buf
, maxlen
);
122 /* Write/Commit totals for journal blocks */
123 write_commit_statistics("blocks : ", &stats
->blocks
, ", ", buf
, maxlen
);
124 write_string(NULL
, "}", suffix
, buf
, maxlen
);
127 static void write_packer_statistics(char *prefix
, struct packer_statistics
*stats
,
128 char *suffix
, char **buf
, unsigned int *maxlen
)
130 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
131 /* Number of compressed data items written since startup */
132 write_u64("compressedFragmentsWritten : ",
133 stats
->compressed_fragments_written
, ", ", buf
, maxlen
);
134 /* Number of blocks containing compressed items written since startup */
135 write_u64("compressedBlocksWritten : ",
136 stats
->compressed_blocks_written
, ", ", buf
, maxlen
);
137 /* Number of VIOs that are pending in the packer */
138 write_u64("compressedFragmentsInPacker : ",
139 stats
->compressed_fragments_in_packer
, ", ", buf
, maxlen
);
140 write_string(NULL
, "}", suffix
, buf
, maxlen
);
143 static void write_slab_journal_statistics(char *prefix
,
144 struct slab_journal_statistics
*stats
,
145 char *suffix
, char **buf
, unsigned int *maxlen
)
147 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
148 /* Number of times the on-disk journal was full */
149 write_u64("diskFullCount : ", stats
->disk_full_count
, ", ", buf
, maxlen
);
150 /* Number of times an entry was added over the flush threshold */
151 write_u64("flushCount : ", stats
->flush_count
, ", ", buf
, maxlen
);
152 /* Number of times an entry was added over the block threshold */
153 write_u64("blockedCount : ", stats
->blocked_count
, ", ", buf
, maxlen
);
154 /* Number of times a tail block was written */
155 write_u64("blocksWritten : ", stats
->blocks_written
, ", ", buf
, maxlen
);
156 /* Number of times we had to wait for the tail to write */
157 write_u64("tailBusyCount : ", stats
->tail_busy_count
, ", ", buf
, maxlen
);
158 write_string(NULL
, "}", suffix
, buf
, maxlen
);
161 static void write_slab_summary_statistics(char *prefix
,
162 struct slab_summary_statistics
*stats
,
163 char *suffix
, char **buf
, unsigned int *maxlen
)
165 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
166 /* Number of blocks written */
167 write_u64("blocksWritten : ", stats
->blocks_written
, ", ", buf
, maxlen
);
168 write_string(NULL
, "}", suffix
, buf
, maxlen
);
171 static void write_ref_counts_statistics(char *prefix
, struct ref_counts_statistics
*stats
,
172 char *suffix
, char **buf
, unsigned int *maxlen
)
174 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
175 /* Number of reference blocks written */
176 write_u64("blocksWritten : ", stats
->blocks_written
, ", ", buf
, maxlen
);
177 write_string(NULL
, "}", suffix
, buf
, maxlen
);
180 static void write_block_map_statistics(char *prefix
, struct block_map_statistics
*stats
,
181 char *suffix
, char **buf
, unsigned int *maxlen
)
183 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
184 /* number of dirty (resident) pages */
185 write_u32("dirtyPages : ", stats
->dirty_pages
, ", ", buf
, maxlen
);
186 /* number of clean (resident) pages */
187 write_u32("cleanPages : ", stats
->clean_pages
, ", ", buf
, maxlen
);
188 /* number of free pages */
189 write_u32("freePages : ", stats
->free_pages
, ", ", buf
, maxlen
);
190 /* number of pages in failed state */
191 write_u32("failedPages : ", stats
->failed_pages
, ", ", buf
, maxlen
);
192 /* number of pages incoming */
193 write_u32("incomingPages : ", stats
->incoming_pages
, ", ", buf
, maxlen
);
194 /* number of pages outgoing */
195 write_u32("outgoingPages : ", stats
->outgoing_pages
, ", ", buf
, maxlen
);
196 /* how many times free page not avail */
197 write_u32("cachePressure : ", stats
->cache_pressure
, ", ", buf
, maxlen
);
198 /* number of get_vdo_page() calls for read */
199 write_u64("readCount : ", stats
->read_count
, ", ", buf
, maxlen
);
200 /* number of get_vdo_page() calls for write */
201 write_u64("writeCount : ", stats
->write_count
, ", ", buf
, maxlen
);
202 /* number of times pages failed to read */
203 write_u64("failedReads : ", stats
->failed_reads
, ", ", buf
, maxlen
);
204 /* number of times pages failed to write */
205 write_u64("failedWrites : ", stats
->failed_writes
, ", ", buf
, maxlen
);
206 /* number of gets that are reclaimed */
207 write_u64("reclaimed : ", stats
->reclaimed
, ", ", buf
, maxlen
);
208 /* number of gets for outgoing pages */
209 write_u64("readOutgoing : ", stats
->read_outgoing
, ", ", buf
, maxlen
);
210 /* number of gets that were already there */
211 write_u64("foundInCache : ", stats
->found_in_cache
, ", ", buf
, maxlen
);
212 /* number of gets requiring discard */
213 write_u64("discardRequired : ", stats
->discard_required
, ", ", buf
, maxlen
);
214 /* number of gets enqueued for their page */
215 write_u64("waitForPage : ", stats
->wait_for_page
, ", ", buf
, maxlen
);
216 /* number of gets that have to fetch */
217 write_u64("fetchRequired : ", stats
->fetch_required
, ", ", buf
, maxlen
);
218 /* number of page fetches */
219 write_u64("pagesLoaded : ", stats
->pages_loaded
, ", ", buf
, maxlen
);
220 /* number of page saves */
221 write_u64("pagesSaved : ", stats
->pages_saved
, ", ", buf
, maxlen
);
222 /* the number of flushes issued */
223 write_u64("flushCount : ", stats
->flush_count
, ", ", buf
, maxlen
);
224 write_string(NULL
, "}", suffix
, buf
, maxlen
);
227 static void write_hash_lock_statistics(char *prefix
, struct hash_lock_statistics
*stats
,
228 char *suffix
, char **buf
, unsigned int *maxlen
)
230 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
231 /* Number of times the UDS advice proved correct */
232 write_u64("dedupeAdviceValid : ", stats
->dedupe_advice_valid
, ", ", buf
, maxlen
);
233 /* Number of times the UDS advice proved incorrect */
234 write_u64("dedupeAdviceStale : ", stats
->dedupe_advice_stale
, ", ", buf
, maxlen
);
235 /* Number of writes with the same data as another in-flight write */
236 write_u64("concurrentDataMatches : ", stats
->concurrent_data_matches
,
238 /* Number of writes whose hash collided with an in-flight write */
239 write_u64("concurrentHashCollisions : ",
240 stats
->concurrent_hash_collisions
, ", ", buf
, maxlen
);
241 /* Current number of dedupe queries that are in flight */
242 write_u32("currDedupeQueries : ", stats
->curr_dedupe_queries
, ", ", buf
, maxlen
);
243 write_string(NULL
, "}", suffix
, buf
, maxlen
);
246 static void write_error_statistics(char *prefix
, struct error_statistics
*stats
,
247 char *suffix
, char **buf
, unsigned int *maxlen
)
249 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
250 /* number of times VDO got an invalid dedupe advice PBN from UDS */
251 write_u64("invalidAdvicePBNCount : ", stats
->invalid_advice_pbn_count
,
253 /* number of times a VIO completed with a VDO_NO_SPACE error */
254 write_u64("noSpaceErrorCount : ", stats
->no_space_error_count
, ", ",
256 /* number of times a VIO completed with a VDO_READ_ONLY error */
257 write_u64("readOnlyErrorCount : ", stats
->read_only_error_count
, ", ",
259 write_string(NULL
, "}", suffix
, buf
, maxlen
);
262 static void write_bio_stats(char *prefix
, struct bio_stats
*stats
, char *suffix
,
263 char **buf
, unsigned int *maxlen
)
265 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
266 /* Number of REQ_OP_READ bios */
267 write_u64("read : ", stats
->read
, ", ", buf
, maxlen
);
268 /* Number of REQ_OP_WRITE bios with data */
269 write_u64("write : ", stats
->write
, ", ", buf
, maxlen
);
270 /* Number of bios tagged with REQ_PREFLUSH and containing no data */
271 write_u64("emptyFlush : ", stats
->empty_flush
, ", ", buf
, maxlen
);
272 /* Number of REQ_OP_DISCARD bios */
273 write_u64("discard : ", stats
->discard
, ", ", buf
, maxlen
);
274 /* Number of bios tagged with REQ_PREFLUSH */
275 write_u64("flush : ", stats
->flush
, ", ", buf
, maxlen
);
276 /* Number of bios tagged with REQ_FUA */
277 write_u64("fua : ", stats
->fua
, ", ", buf
, maxlen
);
278 write_string(NULL
, "}", suffix
, buf
, maxlen
);
281 static void write_memory_usage(char *prefix
, struct memory_usage
*stats
, char *suffix
,
282 char **buf
, unsigned int *maxlen
)
284 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
285 /* Tracked bytes currently allocated. */
286 write_u64("bytesUsed : ", stats
->bytes_used
, ", ", buf
, maxlen
);
287 /* Maximum tracked bytes allocated. */
288 write_u64("peakBytesUsed : ", stats
->peak_bytes_used
, ", ", buf
, maxlen
);
289 write_string(NULL
, "}", suffix
, buf
, maxlen
);
292 static void write_index_statistics(char *prefix
, struct index_statistics
*stats
,
293 char *suffix
, char **buf
, unsigned int *maxlen
)
295 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
296 /* Number of records stored in the index */
297 write_u64("entriesIndexed : ", stats
->entries_indexed
, ", ", buf
, maxlen
);
298 /* Number of post calls that found an existing entry */
299 write_u64("postsFound : ", stats
->posts_found
, ", ", buf
, maxlen
);
300 /* Number of post calls that added a new entry */
301 write_u64("postsNotFound : ", stats
->posts_not_found
, ", ", buf
, maxlen
);
302 /* Number of query calls that found an existing entry */
303 write_u64("queriesFound : ", stats
->queries_found
, ", ", buf
, maxlen
);
304 /* Number of query calls that added a new entry */
305 write_u64("queriesNotFound : ", stats
->queries_not_found
, ", ", buf
, maxlen
);
306 /* Number of update calls that found an existing entry */
307 write_u64("updatesFound : ", stats
->updates_found
, ", ", buf
, maxlen
);
308 /* Number of update calls that added a new entry */
309 write_u64("updatesNotFound : ", stats
->updates_not_found
, ", ", buf
, maxlen
);
310 /* Number of entries discarded */
311 write_u64("entriesDiscarded : ", stats
->entries_discarded
, ", ", buf
, maxlen
);
312 write_string(NULL
, "}", suffix
, buf
, maxlen
);
315 static void write_vdo_statistics(char *prefix
, struct vdo_statistics
*stats
, char *suffix
,
316 char **buf
, unsigned int *maxlen
)
318 write_string(prefix
, "{ ", NULL
, buf
, maxlen
);
319 write_u32("version : ", stats
->version
, ", ", buf
, maxlen
);
320 /* Number of blocks used for data */
321 write_u64("dataBlocksUsed : ", stats
->data_blocks_used
, ", ", buf
, maxlen
);
322 /* Number of blocks used for VDO metadata */
323 write_u64("overheadBlocksUsed : ", stats
->overhead_blocks_used
, ", ",
325 /* Number of logical blocks that are currently mapped to physical blocks */
326 write_u64("logicalBlocksUsed : ", stats
->logical_blocks_used
, ", ", buf
, maxlen
);
327 /* number of physical blocks */
328 write_block_count_t("physicalBlocks : ", stats
->physical_blocks
, ", ",
330 /* number of logical blocks */
331 write_block_count_t("logicalBlocks : ", stats
->logical_blocks
, ", ",
333 /* Size of the block map page cache, in bytes */
334 write_u64("blockMapCacheSize : ", stats
->block_map_cache_size
, ", ",
336 /* The physical block size */
337 write_u64("blockSize : ", stats
->block_size
, ", ", buf
, maxlen
);
338 /* Number of times the VDO has successfully recovered */
339 write_u64("completeRecoveries : ", stats
->complete_recoveries
, ", ",
341 /* Number of times the VDO has recovered from read-only mode */
342 write_u64("readOnlyRecoveries : ", stats
->read_only_recoveries
, ", ",
344 /* String describing the operating mode of the VDO */
345 write_string("mode : ", stats
->mode
, ", ", buf
, maxlen
);
346 /* Whether the VDO is in recovery mode */
347 write_bool("inRecoveryMode : ", stats
->in_recovery_mode
, ", ", buf
, maxlen
);
348 /* What percentage of recovery mode work has been completed */
349 write_u8("recoveryPercentage : ", stats
->recovery_percentage
, ", ", buf
, maxlen
);
350 /* The statistics for the compressed block packer */
351 write_packer_statistics("packer : ", &stats
->packer
, ", ", buf
, maxlen
);
352 /* Counters for events in the block allocator */
353 write_block_allocator_statistics("allocator : ", &stats
->allocator
,
355 /* Counters for events in the recovery journal */
356 write_recovery_journal_statistics("journal : ", &stats
->journal
, ", ",
358 /* The statistics for the slab journals */
359 write_slab_journal_statistics("slabJournal : ", &stats
->slab_journal
,
361 /* The statistics for the slab summary */
362 write_slab_summary_statistics("slabSummary : ", &stats
->slab_summary
,
364 /* The statistics for the reference counts */
365 write_ref_counts_statistics("refCounts : ", &stats
->ref_counts
, ", ",
367 /* The statistics for the block map */
368 write_block_map_statistics("blockMap : ", &stats
->block_map
, ", ", buf
, maxlen
);
369 /* The dedupe statistics from hash locks */
370 write_hash_lock_statistics("hashLock : ", &stats
->hash_lock
, ", ", buf
, maxlen
);
371 /* Counts of error conditions */
372 write_error_statistics("errors : ", &stats
->errors
, ", ", buf
, maxlen
);
373 /* The VDO instance */
374 write_u32("instance : ", stats
->instance
, ", ", buf
, maxlen
);
375 /* Current number of active VIOs */
376 write_u32("currentVIOsInProgress : ", stats
->current_vios_in_progress
,
378 /* Maximum number of active VIOs */
379 write_u32("maxVIOs : ", stats
->max_vios
, ", ", buf
, maxlen
);
380 /* Number of times the UDS index was too slow in responding */
381 write_u64("dedupeAdviceTimeouts : ", stats
->dedupe_advice_timeouts
,
383 /* Number of flush requests submitted to the storage device */
384 write_u64("flushOut : ", stats
->flush_out
, ", ", buf
, maxlen
);
385 /* Logical block size */
386 write_u64("logicalBlockSize : ", stats
->logical_block_size
, ", ", buf
, maxlen
);
387 /* Bios submitted into VDO from above */
388 write_bio_stats("biosIn : ", &stats
->bios_in
, ", ", buf
, maxlen
);
389 write_bio_stats("biosInPartial : ", &stats
->bios_in_partial
, ", ", buf
, maxlen
);
390 /* Bios submitted onward for user data */
391 write_bio_stats("biosOut : ", &stats
->bios_out
, ", ", buf
, maxlen
);
392 /* Bios submitted onward for metadata */
393 write_bio_stats("biosMeta : ", &stats
->bios_meta
, ", ", buf
, maxlen
);
394 write_bio_stats("biosJournal : ", &stats
->bios_journal
, ", ", buf
, maxlen
);
395 write_bio_stats("biosPageCache : ", &stats
->bios_page_cache
, ", ", buf
, maxlen
);
396 write_bio_stats("biosOutCompleted : ", &stats
->bios_out_completed
, ", ",
398 write_bio_stats("biosMetaCompleted : ", &stats
->bios_meta_completed
,
400 write_bio_stats("biosJournalCompleted : ",
401 &stats
->bios_journal_completed
, ", ", buf
, maxlen
);
402 write_bio_stats("biosPageCacheCompleted : ",
403 &stats
->bios_page_cache_completed
, ", ", buf
, maxlen
);
404 write_bio_stats("biosAcknowledged : ", &stats
->bios_acknowledged
, ", ",
406 write_bio_stats("biosAcknowledgedPartial : ",
407 &stats
->bios_acknowledged_partial
, ", ", buf
, maxlen
);
408 /* Current number of bios in progress */
409 write_bio_stats("biosInProgress : ", &stats
->bios_in_progress
, ", ",
411 /* Memory usage stats. */
412 write_memory_usage("memoryUsage : ", &stats
->memory_usage
, ", ", buf
, maxlen
);
413 /* The statistics for the UDS index */
414 write_index_statistics("index : ", &stats
->index
, ", ", buf
, maxlen
);
415 write_string(NULL
, "}", suffix
, buf
, maxlen
);
418 int vdo_write_stats(struct vdo
*vdo
, char *buf
, unsigned int maxlen
)
420 struct vdo_statistics
*stats
;
423 result
= vdo_allocate(1, struct vdo_statistics
, __func__
, &stats
);
424 if (result
!= VDO_SUCCESS
) {
425 vdo_log_error("Cannot allocate memory to write VDO statistics");
429 vdo_fetch_statistics(vdo
, stats
);
430 write_vdo_statistics(NULL
, stats
, NULL
, &buf
, &maxlen
);
435 static void write_index_memory(u32 mem
, char **buf
, unsigned int *maxlen
)
437 char *prefix
= "memorySize : ";
439 /* Convert index memory to fractional value */
440 if (mem
== (u32
)UDS_MEMORY_CONFIG_256MB
)
441 write_string(prefix
, "0.25, ", NULL
, buf
, maxlen
);
442 else if (mem
== (u32
)UDS_MEMORY_CONFIG_512MB
)
443 write_string(prefix
, "0.50, ", NULL
, buf
, maxlen
);
444 else if (mem
== (u32
)UDS_MEMORY_CONFIG_768MB
)
445 write_string(prefix
, "0.75, ", NULL
, buf
, maxlen
);
447 write_u32(prefix
, mem
, ", ", buf
, maxlen
);
450 static void write_index_config(struct index_config
*config
, char **buf
,
451 unsigned int *maxlen
)
453 write_string("index : ", "{ ", NULL
, buf
, maxlen
);
455 write_index_memory(config
->mem
, buf
, maxlen
);
456 /* whether the index is sparse or not */
457 write_bool("isSparse : ", config
->sparse
, ", ", buf
, maxlen
);
458 write_string(NULL
, "}", ", ", buf
, maxlen
);
461 int vdo_write_config(struct vdo
*vdo
, char **buf
, unsigned int *maxlen
)
463 struct vdo_config
*config
= &vdo
->states
.vdo
.config
;
465 write_string(NULL
, "{ ", NULL
, buf
, maxlen
);
467 write_u32("version : ", 1, ", ", buf
, maxlen
);
469 write_block_count_t("physicalSize : ", config
->physical_blocks
* VDO_BLOCK_SIZE
, ", ",
472 write_block_count_t("logicalSize : ", config
->logical_blocks
* VDO_BLOCK_SIZE
, ", ",
475 write_block_count_t("slabSize : ", config
->slab_size
, ", ", buf
, maxlen
);
477 write_index_config(&vdo
->geometry
.index_config
, buf
, maxlen
);
478 write_string(NULL
, "}", NULL
, buf
, maxlen
);