1.\" 2.\" Copyright (c) 1998, 1999, 2001 Kenneth D. Merry. 3.\" All rights reserved. 4.\" 5.\" Redistribution and use in source and binary forms, with or without 6.\" modification, are permitted provided that the following conditions 7.\" are met: 8.\" 1. Redistributions of source code must retain the above copyright 9.\" notice, this list of conditions and the following disclaimer. 10.\" 2. Redistributions in binary form must reproduce the above copyright 11.\" notice, this list of conditions and the following disclaimer in the 12.\" documentation and/or other materials provided with the distribution. 13.\" 3. The name of the author may not be used to endorse or promote products 14.\" derived from this software without specific prior written permission. 15.\" 16.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26.\" SUCH DAMAGE. 27.\" 28.Dd December 15, 2012 29.Dt DEVSTAT 3 30.Os 31.Sh NAME 32.Nm devstat , 33.Nm devstat_getnumdevs , 34.Nm devstat_getgeneration , 35.Nm devstat_getversion , 36.Nm devstat_checkversion , 37.Nm devstat_getdevs , 38.Nm devstat_selectdevs , 39.Nm devstat_buildmatch , 40.Nm devstat_compute_statistics , 41.Nm devstat_compute_etime 42.Nd device statistics utility library 43.Sh LIBRARY 44.Lb libdevstat 45.Sh SYNOPSIS 46.In devstat.h 47.Ft int 48.Fn devstat_getnumdevs "kvm_t *kd" 49.Ft long 50.Fn devstat_getgeneration "kvm_t *kd" 51.Ft int 52.Fn devstat_getversion "kvm_t *kd" 53.Ft int 54.Fn devstat_checkversion "kvm_t *kd" 55.Ft int 56.Fn devstat_getdevs "kvm_t *kd" "struct statinfo *stats" 57.Ft int 58.Fo devstat_selectdevs 59.Fa "struct device_selection **dev_select" 60.Fa "int *num_selected" 61.Fa "int *num_selections" 62.Fa "long *select_generation" 63.Fa "long current_generation" 64.Fa "struct devstat *devices" 65.Fa "int numdevs" 66.Fa "struct devstat_match *matches" 67.Fa "int num_matches" 68.Fa "char **dev_selections" 69.Fa "int num_dev_selections" 70.Fa "devstat_select_mode select_mode" 71.Fa "int maxshowdevs" 72.Fa "int perf_select" 73.Fc 74.Ft int 75.Fo devstat_buildmatch 76.Fa "char *match_str" 77.Fa "struct devstat_match **matches" 78.Fa "int *num_matches" 79.Fc 80.Ft int 81.Fo devstat_compute_statistics 82.Fa "struct devstat *current" 83.Fa "struct devstat *previous" 84.Fa "long double etime" 85.Fa "..." 86.Fc 87.Ft "long double" 88.Fo devstat_compute_etime 89.Fa "struct bintime *cur_time" 90.Fa "struct bintime *prev_time" 91.Fc 92.Sh DESCRIPTION 93The 94.Nm 95library is a library of helper functions for dealing with the kernel 96.Xr devstat 9 97interface, which is accessible to users via 98.Xr sysctl 3 99and 100.Xr kvm 3 . 101All functions that take a 102.Vt "kvm_t *" 103as first argument can be passed 104.Dv NULL 105instead of a kvm handle as this argument, 106which causes the data to be read via 107.Xr sysctl 3 . 108Otherwise, it is read via 109.Xr kvm 3 110using the supplied handle. 111The 112.Fn devstat_checkversion 113function 114should be called with each kvm handle that is going to be used (or with 115.Dv NULL 116if 117.Xr sysctl 3 118is going to be used). 119.Pp 120The 121.Fn devstat_getnumdevs 122function 123returns the number of devices registered with the 124.Nm 125subsystem in the kernel. 126.Pp 127The 128.Fn devstat_getgeneration 129function 130returns the current generation of the 131.Nm 132list of devices in the kernel. 133.Pp 134The 135.Fn devstat_getversion 136function 137returns the current kernel 138.Nm 139version. 140.Pp 141The 142.Fn devstat_checkversion 143function 144checks the userland 145.Nm 146version against the kernel 147.Nm 148version. 149If the two are identical, it returns zero. 150Otherwise, it prints an appropriate error in 151.Va devstat_errbuf 152and returns \-1. 153.Pp 154The 155.Fn devstat_getdevs 156function 157fetches the current list of devices and statistics into the supplied 158.Vt statinfo 159structure. 160The 161.Vt statinfo 162structure can be found in 163.In devstat.h : 164.Bd -literal -offset indent 165struct statinfo { 166 long cp_time[CPUSTATES]; 167 long tk_nin; 168 long tk_nout; 169 struct devinfo *dinfo; 170 long double snap_time; 171}; 172.Ed 173.Pp 174The 175.Fn devstat_getdevs 176function 177expects the 178.Vt statinfo 179structure to be allocated, and it also expects the 180.Va dinfo 181subelement to be allocated and zeroed prior to the first invocation of 182.Fn devstat_getdevs . 183The 184.Va dinfo 185subelement is used to store state between calls, and should not be modified 186after the first call to 187.Fn devstat_getdevs . 188The 189.Va dinfo 190subelement contains the following elements: 191.Bd -literal -offset indent 192struct devinfo { 193 struct devstat *devices; 194 uint8_t *mem_ptr; 195 long generation; 196 int numdevs; 197}; 198.Ed 199.Pp 200The 201.Va kern.devstat.all 202.Xr sysctl 8 203variable contains an array of 204.Nm 205structures, but at the head of the array is the current 206.Nm 207generation. 208The reason the generation is at the head of the buffer is so that userland 209software accessing the 210.Nm 211statistics information can atomically get 212both the statistics information and the corresponding generation number. 213If client software were forced to get the generation number via a separate 214.Xr sysctl 8 215variable (which is available for convenience), the list of devices could 216change between the time the client gets the generation and the time the 217client gets the device list. 218.Pp 219The 220.Va mem_ptr 221subelement of the 222.Vt devinfo 223structure is a pointer to memory that is allocated, and resized if 224necessary, by 225.Fn devstat_getdevs . 226The devices subelement of the 227.Vt devinfo 228structure is basically a pointer to the beginning of the array of devstat 229structures from the 230.Va kern.devstat.all 231.Xr sysctl 8 232variable (or the corresponding values read via 233.Xr kvm 3 ) . 234The generation subelement of the 235.Vt devinfo 236structure contains the corresponding generation number. 237The 238.Va numdevs 239subelement of the 240.Vt devinfo 241structure contains the current 242number of devices registered with the kernel 243.Nm 244subsystem. 245.Pp 246The 247.Fn devstat_selectdevs 248function 249selects devices to display based upon a number of criteria: 250.Bl -tag -width indent 251.It specified devices 252Specified devices are the first selection priority. 253These are generally devices specified by name by the user e.g.\& 254.Li da0 , da1 , cd0 . 255.It match patterns 256These are pattern matching expressions generated by 257.Fn devstat_buildmatch 258from user input. 259.It performance 260If performance mode is enabled, devices will be sorted based on the 261.Va bytes 262field in the 263.Vt device_selection 264structure passed in to 265.Fn devstat_selectdevs . 266The 267.Va bytes 268value currently must be maintained by the user. 269In the future, this may be done for him in a 270.Nm 271library routine. 272If no devices have been selected by name or by pattern, the performance 273tracking code will select every device in the system, and sort them by 274performance. 275If devices have been selected by name or pattern, the performance tracking 276code will honor those selections and will only sort among the selected 277devices. 278.It order in the devstat list 279If the selection mode is set to 280.Dv DS_SELECT_ADD , 281and if there are still less 282than 283.Fa maxshowdevs 284devices selected, 285.Fn devstat_selectdevs 286will automatically select up to 287.Fa maxshowdevs 288devices. 289.El 290.Pp 291The 292.Fn devstat_selectdevs 293function 294performs selections in four different modes: 295.Bl -tag -width ".Dv DS_SELECT_ADDONLY" 296.It Dv DS_SELECT_ADD 297In 298.Dq add 299mode, 300.Fn devstat_selectdevs 301will select any unselected devices specified by name or matching pattern. 302It will also select more devices, in devstat list order, until the number 303of selected devices is equal to 304.Fa maxshowdevs 305or until all devices are 306selected. 307.It Dv DS_SELECT_ONLY 308In 309.Dq only 310mode, 311.Fn devstat_selectdevs 312will clear all current selections, and will only select devices specified 313by name or by matching pattern. 314.It Dv DS_SELECT_REMOVE 315In 316.Dq remove 317mode, 318.Fn devstat_selectdevs 319will remove devices specified by name or by matching pattern. 320It will not select any additional devices. 321.It Dv DS_SELECT_ADDONLY 322In 323.Dq "add only" 324mode, 325.Fn devstat_selectdevs 326will select any unselected devices specified by name or matching pattern. 327In this respect it is identical to 328.Dq add 329mode. 330It will not, however, select any devices other than those specified. 331.El 332.Pp 333In all selection modes, 334.Fn devstat_selectdevs 335will not select any more than 336.Fa maxshowdevs 337devices. 338One exception to this is when you are in 339.Dq top 340mode and no devices have been selected. 341In this case, 342.Fn devstat_selectdevs 343will select every device in the system. 344Client programs must pay attention to selection order when deciding whether 345to pay attention to a particular device. 346This may be the wrong behavior, and probably requires additional thought. 347.Pp 348The 349.Fn devstat_selectdevs 350function 351handles allocation and resizing of the 352.Fa dev_select 353structure passed in 354by the client. 355The 356.Fn devstat_selectdevs 357function 358uses the 359.Fa numdevs 360and 361.Fa current_generation 362fields to track the 363current 364.Nm 365generation and number of devices. 366If 367.Fa num_selections 368is not the same 369as 370.Fa numdevs 371or if 372.Fa select_generation 373is not the same as 374.Fa current_generation , 375.Fn devstat_selectdevs 376will resize the selection list as necessary, and re-initialize the 377selection array. 378.Pp 379The 380.Fn devstat_buildmatch 381function 382takes a comma separated match string and compiles it into a 383.Vt devstat_match 384structure that is understood by 385.Fn devstat_selectdevs . 386Match strings have the following format: 387.Pp 388.D1 Ar device , Ns Ar type , Ns Ar if 389.Pp 390The 391.Fn devstat_buildmatch 392function 393takes care of allocating and reallocating the match list as necessary. 394Currently known match types include: 395.Bl -tag -width indent 396.It device type: 397.Bl -tag -width ".Li enclosure" -compact 398.It Li da 399Direct Access devices 400.It Li sa 401Sequential Access devices 402.It Li printer 403Printers 404.It Li proc 405Processor devices 406.It Li worm 407Write Once Read Multiple devices 408.It Li cd 409CD devices 410.It Li scanner 411Scanner devices 412.It Li optical 413Optical Memory devices 414.It Li changer 415Medium Changer devices 416.It Li comm 417Communication devices 418.It Li array 419Storage Array devices 420.It Li enclosure 421Enclosure Services devices 422.It Li floppy 423Floppy devices 424.El 425.It interface: 426.Bl -tag -width ".Li enclosure" -compact 427.It Li IDE 428Integrated Drive Electronics devices 429.It Li SCSI 430Small Computer System Interface devices 431.It Li NVME 432NVM Express Interface devices 433.It Li other 434Any other device interface 435.El 436.It passthrough: 437.Bl -tag -width ".Li enclosure" -compact 438.It Li pass 439Passthrough devices 440.El 441.El 442.Pp 443The 444.Fn devstat_compute_statistics 445function provides complete statistics calculation. 446There are four arguments for which values 447.Em must 448be supplied: 449.Fa current , 450.Fa previous , 451.Fa etime , 452and the terminating argument for the varargs list, 453.Dv DSM_NONE . 454For most applications, the user will want to supply valid 455.Vt devstat 456structures for both 457.Fa current 458and 459.Fa previous . 460In some instances, for instance when calculating statistics since system 461boot, the user may pass in a 462.Dv NULL 463pointer for the 464.Fa previous 465argument. 466In that case, 467.Fn devstat_compute_statistics 468will use the total stats in the 469.Fa current 470structure to calculate statistics over 471.Fa etime . 472For each statistics to be calculated, the user should supply the proper 473enumerated type (listed below), and a variable of the indicated type. 474All statistics are either integer values, for which a 475.Vt uint64_t 476is used, 477or floating point, for which a 478.Vt "long double" 479is used. 480The statistics that may be calculated are: 481.Bl -tag -width ".Dv DSM_TRANSFERS_PER_SECOND_OTHER" 482.It Dv DSM_NONE 483type: N/A 484.Pp 485This 486.Em must 487be the last argument passed to 488.Fn devstat_compute_statistics . 489It is an argument list terminator. 490.It Dv DSM_TOTAL_BYTES 491type: 492.Vt "uint64_t *" 493.Pp 494The total number of bytes transferred between the acquisition of 495.Fa previous 496and 497.Fa current . 498.It Dv DSM_TOTAL_BYTES_READ 499.It Dv DSM_TOTAL_BYTES_WRITE 500.It Dv DSM_TOTAL_BYTES_FREE 501type: 502.Vt "uint64_t *" 503.Pp 504The total number of bytes in transactions of the specified type 505between the acquisition of 506.Fa previous 507and 508.Fa current . 509.It Dv DSM_TOTAL_TRANSFERS 510type: 511.Vt "uint64_t *" 512.Pp 513The total number of transfers between the acquisition of 514.Fa previous 515and 516.Fa current . 517.It Dv DSM_TOTAL_TRANSFERS_OTHER 518.It Dv DSM_TOTAL_TRANSFERS_READ 519.It Dv DSM_TOTAL_TRANSFERS_WRITE 520.It Dv DSM_TOTAL_TRANSFERS_FREE 521type: 522.Vt "uint64_t *" 523.Pp 524The total number of transactions of the specified type between 525the acquisition of 526.Fa previous 527and 528.Fa current . 529.It Dv DSM_TOTAL_DURATION 530type: 531.Vt "long double *" 532.Pp 533The total duration of transactions, in seconds, between the acquisition of 534.Fa previous 535and 536.Fa current . 537.It Dv DSM_TOTAL_DURATION_OTHER 538.It Dv DSM_TOTAL_DURATION_READ 539.It Dv DSM_TOTAL_DURATION_WRITE 540.It Dv DSM_TOTAL_DURATION_FREE 541type: 542.Vt "long double *" 543.Pp 544The total duration of transactions of the specified type between 545the acquisition of 546.Fa previous 547and 548.Fa current . 549.It Dv DSM_TOTAL_BUSY_TIME 550type: 551.Vt "long double *" 552.Pp 553Total time the device had one or more transactions outstanding 554between the acquisition of 555.Fa previous 556and 557.Fa current . 558.It Dv DSM_TOTAL_BLOCKS 559type: 560.Vt "uint64_t *" 561.Pp 562The total number of blocks transferred between the acquisition of 563.Fa previous 564and 565.Fa current . 566This number is in terms of the blocksize reported by the device. 567If no blocksize has been reported (i.e., the block size is 0), a default 568blocksize of 512 bytes will be used in the calculation. 569.It Dv DSM_TOTAL_BLOCKS_READ 570.It Dv DSM_TOTAL_BLOCKS_WRITE 571.It Dv DSM_TOTAL_BLOCKS_FREE 572type: 573.Vt "uint64_t *" 574.Pp 575The total number of blocks of the specified type between the acquisition of 576.Fa previous 577and 578.Fa current . 579This number is in terms of the blocksize reported by the device. 580If no blocksize has been reported (i.e., the block size is 0), a default 581blocksize of 512 bytes will be used in the calculation. 582.It Dv DSM_KB_PER_TRANSFER 583type: 584.Vt "long double *" 585.Pp 586The average number of kilobytes per transfer between the acquisition of 587.Fa previous 588and 589.Fa current . 590.It Dv DSM_KB_PER_TRANSFER_READ 591.It Dv DSM_KB_PER_TRANSFER_WRITE 592.It Dv DSM_KB_PER_TRANSFER_FREE 593type: 594.Vt "long double *" 595.Pp 596The average number of kilobytes in the specified type transaction between 597the acquisition of 598.Fa previous 599and 600.Fa current . 601.It Dv DSM_TRANSFERS_PER_SECOND 602type: 603.Vt "long double *" 604.Pp 605The average number of transfers per second between the acquisition of 606.Fa previous 607and 608.Fa current . 609.It Dv DSM_TRANSFERS_PER_SECOND_OTHER 610.It Dv DSM_TRANSFERS_PER_SECOND_READ 611.It Dv DSM_TRANSFERS_PER_SECOND_WRITE 612.It Dv DSM_TRANSFERS_PER_SECOND_FREE 613type: 614.Vt "long double *" 615.Pp 616The average number of transactions of the specified type per second 617between the acquisition of 618.Fa previous 619and 620.Fa current . 621.It Dv DSM_MB_PER_SECOND 622type: 623.Vt "long double *" 624.Pp 625The average number of megabytes transferred per second between the 626acquisition of 627.Fa previous 628and 629.Fa current . 630.It Dv DSM_MB_PER_SECOND_READ 631.It Dv DSM_MB_PER_SECOND_WRITE 632.It Dv DSM_MB_PER_SECOND_FREE 633type: 634.Vt "long double *" 635.Pp 636The average number of megabytes per second in the specified type of 637transaction between the acquisition of 638.Fa previous 639and 640.Fa current . 641.It Dv DSM_BLOCKS_PER_SECOND 642type: 643.Vt "long double *" 644.Pp 645The average number of blocks transferred per second between the acquisition of 646.Fa previous 647and 648.Fa current . 649This number is in terms of the blocksize reported by the device. 650If no blocksize has been reported (i.e., the block size is 0), a default 651blocksize of 512 bytes will be used in the calculation. 652.It Dv DSM_BLOCKS_PER_SECOND_READ 653.It Dv DSM_BLOCKS_PER_SECOND_WRITE 654.It Dv DSM_BLOCKS_PER_SECOND_FREE 655type: 656.Vt "long double *" 657.Pp 658The average number of blocks per second in the specified type of transaction 659between the acquisition of 660.Fa previous 661and 662.Fa current . 663This number is in terms of the blocksize reported by the device. 664If no blocksize has been reported (i.e., the block size is 0), a default 665blocksize of 512 bytes will be used in the calculation. 666.It Dv DSM_MS_PER_TRANSACTION 667type: 668.Vt "long double *" 669.Pp 670The average duration of transactions between the acquisition of 671.Fa previous 672and 673.Fa current . 674.It Dv DSM_MS_PER_TRANSACTION_OTHER 675.It Dv DSM_MS_PER_TRANSACTION_READ 676.It Dv DSM_MS_PER_TRANSACTION_WRITE 677.It Dv DSM_MS_PER_TRANSACTION_FREE 678type: 679.Vt "long double *" 680.Pp 681The average duration of transactions of the specified type between the 682acquisition of 683.Fa previous 684and 685.Fa current . 686.It Dv DSM_BUSY_PCT 687type: 688.Vt "long double *" 689.Pp 690The percentage of time the device had one or more transactions outstanding 691between the acquisition of 692.Fa previous 693and 694.Fa current . 695.It Dv DSM_QUEUE_LENGTH 696type: 697.Vt "uint64_t *" 698.Pp 699The number of not yet completed transactions at the time when 700.Fa current 701was acquired. 702.It Dv DSM_SKIP 703type: N/A 704.Pp 705If you do not need a result from 706.Fn devstat_compute_statistics , 707just put 708.Dv DSM_SKIP 709as first (type) parameter and 710.Dv NULL 711as second parameter. 712This can be useful in scenarios where the statistics to be calculated 713are determined at run time. 714.El 715.Pp 716The 717.Fn devstat_compute_etime 718function 719provides an easy way to find the difference in seconds between two 720.Vt bintime 721structures. 722This is most commonly used in conjunction with the time recorded by the 723.Fn devstat_getdevs 724function (in 725.Vt "struct statinfo" ) 726each time it fetches the current 727.Nm 728list. 729.Sh RETURN VALUES 730The 731.Fn devstat_getnumdevs , 732.Fn devstat_getgeneration , 733and 734.Fn devstat_getversion 735function 736return the indicated sysctl variable, or \-1 if there is an error 737fetching the variable. 738.Pp 739The 740.Fn devstat_checkversion 741function 742returns 0 if the kernel and userland 743.Nm 744versions match. 745If they do not match, it returns \-1. 746.Pp 747The 748.Fn devstat_getdevs 749and 750.Fn devstat_selectdevs 751functions 752return \-1 in case of an error, 0 if there is no error, and 1 if the device 753list or selected devices have changed. 754A return value of 1 from 755.Fn devstat_getdevs 756is usually a hint to re-run 757.Fn devstat_selectdevs 758because the device list has changed. 759.Pp 760The 761.Fn devstat_buildmatch 762function returns \-1 for error, and 0 if there is no error. 763.Pp 764The 765.Fn devstat_compute_etime 766function 767returns the computed elapsed time. 768.Pp 769The 770.Fn devstat_compute_statistics 771function returns \-1 for error, and 0 for success. 772.Pp 773If an error is returned from one of the 774.Nm 775library functions, the reason for the error is generally printed in 776the global string 777.Va devstat_errbuf 778which is 779.Dv DEVSTAT_ERRBUF_SIZE 780characters long. 781.Sh SEE ALSO 782.Xr systat 1 , 783.Xr kvm 3 , 784.Xr sysctl 3 , 785.Xr iostat 8 , 786.Xr rpc.rstatd 8 , 787.Xr sysctl 8 , 788.Xr vmstat 8 , 789.Xr devstat 9 790.Sh HISTORY 791The 792.Nm 793statistics system first appeared in 794.Fx 3.0 . 795The new interface (the functions prefixed with 796.Li devstat_ ) 797first appeared in 798.Fx 5.0 . 799.Sh AUTHORS 800.An Kenneth Merry Aq Mt ken@FreeBSD.org 801.Sh BUGS 802There should probably be an interface to de-allocate memory allocated by 803.Fn devstat_getdevs , 804.Fn devstat_selectdevs , 805and 806.Fn devstat_buildmatch . 807.Pp 808The 809.Fn devstat_selectdevs 810function 811should probably not select more than 812.Fa maxshowdevs 813devices in 814.Dq top 815mode when no devices have been selected previously. 816.Pp 817There should probably be functions to perform the statistics buffer 818swapping that goes on in most of the clients of this library. 819.Pp 820The 821.Vt statinfo 822and 823.Vt devinfo 824structures should probably be cleaned up and thought out a little more. 825