1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-05 13:18:20 +03:00

dmstats: add libdm-stats library and 'dmsetup stats' command

Add the libdm-stats module to libdm: this implements a simple interface
for creating, managing and interrogating I/O statistics regions and
areas on device-mapper devices.

The library interface is documented in libdevmapper.h and provides a
'dm_stats' handle that is used to perform statistics operations and
obtain data.

Public methods are provided to create and destroy handles and to list,
create, and destroy statistics regions as well as to obtain and parse
counter data and calculate rate-based metrics.

This commit also adds a 'dmsetup stats' (aka 'dmstats') command with
'clear', 'create', 'delete', 'list', 'print', and 'report' sub-commands.

See the library documentation and the dmstats.8 manual page for detailed
API and command descriptions.
This commit is contained in:
Bryn M. Reeves 2015-08-05 10:40:00 +01:00
parent f06d866110
commit d62a8d2f15
8 changed files with 4388 additions and 37 deletions

View File

@ -1,5 +1,19 @@
Version 1.02.104 -
=================================
Add dmstats.8 man page
Add report stats sub-command to provide repeating stats reports.
Add clear, delete, list, and print stats sub-commands.
Add --segments switch to create one region per device segment.
Add create stats sub-command and --start, --length, --areas and --areasize.
Recognize 'dmstats' as an alias for 'dmsetup stats' when run with this name.
Add a 'stats' command to dmsetup to configure, manage and report stats data.
Add --regionid, --allregions to specify a single stats region or all regions.
Add --allprograms for stats commands that filter by program ID.
Add --auxdata and --programid arguments to specify aux data and program ID.
Add statistics fields to -o <field>
Add libdm-stats library to allow management of device-mapper statistics.
Add --nosuffix to suppress unit suffixes in report output.
Add --units to control report field output units.
Add support to redisplay column headings for repeating column reports.
Fix report header and row resource leaks.
Report timestamps of ioctls with dmsetup -vvv.

View File

@ -1,5 +1,73 @@
dm_report_column_headings
dm_size_to_string
dm_stats_bind_devno
dm_stats_bind_name
dm_stats_bind_uuid
dm_stats_buffer_destroy
dm_stats_clear_region
dm_stats_create
dm_stats_create_region
dm_stats_delete_region
dm_stats_destroy
dm_stats_get_area_start
dm_stats_get_average_queue_size
dm_stats_get_average_rd_wait_time
dm_stats_get_average_request_size
dm_stats_get_average_wait_time
dm_stats_get_average_wr_wait_time
dm_stats_get_current_area
dm_stats_get_current_area_len
dm_stats_get_current_area_start
dm_stats_get_current_nr_areas
dm_stats_get_current_region
dm_stats_get_current_region_area_len
dm_stats_get_current_region_aux_data
dm_stats_get_current_region_len
dm_stats_get_current_region_program_id
dm_stats_get_current_region_start
dm_stats_get_io_in_progress
dm_stats_get_io_nsecs
dm_stats_get_nr_areas
dm_stats_get_nr_regions
dm_stats_get_rd_merges_per_sec
dm_stats_get_read_nsecs
dm_stats_get_reads
dm_stats_get_read_sectors
dm_stats_get_read_sectors_per_sec
dm_stats_get_reads_merged
dm_stats_get_reads_per_sec
dm_stats_get_region_area_len
dm_stats_get_region_aux_data
dm_stats_get_region_len
dm_stats_get_region_nr_areas
dm_stats_get_region_program_id
dm_stats_get_region_start
dm_stats_get_sampling_interval_ms
dm_stats_get_sampling_interval_ns
dm_stats_get_service_time
dm_stats_get_throughput
dm_stats_get_total_read_nsecs
dm_stats_get_total_write_nsecs
dm_stats_get_utilization
dm_stats_get_weighted_io_nsecs
dm_stats_get_write_nsecs
dm_stats_get_writes
dm_stats_get_write_sectors
dm_stats_get_write_sectors_per_sec
dm_stats_get_writes_merged
dm_stats_get_writes_per_sec
dm_stats_get_wr_merges_per_sec
dm_stats_list
dm_stats_populate
dm_stats_print_region
dm_stats_region_present
dm_stats_set_program_id
dm_stats_set_sampling_interval_ms
dm_stats_set_sampling_interval_ns
dm_stats_walk_end
dm_stats_walk_next
dm_stats_walk_next_region
dm_stats_walk_start
dm_task_get_ioctl_timestamp
dm_task_set_record_timestamp
dm_timestamp_alloc

View File

@ -26,6 +26,7 @@ SOURCES =\
libdm-string.c \
libdm-report.c \
libdm-timestamp.c \
libdm-stats.c \
libdm-config.c \
mm/dbg_malloc.c \
mm/pool.c \

View File

