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 other 432Any other device interface 433.El 434.It passthrough: 435.Bl -tag -width ".Li enclosure" -compact 436.It Li pass 437Passthrough devices 438.El 439.El 440.Pp 441The 442.Fn devstat_compute_statistics 443function provides complete statistics calculation. 444There are four arguments for which values 445.Em must 446be supplied: 447.Fa current , 448.Fa previous , 449.Fa etime , 450and the terminating argument for the varargs list, 451.Dv DSM_NONE . 452For most applications, the user will want to supply valid 453.Vt devstat 454structures for both 455.Fa current 456and 457.Fa previous . 458In some instances, for instance when calculating statistics since system 459boot, the user may pass in a 460.Dv NULL 461pointer for the 462.Fa previous 463argument. 464In that case, 465.Fn devstat_compute_statistics 466will use the total stats in the 467.Fa current 468structure to calculate statistics over 469.Fa etime . 470For each statistics to be calculated, the user should supply the proper 471enumerated type (listed below), and a variable of the indicated type. 472All statistics are either integer values, for which a 473.Vt uint64_t 474is used, 475or floating point, for which a 476.Vt "long double" 477is used. 478The statistics that may be calculated are: 479.Bl -tag -width ".Dv DSM_TRANSFERS_PER_SECOND_OTHER" 480.It Dv DSM_NONE 481type: N/A 482.Pp 483This 484.Em must 485be the last argument passed to 486.Fn devstat_compute_statistics . 487It is an argument list terminator. 488.It Dv DSM_TOTAL_BYTES 489type: 490.Vt "uint64_t *" 491.Pp 492The total number of bytes transferred between the acquisition of 493.Fa previous 494and 495.Fa current . 496.It Dv DSM_TOTAL_BYTES_READ 497.It Dv DSM_TOTAL_BYTES_WRITE 498.It Dv DSM_TOTAL_BYTES_FREE 499type: 500.Vt "uint64_t *" 501.Pp 502The total number of bytes in transactions of the specified type 503between the acquisition of 504.Fa previous 505and 506.Fa current . 507.It Dv DSM_TOTAL_TRANSFERS 508type: 509.Vt "uint64_t *" 510.Pp 511The total number of transfers between the acquisition of 512.Fa previous 513and 514.Fa current . 515.It Dv DSM_TOTAL_TRANSFERS_OTHER 516.It Dv DSM_TOTAL_TRANSFERS_READ 517.It Dv DSM_TOTAL_TRANSFERS_WRITE 518.It Dv DSM_TOTAL_TRANSFERS_FREE 519type: 520.Vt "uint64_t *" 521.Pp 522The total number of transactions of the specified type between 523the acquisition of 524.Fa previous 525and 526.Fa current . 527.It Dv DSM_TOTAL_DURATION 528type: 529.Vt "long double *" 530.Pp 531The total duration of transactions, in seconds, between the acquisition of 532.Fa previous 533and 534.Fa current . 535.It Dv DSM_TOTAL_DURATION_OTHER 536.It Dv DSM_TOTAL_DURATION_READ 537.It Dv DSM_TOTAL_DURATION_WRITE 538.It Dv DSM_TOTAL_DURATION_FREE 539type: 540.Vt "long double *" 541.Pp 542The total duration of transactions of the specified type between 543the acquisition of 544.Fa previous 545and 546.Fa current . 547.It Dv DSM_TOTAL_BUSY_TIME 548type: 549.Vt "long double *" 550.Pp 551Total time the device had one or more transactions outstanding 552between the acquisition of 553.Fa previous 554and 555.Fa current . 556.It Dv DSM_TOTAL_BLOCKS 557type: 558.Vt "uint64_t *" 559.Pp 560The total number of blocks transferred between the acquisition of 561.Fa previous 562and 563.Fa current . 564This number is in terms of the blocksize reported by the device. 565If no blocksize has been reported (i.e., the block size is 0), a default 566blocksize of 512 bytes will be used in the calculation. 567.It Dv DSM_TOTAL_BLOCKS_READ 568.It Dv DSM_TOTAL_BLOCKS_WRITE 569.It Dv DSM_TOTAL_BLOCKS_FREE 570type: 571.Vt "uint64_t *" 572.Pp 573The total number of blocks of the specified type between the acquisition of 574.Fa previous 575and 576.Fa current . 577This number is in terms of the blocksize reported by the device. 578If no blocksize has been reported (i.e., the block size is 0), a default 579blocksize of 512 bytes will be used in the calculation. 580.It Dv DSM_KB_PER_TRANSFER 581type: 582.Vt "long double *" 583.Pp 584The average number of kilobytes per transfer between the acquisition of 585.Fa previous 586and 587.Fa current . 588.It Dv DSM_KB_PER_TRANSFER_READ 589.It Dv DSM_KB_PER_TRANSFER_WRITE 590.It Dv DSM_KB_PER_TRANSFER_FREE 591type: 592.Vt "long double *" 593.Pp 594The average number of kilobytes in the specified type transaction between 595the acquisition of 596.Fa previous 597and 598.Fa current . 599.It Dv DSM_TRANSFERS_PER_SECOND 600type: 601.Vt "long double *" 602.Pp 603The average number of transfers per second between the acquisition of 604.Fa previous 605and 606.Fa current . 607.It Dv DSM_TRANSFERS_PER_SECOND_OTHER 608.It Dv DSM_TRANSFERS_PER_SECOND_READ 609.It Dv DSM_TRANSFERS_PER_SECOND_WRITE 610.It Dv DSM_TRANSFERS_PER_SECOND_FREE 611type: 612.Vt "long double *" 613.Pp 614The average number of transactions of the specified type per second 615between the acquisition of 616.Fa previous 617and 618.Fa current . 619.It Dv DSM_MB_PER_SECOND 620type: 621.Vt "long double *" 622.Pp 623The average number of megabytes transferred per second between the 624acquisition of 625.Fa previous 626and 627.Fa current . 628.It Dv DSM_MB_PER_SECOND_READ 629.It Dv DSM_MB_PER_SECOND_WRITE 630.It Dv DSM_MB_PER_SECOND_FREE 631type: 632.Vt "long double *" 633.Pp 634The average number of megabytes per second in the specified type of 635transaction between the acquisition of 636.Fa previous 637and 638.Fa current . 639.It Dv DSM_BLOCKS_PER_SECOND 640type: 641.Vt "long double *" 642.Pp 643The average number of blocks transferred per second between the acquisition of 644.Fa previous 645and 646.Fa current . 647This number is in terms of the blocksize reported by the device. 648If no blocksize has been reported (i.e., the block size is 0), a default 649blocksize of 512 bytes will be used in the calculation. 650.It Dv DSM_BLOCKS_PER_SECOND_READ 651.It Dv DSM_BLOCKS_PER_SECOND_WRITE 652.It Dv DSM_BLOCKS_PER_SECOND_FREE 653type: 654.Vt "long double *" 655.Pp 656The average number of blocks per second in the specified type of transaction 657between the acquisition of 658.Fa previous 659and 660.Fa current . 661This number is in terms of the blocksize reported by the device. 662If no blocksize has been reported (i.e., the block size is 0), a default 663blocksize of 512 bytes will be used in the calculation. 664.It Dv DSM_MS_PER_TRANSACTION 665type: 666.Vt "long double *" 667.Pp 668The average duration of transactions between the acquisition of 669.Fa previous 670and 671.Fa current . 672.It Dv DSM_MS_PER_TRANSACTION_OTHER 673.It Dv DSM_MS_PER_TRANSACTION_READ 674.It Dv DSM_MS_PER_TRANSACTION_WRITE 675.It Dv DSM_MS_PER_TRANSACTION_FREE 676type: 677.Vt "long double *" 678.Pp 679The average duration of transactions of the specified type between the 680acquisition of 681.Fa previous 682and 683.Fa current . 684.It Dv DSM_BUSY_PCT 685type: 686.Vt "long double *" 687.Pp 688The percentage of time the device had one or more transactions outstanding 689between the acquisition of 690.Fa previous 691and 692.Fa current . 693.It Dv DSM_QUEUE_LENGTH 694type: 695.Vt "uint64_t *" 696.Pp 697The number of not yet completed transactions at the time when 698.Fa current 699was acquired. 700.It Dv DSM_SKIP 701type: N/A 702.Pp 703If you do not need a result from 704.Fn devstat_compute_statistics , 705just put 706.Dv DSM_SKIP 707as first (type) parameter and 708.Dv NULL 709as second parameter. 710This can be useful in scenarios where the statistics to be calculated 711are determined at run time. 712.El 713.Pp 714The 715.Fn devstat_compute_etime 716function 717provides an easy way to find the difference in seconds between two 718.Vt bintime 719structures. 720This is most commonly used in conjunction with the time recorded by the 721.Fn devstat_getdevs 722function (in 723.Vt "struct statinfo" ) 724each time it fetches the current 725.Nm 726list. 727.Sh RETURN VALUES 728The 729.Fn devstat_getnumdevs , 730.Fn devstat_getgeneration , 731and 732.Fn devstat_getversion 733function 734return the indicated sysctl variable, or \-1 if there is an error 735fetching the variable. 736.Pp 737The 738.Fn devstat_checkversion 739function 740returns 0 if the kernel and userland 741.Nm 742versions match. 743If they do not match, it returns \-1. 744.Pp 745The 746.Fn devstat_getdevs 747and 748.Fn devstat_selectdevs 749functions 750return \-1 in case of an error, 0 if there is no error, and 1 if the device 751list or selected devices have changed. 752A return value of 1 from 753.Fn devstat_getdevs 754is usually a hint to re-run 755.Fn devstat_selectdevs 756because the device list has changed. 757.Pp 758The 759.Fn devstat_buildmatch 760function returns \-1 for error, and 0 if there is no error. 761.Pp 762The 763.Fn devstat_compute_etime 764function 765returns the computed elapsed time. 766.Pp 767The 768.Fn devstat_compute_statistics 769function returns \-1 for error, and 0 for success. 770.Pp 771If an error is returned from one of the 772.Nm 773library functions, the reason for the error is generally printed in 774the global string 775.Va devstat_errbuf 776which is 777.Dv DEVSTAT_ERRBUF_SIZE 778characters long. 779.Sh SEE ALSO 780.Xr systat 1 , 781.Xr kvm 3 , 782.Xr sysctl 3 , 783.Xr iostat 8 , 784.Xr rpc.rstatd 8 , 785.Xr sysctl 8 , 786.Xr vmstat 8 , 787.Xr devstat 9 788.Sh HISTORY 789The 790.Nm 791statistics system first appeared in 792.Fx 3.0 . 793The new interface (the functions prefixed with 794.Li devstat_ ) 795first appeared in 796.Fx 5.0 . 797.Sh AUTHORS 798.An Kenneth Merry Aq Mt ken@FreeBSD.org 799.Sh BUGS 800There should probably be an interface to de-allocate memory allocated by 801.Fn devstat_getdevs , 802.Fn devstat_selectdevs , 803and 804.Fn devstat_buildmatch . 805.Pp 806The 807.Fn devstat_selectdevs 808function 809should probably not select more than 810.Fa maxshowdevs 811devices in 812.Dq top 813mode when no devices have been selected previously. 814.Pp 815There should probably be functions to perform the statistics buffer 816swapping that goes on in most of the clients of this library. 817.Pp 818The 819.Vt statinfo 820and 821.Vt devinfo 822structures should probably be cleaned up and thought out a little more. 823