@ -395,6 +395,502 @@ struct dm_status_thin {
int dm_get_status_thin(struct dm_pool *mem, const char *params,
struct dm_status_thin **status);
/*
* device-mapper statistics support
*/
/*
* Statistics handle.
*
* Operations on dm_stats objects include managing statistics regions
* and obtaining and manipulating current counter values from the
* kernel. Methods are provided to return baisc count values and to
* derive time-based metrics when a suitable interval estimate is
* provided.
*
* Internally the dm_stats handle contains a pointer to a table of one
* or more dm_stats_region objects representing the regions registered
* with the dm_stats_create_region() method. These in turn point to a
* table of one or more dm_stats_counters objects containing the
* counter sets for each defined area within the region:
*
* dm_stats->dm_stats_region[nr_regions]->dm_stats_counters[nr_areas]
*
* This structure is private to the library and may change in future
* versions: all users should make use of the public interface and treat
* the dm_stats type as an opaque handle.
*
* Regions and counter sets are stored in order of increasing region_id.
* Depending on region specifications and the sequence of create and
* delete operations this may not correspond to increasing sector
* number: users of the library should not assume that this is the case
* unless region creation is deliberately managed to ensure this (by
* always creating regions in strict order of ascending sector address).
*
* Regions may also overlap so the same sector range may be included in
* more than one region or area: applications should be prepared to deal
* with this or manage regions such that it does not occur.
*/
struct dm_stats;
/*
* Allocate a dm_stats handle to use for subsequent device-mapper
* statistics operations. A program_id may be specified and will be
* used by default for subsequent operations on this handle.
*
* If program_id is NULL or the empty string a program_id will be
* automatically set to the value contained in /proc/self/comm.
*/
struct dm_stats *dm_stats_create(const char *program_id);
/*
* Bind a dm_stats handle to the specified device major and minor
* values. Any previous binding is cleared and any preexisting counter
* data contained in the handle is released.
*/
int dm_stats_bind_devno(struct dm_stats *dms, int major, int minor);
/*
* Bind a dm_stats handle to the specified device name.
* Any previous binding is cleared and any preexisting counter
* data contained in the handle is released.
*/
int dm_stats_bind_name(struct dm_stats *dms, const char *name);
/*
* Bind a dm_stats handle to the specified device UUID.
* Any previous binding is cleared and any preexisting counter
* data contained in the handle is released.
*/
int dm_stats_bind_uuid(struct dm_stats *dms, const char *uuid);
#define DM_STATS_ALL_PROGRAMS ""
/*
* Parse the response from a @stats_list message. dm_stats_list will
* allocate the necessary dm_stats and dm_stats region structures from
* the embedded dm_pool. No counter data will be obtained (the counters
* members of dm_stats_region objects are set to NULL).
*
* A program_id may optionally be supplied; if the argument is non-NULL
* only regions with a matching program_id value will be considered. If
* the argument is NULL then the default program_id associated with the
* dm_stats handle will be used. Passing the special value
* DM_STATS_ALL_PROGRAMS will cause all regions to be queried
* regardless of region program_id.
*/
int dm_stats_list(struct dm_stats *dms, const char *program_id);
#define DM_STATS_REGIONS_ALL UINT64_MAX
/*
* Populate a dm_stats object with statistics for one or more regions of
* the specified device.
*
* A program_id may optionally be supplied; if the argument is non-NULL
* only regions with a matching program_id value will be considered. If
* the argument is NULL then the default program_id associated with the
* dm_stats handle will be used. Passing the special value
* DM_STATS_ALL_PROGRAMS will cause all regions to be queried
* regardless of region program_id.
*
* Passing the special value DM_STATS_REGIONS_ALL as the region_id
* argument will attempt to retrieve all regions selected by the
* program_id argument.
*
* If region_id is used to request a single region_id to be populated
* the program_id is ignored.
*/
int dm_stats_populate(struct dm_stats *dms, const char *program_id,
uint64_t region_id);
/*
* Create a new statistics region on the device bound to dms.
*
* start and len specify the region start and length in 512b sectors.
* Passing zero for both start and len will create a region spanning
* the entire device.
*
* Step determines how to subdivide the region into discrete counter
* sets: a positive value specifies the size of areas into which the
* region should be split while a negative value will split the region
* into a number of areas equal to the absolute value of step:
*
* - a region with one area spanning the entire device:
*
* dm_stats_create_region(dms, 0, 0, -1, p, a);
*
* - a region with areas of 1MiB:
*
* dm_stats_create_region(dms, 0, 0, 1 << 11, p, a);
*
* - one 1MiB region starting at 1024 sectors with two areas:
*
* dm_stats_create_region(dms, 1024, 1 << 11, -2, p, a);
*
* program_id is an optional string argument that identifies the
* program creating the region. If program_id is NULL or the empty
* string the default program_id stored in the handle will be used.
*
* aux_data is an optional string argument passed to the kernel that is
* stored with the statistics region. It is not currently accessed by
* the library or kernel and may be used to store arbitrary user data.
*
* The region_id of the newly-created region is returned in *region_id
* if it is non-NULL.
*/
int dm_stats_create_region(struct dm_stats *dms, uint64_t *region_id,
uint64_t start, uint64_t len, int64_t step,
const char *program_id, const char *aux_data);
/*
* Delete the specified statistics region. This will also mark the
* region as not-present and discard any existing statistics data.
*/
int dm_stats_delete_region(struct dm_stats *dms, uint64_t region_id);
/*
* Clear the specified statistics region. This requests the kernel to
* zero all counter values (except in-flight I/O). Note that this
* operation is not atomic with respect to reads of the counters; any IO
* events occurring between the last print operation and the clear will
* be lost. This can be avoided by using the atomic print-and-clear
* function of the dm_stats_print_region() call or by using the higher
* level dm_stats_populate() interface.
*/
int dm_stats_clear_region(struct dm_stats *dms, uint64_t region_id);
/*
* Print the current counter values for the specified statistics region
* and return them as a string. The memory for the string buffer will
* be allocated from the dm_stats handle's private pool and should be
* returned by calling dm_stats_buffer_destroy() when no longer
* required. The pointer will become invalid following any call that
* clears or reinitializes the handle (destroy, list, populate, bind).
*
* This allows applications that wish to access the raw message response
* to obtain it via a dm_stats handle; no parsing of the textual counter
* data is carried out by this function.
*
* Most users are recommended to use the dm_stats_populate() call
* instead since this will automatically parse the statistics data into
* numeric form accessible via the dm_stats_get_*() counter access
* methods.
*
* A subset of the data lines may be requested by setting the
* start_line and num_lines parameters. If both are zero all data
* lines are returned.
*
* If the clear parameter is non-zero the operation will also
* atomically reset all counter values to zero (except in-flight IO).
*/
char *dm_stats_print_region(struct dm_stats *dms, uint64_t region_id,
unsigned start_line, unsigned num_lines,
unsigned clear);
/*
* Destroy a statistics response buffer obtained from a call to
* dm_stats_print_region().
*/
void dm_stats_buffer_destroy(struct dm_stats *dms, char *buffer);
/*
* Determine the number of regions contained in a dm_stats handle
* following a dm_stats_list() or dm_stats_populate() call.
*
* The value returned is the number of registered regions visible with the
* progam_id value used for the list or populate operation and may not be
* equal to the highest present region_id (either due to program_id
* filtering or gaps in the sequence of region_id values).
*
* Always returns zero on an empty handle.
*/
uint64_t dm_stats_get_nr_regions(const struct dm_stats *dms);
/*
* Test whether region_id is present in this dm_stats handle.
*/
int dm_stats_region_present(const struct dm_stats *dms, uint64_t region_id);
/*
* Returns the number of areas (counter sets) contained in the specified
* region_id of the supplied dm_stats handle.
*/
uint64_t dm_stats_get_region_nr_areas(const struct dm_stats *dms,
uint64_t region_id);
/*
* Returns the total number of areas (counter sets) in all regions of the
* given dm_stats object.
*/
uint64_t dm_stats_get_nr_areas(const struct dm_stats *dms);
/*
* Destroy a dm_stats object and all associated regions and counter
* sets.
*/
void dm_stats_destroy(struct dm_stats *dms);
/*
* Counter sampling interval
*/
/*
* Set the sampling interval for counter data to the specified value in
* either nanoseconds or milliseconds.
*
* The interval is used to calculate time-based metrics from the basic
* counter data: an interval must be set before calling any of the
* metric methods.
*
* For best accuracy the duration should be measured and updated at the
* end of each interval.
*
* All values are stored internally with nanosecond precision and are
* converted to or from ms when the millisecond interfaces are used.
*/
void dm_stats_set_sampling_interval_ns(struct dm_stats *dms,
uint64_t interval_ns);
void dm_stats_set_sampling_interval_ms(struct dm_stats *dms,
uint64_t interval_ms);
/*
* Retrieve the configured sampling interval in either nanoseconds or
* milliseconds.
*/
uint64_t dm_stats_get_sampling_interval_ns(const struct dm_stats *dms);
uint64_t dm_stats_get_sampling_interval_ms(const struct dm_stats *dms);
/*
* Override program_id. This may be used to change the default
* program_id value for an existing handle. If the allow_empty argument
* is non-zero a NULL or empty program_id is permitted.
*
* Use with caution! Most users of the library should set a valid,
* non-NULL program_id for every statistics region created. Failing to
* do so may result in confusing state when multiple programs are
* creating and managing statistics regions.
*
* All users of the library are encouraged to choose an unambiguous,
* unique program_id: this could be based on PID (for programs that
* create, report, and delete regions in a single process), session id,
* executable name, or some other distinguishing string.
*
* Use of the empty string as a program_id does not simplify use of the
* library or the command line tools and use of this value is strongly
* discouraged.
*/
int dm_stats_set_program_id(struct dm_stats *dms, int allow_empty,
const char *program_id);
/*
* Region properties: size, length & area_len.
*
* Region start and length are returned in units of 512b as specified
* at region creation time. The area_len value gives the size of areas
* into which the region has been subdivided. For regions with a single
* area spanning the range this value is equal to the region length.
*
* For regions created with a specified number of areas the value
* represents the size of the areas into which the kernel divided the
* region excluding any rounding of the last area size. The number of
* areas may be obtained using the dm_stats_nr_areas_region() call.
*
* All values are returned in units of 512b sectors.
*/
uint64_t dm_stats_get_region_start(const struct dm_stats *dms, uint64_t *start,
uint64_t region_id);
uint64_t dm_stats_get_region_len(const struct dm_stats *dms, uint64_t *len,
uint64_t region_id);
uint64_t dm_stats_get_region_area_len(const struct dm_stats *dms,
uint64_t *area_len, uint64_t region_id);
/*
* Area properties: start and length.
*
* The area length is always equal to the area length of the region
* that contains it and is obtained from dm_stats_get_region_area_len().
*
* The start offset of an area is a function of the area_id and the
* containing region's start and area length.
*
* All values are returned in units of 512b sectors.
*/
uint64_t dm_stats_get_area_start(const struct dm_stats *dms, uint64_t *start,
uint64_t region_id, uint64_t area_id);
/*
* Retrieve program_id and aux_data for a specific region. Only valid
* following a call to dm_stats_list(). The returned pointer does not
* need to be freed separately from the dm_stats handle but will become
* invalid after a dm_stats_destroy(), dm_stats_list(),
* dm_stats_populate(), or dm_stats_bind*() of the handle from which it
* was obtained.
*/
const char *dm_stats_get_region_program_id(const struct dm_stats *dms,
uint64_t region_id);
const char *dm_stats_get_region_aux_data(const struct dm_stats *dms,
uint64_t region_id);
/*
* Statistics cursor
*
* A dm_stats handle maintains an optional cursor into the statistics
* regions and areas that it stores. Iterators are provided to visit
* each region, or each area in a handle and accessor methods are
* provided to obtain properties and values for the region or area
* at the current cursor position.
*
* Using the cursor simplifies walking all regions or areas when the
* region table is sparse (i.e. contains some present and some
* non-present region_id values either due to program_id filtering
* or the ordering of region creation and deletion).
*/
/*
* Initialise the cursor of a dm_stats handle to address the first
* present region. It is valid to attempt to walk a NULL stats handle
* or a handle containing no present regions; in this case any call to
* dm_stats_walk_next() becomes a no-op and all calls to
* dm_stats_walk_end() return true.
*/
void dm_stats_walk_start(struct dm_stats *dms);
/*
* Advance the statistics cursor to the next area, or to the next
* present region if at the end of the current region.
*/
void dm_stats_walk_next(struct dm_stats *dms);
/*
* Advance the statistics cursor to the next region.
*/
void dm_stats_walk_next_region(struct dm_stats *dms);
/*
* Test whether the end of a statistics walk has been reached.
*/
int dm_stats_walk_end(struct dm_stats *dms);
/*
* Stats iterators
*
* C 'for' and 'do'/'while' style iterators for dm_stats data.
*
* It is not safe to call any function that modifies the region table
* within the loop body (i.e. dm_stats_list(), dm_stats_populate(),
* dm_stats_init(), or dm_stats_destroy()).
*
* All counter and property (dm_stats_get_*) access methods, as well as
* dm_stats_populate_region() can be safely called from loops.
*
*/
/*
* Iterate over the regions table visiting each region.
*
* If the region table is empty or unpopulated the loop body will not be
* executed.
*/
#define dm_stats_foreach_region(dms) \
for (dm_stats_walk_start((dms)); \
!dm_stats_walk_end((dms)); dm_stats_walk_next_region((dms)))
/*
* Iterate over the regions table visiting each area.
*
* If the region table is empty or unpopulated the loop body will not
* be executed.
*/
#define dm_stats_foreach_area(dms) \
for (dm_stats_walk_start((dms)); \
!dm_stats_walk_end((dms)); dm_stats_walk_next((dms)))
/*
* Start a walk iterating over the regions contained in dm_stats handle
* 'dms'.
*
* The body of the loop should call dm_stats_walk_next() or
* dm_stats_walk_next_region() to advance to the next element.
*
* The loop body is executed at least once even if the stats handle is
* empty.
*/
#define dm_stats_walk_do(dms) \
dm_stats_walk_start((dms)); \
do
/*
* Start a 'while' style loop or end a 'do..while' loop iterating over the
* regions contained in dm_stats handle 'dms'.
*/
#define dm_stats_walk_while(dms) \
while(!dm_stats_walk_end((dms)))
/*
* Cursor relative property methods
*
* Calls with the prefix dm_stats_get_current_* operate relative to the
* current cursor location, returning properties for the current region
* or area of the supplied dm_stats handle.
*
*/
/*
* Returns the number of areas (counter sets) contained in the current
* region of the supplied dm_stats handle.
*/
uint64_t dm_stats_get_current_nr_areas(const struct dm_stats *dms);
/*
* Retrieve the current values of the stats cursor.
*/
uint64_t dm_stats_get_current_region(const struct dm_stats *dms);
uint64_t dm_stats_get_current_area(const struct dm_stats *dms);
/*
* Current region properties: size, length & area_len.
*
* See the comments for the equivalent dm_stats_get_* versions for a
* complete description of these methods.
*
* All values are returned in units of 512b sectors.
*/
uint64_t dm_stats_get_current_region_start(const struct dm_stats *dms,
uint64_t *start);
uint64_t dm_stats_get_current_region_len(const struct dm_stats *dms,
uint64_t *len);
uint64_t dm_stats_get_current_region_area_len(const struct dm_stats *dms,
uint64_t *area_len);
/*
* Current area properties: start and length.
*
* See the comments for the equivalent dm_stats_get_* versions for a
* complete description of these methods.
*
* All values are returned in units of 512b sectors.
*/
uint64_t dm_stats_get_current_area_start(const struct dm_stats *dms,
uint64_t *start);
uint64_t dm_stats_get_current_area_len(const struct dm_stats *dms,
uint64_t *start);
/*
* Return a pointer to the program_id string for region at the current
* cursor location.
*/
const char *dm_stats_get_current_region_program_id(const struct dm_stats *dms);
/*
* Return a pointer to the aux_data string for the region at the current
* cursor location.
*/
const char *dm_stats_get_current_region_aux_data(const struct dm_stats *dms);
/*
* Call this to actually run the ioctl.
*/
@ -1941,6 +2437,153 @@ int dm_report_field_percent(struct dm_report *rh, struct dm_report_field *field,
void dm_report_field_set_value(struct dm_report_field *field, const void *value,
const void *sortvalue);
/*
* Stats counter access methods
*
* Each method returns the corresponding stats counter value from the
* supplied dm_stats handle for the specified region_id and area_id.
* If either region_id or area_id uses one of the special values
* DM_STATS_REGION_CURRENT or DM_STATS_AREA_CURRENT then the region
* or area is selected according to the current state of the dm_stats
* handle's embedded cursor.
*
* See the kernel documentation for complete descriptions of each
* counter field:
*
* Documentation/device-mapper/statistics.txt
* Documentation/iostats.txt
*
* reads: the number of reads completed
* reads_merged: the number of reads merged
* read_sectors: the number of sectors read
* read_nsecs: the number of nanoseconds spent reading
* writes: the number of writes completed
* writes_merged: the number of writes merged
* write_sectors: the number of sectors written
* write_nsecs: the number of nanoseconds spent writing
* io_in_progress: the number of I/Os currently in progress
* io_nsecs: the number of nanoseconds spent doing I/Os
* weighted_io_nsecs: the weighted number of nanoseconds spent doing I/Os
* total_read_nsecs: the total time spent reading in nanoseconds
* total_write_nsecs: the total time spent writing in nanoseconds
*/
#define DM_STATS_REGION_CURRENT UINT64_MAX
#define DM_STATS_AREA_CURRENT UINT64_MAX
uint64_t dm_stats_get_reads(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_reads_merged(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_read_sectors(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_read_nsecs(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_writes(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_writes_merged(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_write_sectors(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_write_nsecs(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_io_in_progress(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_io_nsecs(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_weighted_io_nsecs(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_total_read_nsecs(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
uint64_t dm_stats_get_total_write_nsecs(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
/*
* Derived statistics access methods
*
* Each method returns the corresponding value calculated from the
* counters stored in the supplied dm_stats handle for the specified
* region_id and area_id. If either region_id or area_id uses one of the
* special values DM_STATS_REGION_CURRENT or DM_STATS_AREA_CURRENT then
* the region or area is selected according to the current state of the
* dm_stats handle's embedded cursor.
*
* The set of metrics is based on the fields provided by the Linux
* iostats program.
*
* rd_merges_per_sec: the number of reads merged per second
* wr_merges_per_sec: the number of writes merged per second
* reads_per_sec: the number of reads completed per second
* writes_per_sec: the number of writes completed per second
* read_sectors_per_sec: the number of sectors read per second
* write_sectors_per_sec: the number of sectors written per second
* average_request_size: the average size of requests submitted
* service_time: the average service time (in ns) for requests issued
* average_queue_size: the average queue length
* average_wait_time: the average time for requests to be served (in ns)
* average_rd_wait_time: the average read wait time
* average_wr_wait_time: the average write wait time
*/
int dm_stats_get_rd_merges_per_sec(const struct dm_stats *dms, double *rrqm,
uint64_t region_id, uint64_t area_id);
int dm_stats_get_wr_merges_per_sec(const struct dm_stats *dms, double *rrqm,
uint64_t region_id, uint64_t area_id);
int dm_stats_get_reads_per_sec(const struct dm_stats *dms, double *rd_s,
uint64_t region_id, uint64_t area_id);
int dm_stats_get_writes_per_sec(const struct dm_stats *dms, double *wr_s,
uint64_t region_id, uint64_t area_id);
int dm_stats_get_read_sectors_per_sec(const struct dm_stats *dms,
double *rsec_s, uint64_t region_id,
uint64_t area_id);
int dm_stats_get_write_sectors_per_sec(const struct dm_stats *dms,
double *wr_s, uint64_t region_id,
uint64_t area_id);
int dm_stats_get_average_request_size(const struct dm_stats *dms,
double *arqsz, uint64_t region_id,
uint64_t area_id);
int dm_stats_get_service_time(const struct dm_stats *dms, double *svctm,
uint64_t region_id, uint64_t area_id);
int dm_stats_get_average_queue_size(const struct dm_stats *dms, double *qusz,
uint64_t region_id, uint64_t area_id);
int dm_stats_get_average_wait_time(const struct dm_stats *dms, double *await,
uint64_t region_id, uint64_t area_id);
int dm_stats_get_average_rd_wait_time(const struct dm_stats *dms,
double *await, uint64_t region_id,
uint64_t area_id);
int dm_stats_get_average_wr_wait_time(const struct dm_stats *dms,
double *await, uint64_t region_id,
uint64_t area_id);
int dm_stats_get_throughput(const struct dm_stats *dms, double *tput,
uint64_t region_id, uint64_t area_id);
int dm_stats_get_utilization(const struct dm_stats *dms, dm_percent_t *util,
uint64_t region_id, uint64_t area_id);
/*************************
* config file parse/print
*************************/

1360
libdm/libdm-stats.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -83,7 +83,7 @@ ifneq ("@THIN@", "none")
MAN7+=lvmthin.7
endif
MAN8DM=dmsetup.8 $(DMEVENTDMAN) $(BLKDEACTIVATEMAN)
MAN8DM=dmsetup.8 dmstats.8 $(DMEVENTDMAN) $(BLKDEACTIVATEMAN)
MAN5DIR=$(mandir)/man5
MAN7DIR=$(mandir)/man7
MAN8DIR=$(mandir)/man8

693
man/dmstats.8.in Normal file
View File

@ -0,0 +1,693 @@
.TH DMSTATS 8 "Jul 25 2015" "Linux" "MAINTENANCE COMMANDS"
.SH NAME
dmstats \(em device-mapper statistics management
.SH SYNOPSIS
.ad l
.B dmsetup stats
.I command
.RB [ options ]
.br
.B dmstats <command>
.RB [[
.IR device_name ]
.RB |[ \-\-uuid
.IR uuid ]
.RB |[ \-\-major
.IR major
.RB \-\-minor
.IR minor ]]
.br
.B dmstats clear
.I device_name
.RB [ \-\-allregions
.RB | \-\-regionid
.IR id ]
.br
.B dmstats create
.I device_name
.RB [[ \-\-areas
.IR nr_areas ]
.RB |[ \-\-areasize
.IR area_size ]]
.RB [[ \-\-start
.IR start_sector ]
.RB [ \-\-length
.IR length ]
.RB |[ \-\-segments ]]
.RB [ \-\-auxdata
.IR data ]
.RB [ \-\-programid
.IR id ]
.br
.B dmstats delete
.I device_name
.RB [ \-\-force ]
.RB [ \-\-allregions
.RB | \-\-regionid
.IR id ]
.RB [ \-\-allprograms
.RB | \-\-programid
.IR id ]
.br
.B dmstats help
.RB [ \-c | \-C | \-\-columns ]
.br
.B dmstats list
.RI [ device_name ]
.RB [ \-\-allprograms
.RB | \-\-programid
.IR id ]
.RB [ \-\-units
.IR units ]
.RB [ \-\-nosuffix ]
.br
.B dmstats print
.RI [ device_name ]
.RB [ \-\-clear ]
.RB [ \-\-allprograms
.RB | \-\-programid
.IR id ]
.RB [ \-\-allregions
.RB | \-\-regionid
.IR id ]
.br
.B dmstats report
.RI [ device_name ]
.RB [ \-\-interval
.IR seconds ]
.RB [ \-\-count
.IR count ]
.RB [ \-\-units
.IR units ]
.RB [ \-\-allprograms ]
.RB [ \-\-programid
.IR id ]
.RB [ \-\-regionid
.IR id ]
.RB [ \-O | \-\-sort
.IR sort_fields ]
.RB [ \-S | \-\-select
.IR Selection ]
.RB [ \-\-units
.IR units ]
.RB [ \-\-nosuffix ]
.br
.ad b
.SH DESCRIPTION
The dmstats program manages IO statistics regions for devices that use
the device-mapper driver. Statistics regions may be created, deleted,
listed and reported on using the tool.
The first argument to dmstats is a command.
The second argument is the device name, uuid, or major and minor
numbers.
Further options permit the selection of regions, output format
control, and reporting behaviour.
When the program is run using the 'dmstats' alias, the command
\fBmust\fP be the first argument and any switches and options should be
specified following the command itself. This limitation is not present
when run as 'dmsetup stats'.
When no device argument is given dmstats will by default operate on all
device-mapper devices present. The \fBcreate\fP and \fBdelete\fP
commands require the use of \fB--force\fP when used in this way.
.SH OPTIONS
.TP
.B \-\-allprograms
Include regions from all program IDs for list and report operations.
.TP
.B \-\-allregions
Include all present regions for commands that normally accept a single
region identifier.
.TP
.B \-\-areas \fInr_areas
Specify the number of statistics areas to create within a new region.
.TP
.B \-\-areasize \fIarea_size
Specify the size of areas into which a new region should be divided. An
optional suffix selects units of bBsSkKmMgGtTpPeE: (b)ytes,
(s)ectors, (k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes,
(p)etabytes, (e)xabytes. Capitalise to use multiples of 1000 (S.I.)
instead of 1024.
.TP
.B \-\-auxdata \fIaux_data
Specify auxilliary data (a string) to be stored with a new region.
.TP
.B \-\-clear
When printing statistics counters, also atomically reset them to zero.
.TP
.B \-\-count \fIcount
Specify the iteration count for repeating reports. If the count
argument is zero reports will continue to repeat until interrupted.
.TP
.B \-\-interval \fIseconds
Specify the interval in seconds between successive iterations for
repeating reports. If \-\-interval is specified but \-\-count is not,
reports will continue to repeat until interrupted.
.TP
.B \-\-length \fIlength
Specify the length of a new statistics region in sectors. An optional
suffix selects units of bBsSkKmMgGtTpPeE: (b)ytes, (s)ectors,
(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes,
(e)xabytes. Capitalise to use multiples of 1000 (S.I.) instead of 1024.
.TP
.BR \-j | \-\-major\ \fImajor
Specify the major number.
.TP
.BR \-m | \-\-minor\ \fIminor
Specify the minor number.
.TP
.B \-\-nosuffix
Suppress the suffix on output sizes. Use with \fB\-\-units\fP
(except h and H) if processing the output.
.TP
.BR \-o | \-\-options
Specify which report fields to display.
.TP
.BR \-O | \-\-sort\ \fIsort_fields
Sort output according to the list of fields given. Precede any
sort_field with - for a reverse sort on that column.
.TP
.B \-\-programid \fIid
Specify a program ID string. When creating new statistics regions this
string is stored with the region. Subsequent operations may supply a
program ID in order to select only regions with a matching value. The
default program ID for dmstats-managed regions is "dmstats".
.TP
.BR \-S | \-\-select \ \fIselection
Display only rows that match selection criteria. All rows with the
additional "selected" column (-o selected) showing 1 if the row matches
the selection and 0 otherwise. The selection criteria are defined by
specifying column names and their valid values while making use of
supported comparison operators.
.TP
.B \-\-start \fIstart
Specify the start offset of a new statistics region in sectors. An
optional suffix selects units of bBsSkKmMgGtTpPeE: (b)ytes,
(s)ectors, (k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes,
(p)etabytes, (e)xabytes. Capitalise to use multiples of 1000 (S.I.)
instead of 1024.
.TP
.B \-\-segments
Create a new statistics region for each target contained in the target
device. This causes a separate region to be allocated for each segment
of the device.
.TP
.BR \-\-units \ hHbBsSkKmMgGtTpPeE
Set the display units for report output. All sizes are output in these
units: (h)uman-readable, (b)ytes, (s)ectors, (k)ilobytes, (m)egabytes,
(g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes. Capitalise to use
multiples of 1000 (S.I.) instead of 1024. Can also specify custom units
e.g. \fB\-\-units 3M\fP
.TP
.BR \-u | \-\-uuid
Specify the uuid.
.TP
.BR \-v | \-\-verbose \ [ \-v | \-\-verbose ]
Produce additional output.
.br
.SH COMMANDS
.TP
.B clear
.I device_name
.RB [ \-\-allregions
.RB | \-\-regionid
.IR id ]
.RB [ \-\-allprograms
.RB | \-\-programid
.IR id ]
.br
Instructs the kernel to clear statistics counters for the speficied
regions (with the exception of in-flight IO counters).
.br
.TP
.B create
.I device_name
.RB [ \-\-areas
.IR nr_areas ]
.RB [ \-\-areasize
.IR area_size ]
.RB [[ \-\-start
.IR start_sector ]
.RB [ \-\-length
.IR length ]
.RB |[ \-\-segments ]]
.RB [ \-\-auxdata
.IR data ]
.RB [ \-\-programid
.IR id ]
.br
Creates one or more new statistics regions on the specified device(s).
The region will span the entire device unless \fB\-\-start\fP and
\fB\-\-length\fP or \fB\-\-target\fP are given. The \fB\-\-start\fP and
\fB\-\-length\fP options allow a region of arbitrary length to be placed
at an arbitrary offset into the device. The \fB\-\-segments\fP option
causes a new region to be created for each target in the corresponding
device-mapper device's table.
An optional \fBprogram_id\fP or \fBaux_data\fP string may be associated
with the region. A \fBprogram_id\fP may then be used to select regions
for subsequent list, print, and report operations. The \fBaux_data\fP
stores an arbitrary string and is not used by dmstats or the
device-mapper kernel statistics subsystem.
By default dmstats creates regions with a \fBprogram_id\fP of
"DMSTATS1".
On success the \fBregion_id\fP of the newly created region is printed to
stdout.
.br
.TP
.B delete
.I [ device_name ]
.RB [ \-\-force ]
.RB [ \-\-allregions
.RB | \-\-regionid
.IR id ]
.RB [ \-\-allprograms
.RB | \-\-programid
.IR id ]
.br
Delete the specified statistics region. All counters and resources used
by the region are released and the region will not appear in the output
of subsequent list, print, or report operations.
All regions registered on a device may be removed using
\fB\-\-allregions\fP.
To remove all regions on all devices \fB\-\-force\fP must be used.
.br
.TP
.B help
.RB [ \-c | \-C | \-\-columns ]
.br
Outputs a summary of the commands available, optionally including
the list of report fields.
.br
.TP
.B list
.RI [ device_name ]
.RB [ \-\-allprograms ]
.RB [ \-\-programid
.IR id ]
.br
List the statistics regions registered on the device. If the
\fB\-\-allprograms\fP switch is given all regions will be listed
regardless of region program ID values.
.br
.TP
.B print
.RB [ \-\-clear ]
.IR
.RB [ \-\-allregions
.RB | \-\-regionid
.IR id ]
.RB [ \-\-allprograms
.RB | \-\-programid
.IR id ]
.br
Print raw statistics counters for the specified region or for all
present regions.
.br
.TP
.B report
.RB [ \-\-allprograms ]
.RB [ \-\-interval
.IR seconds ]
.RB [ \-\-count
.IR count ]
.RB [ \-\-units
.IR unit ]
.RB [ \-\-regionid
.IR id ]
.RB [ \-\-programid
.IR id ]
.RB [ \-O | \-\-sort
.IR sort_fields ]
.RB [ \-S | \-\-select
.IR Selection ]
.RB [ \-\-units
.IR units ]
.br
Start a report for the specified region or for all present regions. If
the count argument is specified, the report will repeat at a fixed
interval set by the \fB\-\-interval\fP option. The default interval is
one second.
If the \fB\-\-allprograms\fP switch is given, all regions will be
listed, regardless of region program ID values.
.br
.SH REGIONS AND AREAS
The device-mapper statistics facility allows separate performance
counters to be maintained for arbitrary regions of devices. A region may
span any range: from a single sector to the whole device. A region may
be further sub-divided into a number of distinct areas (one or more),
each with its own counter set.
By default new regions span the entire device. The \fB\-\-start\fP and
\fB\-\-length\fP options allows a region of any size to be placed at any
location on the device.
A region may be either divided into the specified number of equal-sized
areas, or into areas of the given size by specifying one of
\fB\-\-areas\fP or \fB\-\-areasize\fP when creating a region with the
\fBcreate\fP command. Depending on the size of the areas and the device
region the final area within the region may be smaller than requested.
.SS Region identifiers
Each region is assigned an identifier when it is created that is used to
reference the region in subsequent operations. Region identifiers are
unique within a given device (including across different \fBprogram_id\fP
values).
.br
Depending on the sequence of create and delete operations, gaps may
exist in the sequence of \fBregion_id\fP values for a particular device.
.SH REPORT FIELDS
The dmstats report provides several types of field that may be added to
the default field set, or used to create custom reports.
.br
All performance counters and metrics are calculated per-area.
.br
.SS Derived metrics
A number of metrics fields are included that provide high level
performance indicators. These are based on the fields provided by the
conventional Linux iostat program and are derived from the basic counter
values provided by the kernel for each area.
.br
.HP
.B rrqm
.br
Read requests merged per second.
.HP
.B wrqm
.br
Write requests merged per second.
.HP
.B rs
.br
Read requests per second.
.HP
.B ws
.br
Write requests per second.
.HP
.B rsec
.br
Sectors read per second.
.HP
.B wsec
.br
Sectors written per second.
.HP
.B arqsz
.br
The average size of requests submitted to the area.
.HP
.B qusz
.br
The average queue length.
.HP
.B await
.br
The average wait time for read and write requests.
.HP
.B r_await
.br
The average wait time for read requests.
.HP
.B w_await
.br
The average wait time for write requests.
.HP
.B tput
.br
The device throughput in requests per second.
.HP
.B svctm
.br
The average service time (in milliseconds) for I/O requests that
were issued to the device.
.HP
.B util
.br
Percentage of CPU time during which I/O requests were issued to the
device (bandwidth utilization for the device). Device saturation occurs
when this value is close to 100%.
.br
.SS Region and area meta fields
Meta fields provide information about the region or area that the
statistics values relate to. This includes the region and area
identifier, start, length, and counts, as well as the program ID and
auxiliary data values.
.br
.HP
.B region_id
.br
Region identifier. This is a non-negative integer returned by the kernel
when a statistics region is created.
.HP
.B region_start
.br
.br
The region start sector in units of 512 byte sectors.
.HP
.B region_len
.br
The length of the region in units of 512 byte sectors.
.HP
.B area_id
.br
Area identifier. Area identifiers are assigned by the device-mapper
statistics library and uniquely identify each area within a region. Each
ID corresponds to a distinct set of performance counters for that area
of the statistics region. Area identifiers are always monotonically
increasing within a region so that higher ID values correspond to
greater sector addresses within the region and no gaps in the sequence
of identifiers exist. Sorting a report by device, region start, and area
ID (the default) will then produce rows in order of ascending region and
area address.
.HP
.B area_start
.br
The area start sector in units of 512 byte sectors.
.HP
.B area_len
.br
The length of the area in units of 512 byte sectors.
.HP
.B area_count
.br
The number of areas in this region.
.HP
.B program_id
.br
The program ID value associated with this region.
.HP
.B aux_data
.br
The auxiliary data value associated with this region.
.br
.SS Basic counters
Basic counters provide access to the raw counter data from the kernel,
allowing further processing to be carried out by another program.
The kernel provides thirteen separate counters for each statistics
area. The first eleven of these match the counters provided in
/proc/diskstats or /sys/block/*/*/stat. The final pair provide separate
counters for read and write time.
.P
.HP
.B reads
.br
The number of reads successfully completed this interval.
.HP
.B read_merges
.br
The number of read requests merged this interval. This field is
incremented every time a pair of requests are merged to create a single
request to be issued to the device.
.HP
.B read_sectors
.br
The number of 512 byte sectors read this interval.
.HP
.B read_nsecs
.br
The number of nanoseconds spent reading during this interval.
.HP
.B writes
.br
The number of writes successfully completed this interval.
.HP
.B write_merges
.br
The number of write requests merged this interval. This field is
incremented every time a pair of requests are merged to create a single
request to be issued to the device.
.HP
.B write_sectors
.br
The number of 512 byte sectors written this interval.
.HP
.B write_nsecs
.br
The number of nanoseconds spent writing during this interval.
.HP
.B in_progress
.br
The number of reads and writes currently in progress.
.HP
.B io_nsecs
.br
The number of nanoseconds spent reading and writing.
.HP
.B weighted_io_nsecs
.br
This field is incremented at each I/O start, I/O completion, I/O merge,
or read of these stats by the number of I/Os in progress multiplied by
the number of milliseconds spent doing I/O since the last update of this
field. This can provide an easy measure of both I/O completion time and
the backlog that may be accumulating.
.br
.br
.P
.SH EXAMPLES
Create a whole-device region with one area on vg00/lvol1
.br
.br
# dmstats create vg00/lvol1
.br
Created region: 0
.br
.br
Create a 32M region 1G into device d0
.br
.br
# dmstats create --start 1G --length 32M d0
.br
Created region: 2
.br
Create a whole-device region with 8 areas on every device
.br
.br
# dmstats create --areas 8
.br
Created region: 0
.br
Created region: 0
.br
Created region: 0
.br
Created region: 2
.br
Created region: 0
.br
Created region: 0
.br
.br
Delete all regions on all devices
.br
.br
# dmstats delete --allregions --force
.br
.br
Create a whole-device region with areas 10GiB in size on vg00/lvol1
using dmsetup
.br
.br
# dmsetup stats create --areasize 10G vg00/lvol1
.br
Created region: 1
.br
.br
Create a 1GiB region with 16 areas at the start of vg00/lvol1
.br
# dmstats create --start 0 --len 1G --areas=16 vg00/lvol1
.br
Created region: 2
.br
.br
List the statistics regions registered on vg00/lvol1
.br
# dmstats list vg00/lvol1
.br
RegionID RegStart RegLen AreaSize ProgramID AuxData
.br
0 0 104857600 20971520 dmstats
.br
1 0 104857600 20971520 dmstats
.br
2 0 2097152 131072 dmstats
.br
.br
Display five statistics reports for vg00/lvol1 at an interval of one second
.br
.br
# dmstats report --interval 1 --count 5 vg00/lvol1
.br
Name RgID ArID RRqM/s WRqM/s R/s W/s RSz/s WSz/s AvRqSz QSize SvcTm Util% AWait
.br
vg00-lvol1 0 0 0.00 0.00 8.00 0.00 48.00k 0 6.00k 0.00 5.50 4.40 6.62
.br
vg00-lvol1 0 1 0.00 0.00 22.00 0.00 624.00k 0 28.00k 0.00 5.23 11.50 5.36
.br
vg00-lvol1 0 2 0.00 0.00 353.00 0.00 1.84m 0 5.00k 0.00 1.34 47.40 1.33
.br
vg00-lvol1 0 3 0.00 0.00 73.00 0.00 592.00k 0 8.00k 0.00 2.10 15.30 2.10
.br
vg00-lvol1 0 4 0.00 0.00 5.00 0.00 52.00k 0 10.00k 0.00 4.00 2.00 4.00
.br
[...]
.br
.br
Create one region for reach target contained in device vg00/lvol1
.br
.br
# dmstats create --segments vg00/lvol1
.br
Created region: 0
.br
Created region: 1
.br
Created region: 2
.br
.br
Print raw counters for region 4 on device d0
.br
.br
# dmstats print --regionid 4 d0
.br
2097152+65536 0 0 0 0 29 0 264 701 0 41 701 0 41
.br
.br
.SH AUTHORS
Bryn M. Reeves <bmr@redhat.com>
.SH SEE ALSO
LVM2 resource page https://www.sourceware.org/lvm2/
.br
Device-mapper resource page: http://sources.redhat.com/dm/
.br
Device-mapper statistics kernel documentation
.br
Documentation/device-mapper/statistics.txt

File diff suppressed because it is too large Load Diff