kstat2(3kstat2) 맨 페이지 - 윈디하나의 솔라나라

개요

섹션
맨 페이지 이름
검색(S)

kstat2(3kstat2)

Kernel Statistics Library Functions, Version 2                 kstat2(3KSTAT2)



NAME
       kstat2 - kernel statistics facility, version 2

DESCRIPTION
       The kstat2 facility is a general-purpose mechanism for providing kernel
       statistics to users.

   The kstat2 Model
       The kernel maintains a collection of statistics structures, or  kstats.
       Access  to  the statistics is through the libkstat2 shared library. The
       majority of accesses are made through opaque handles, with data  values
       being accessed through read-only structures.

   kstat2 Status Codes
       All  kstat2 API functions return a status code which is a member of the
       kstat2_status_t enumeration. The value,  KSTAT2_S_OK,  is  returned  on
       success,  with other values being returned on error. A string represen‐
       tation of the error can be  obtained  from  the  kstat2_status_string()
       function.

   Returned Values
       As the kstat2 API functions use the return
                           value()  function  for  status and information, any
       values that the API needs to return requires an address of  a  variable
       to  be  supplied  for  the value to be placed in. If there is an error,
       this variable will be left unchanged. All input and  output  parameters
       are  checked  for  NULL,  with  an  error  being  returned if necessary
       (KSTAT2_S_INVAL_ARG).

   Data Representation
       The primary data type in kstat2 is a (key, value) map, where values  in
       the  map  can be integers, lists of integers, strings, lists of strings
       or sub-maps. The kstats are identified by a URI, where each  successive
       path  component  of the URI corresponds to a sub-level of map. Maps may
       be iterated over and items retrieved. Values are returned as  read-only
       C  structures  containing  the map item key and value. Application pro‐
       vided values may also be stored in the maps.

   Data Retrieval and Updates
       When a kstat2 handle is opened, the set of currently  available  kstats
       is  retrieved from Oracle Solaris and is used to populate the map tree,
       but no  actual  data  values  are  retrieved  at  that  point.  Calling
       kstat2_update()  function  will  re-synchronise  the  map tree with the
       kstats currently held by the OS, adding and deleting  items  as  neces‐
       sary.


       Data values are only retrieved when a leaf kstat map is first accessed,
       at which point all the data values within the map kstat  are  retrieved
       and  stored.  Subsequent accesses to values in the map will not trigger
       re-reading from the kernel, so the values will  remain  consistent.  In
       order  to  trigger  re-reading  of  the  values  from  Oracle  Solaris,
       kstat2_update() function must be called. Data values will then  be  re-
       read on the next access to any map value.

   Using the kstat2 API
   Accessing the API
       Programs  that  want  to  use the kstat2 API need to include the header
       file kstat2.h and link against the library libkstat2.

   Obtaining a kstat Handle
       This first step to using the API is to obtain a new kstat v2 handle.

       Example 1 Obtaining a New kstat v2 Handle



                 kstat2_status_t stat;
                 kstat2_handle_t handle;
                 stat = kstat2_open(&handle, NULL);
                 if (stat != KSTAT2_S_OK) {
                     (void) printf("can't open kstats: %s\n",
                       kstat2_status_string(stat));
                     exit(1);
                 }



   Filtering kstats
       If an application is only interested in a small number  of  statistics,
       it  can  open  a specific view on the kstat tree by supplying a matcher
       list to the kstat2_open() function to match  those  particular  kstats.
       Only  kstats  that  match one or more matchers will be available in the
       kstat session. Restricting the number of kstats that are available will
       improve  performance  and reduce the memory footprint of the kstat ses‐
       sion.

       Example 2 Obtaining a New kstat v2 Handle Using Matchers



         kstat2_status_t stat;
         kstat2_matcher_list_t matchers;
         kstat2_handle_t handle;
         stat = kstat2_alloc_matcher_list(&matchers);
         if (stat != KSTAT2_S_OK) {
                 (void) printf("can't create kstat matcher list: %s\n",
                     kstat2_status_string(stat));
                 exit(1);
         }

         /* We only care about CPU statistics */
         stat = kstat2_add_matcher(KSTAT2_M_GLOB,
             "kstat:/system/cpu/*", matchers);
         if (stat != KSTAT2_S_OK) {
                 (void) printf("can't create kstat matcher: %s\n",
                     kstat2_status_string(stat));
                 exit(1);
         }

         stat = kstat2_open(&handle, matchers);
         if (stat != KSTAT2_S_OK) {
             (void) printf("can't open kstats: %s\n",
                 kstat2_status_string(stat));
             exit(1);
         }



   Obtaining a Reference to a Map and Accessing its Values
       If you know the map that contains the data values you wish to retrieve,
       you   must  first  retrieve  the  map  by  providing  its  URI  to  the
       kstat2_lookup_map() function. Once you  have  the  map,  you  can  then
       extract  the  values  you  are interested by using the kstat2_map_get()
       function. The values are returned in a C structure where all  the  mem‐
       bers are const. The values should not be modified as doing so will cor‐
       rupt the internal state of the library. The structure contains the name
       and  value,  as a union. The type field discriminates between the union
       members, and will be one of the following five types:

           o      KSTAT2_NVVT_MAP - nested Name/Value map


           o      KSTAT2_NVVT_INT - 64-bit unsigned integer


           o      KSTAT2_NVVT_INTS - array of 64-bit unsigned integers


           o      KSTAT2_NVVT_STR - null-terminated C string


           o      KSTAT2_NVVT_STRS - array of null-terminated C strings



       In addition, the kstat2_nv_t structure contains  a  kind  field,  which
       distinguishes  between  kernel  provided values (KSTAT2_NVK_SYS), user-
       added values (KSTAT2_NVK_USR), and sub-map values (KSTAT2_NVK_MAP).  It
       also contains a flags field with the following possible values:

           o      KSTAT2_NVVF_INVAL - the value is currently invalid



       The structure used to hold name/value pairs is as follows.


                 typedef struct kstat2_nv {
                     const char *const name; /* Name of the pair */
                     const uint8_t type;     /* Value type of the pair */
                     const uint8_t kind;     /* Kind of the pair */
                     const uint16_t flags    /* Flags of the pair */
                     union {                 /* Data value of the pair */
                         const kstat2_map_t const map;
                         const uint64_t integer;
                         struct {
                             const uint64_t *const array;
                             const uint32_t length;
                         } integers;
                         const char *const string;
                         struct {
                             const char *const *const array;
                             const uint32_t length;
                         } strings;
                     } data;
                 } *kstat2_nv_t;


       Example 3 Map Lookup and Value Display



                 kstat2_map_t map;
                 stat = kstat2_lookup_map(handle,
                     "kstat:/system/cpu/2/sys", &map);
                 if (stat != KSTAT2_S_OK) {
                         (void) printf("can't lookup kstat: %s\n",
                 kstat2_status_string(stat));
                         exit(1);
                 }
                 kstat2_nv_t val;
                 stat = kstat2_map_get(map, "cpu_ticks_idle", &val);
                 if (stat != KSTAT2_S_OK) {
                         (void) printf("can't get value: %s\n",
                 kstat2_status_string(stat));
                         exit(1);
                 }
                 const char *const *sp;
                 const uint64_t *ip;
                 switch (val->type) {
                 case KSTAT2_NVVT_MAP:
                         (void) printf("unexpected submap\n");
                         break;
                 case KSTAT2_NVVT_INT:
                         (void) printf("%s = %llu\n", val->name, val->kstat2_integer);
                         break;
                 case KSTAT2_NVVT_INTS:
                         (void) printf("%s = ", val->name);
                         for (uint32_t i = 0, ip = val->kstat2_integers.array;
                             i < val->kstat2_integers.length;
                             i++, ip++) {
                                 if (i > 0) {
                                         (void) printf(",");
                                 }
                                 (void) printf("%llu\n", *ip);
                         }
                         (void) printf("\n");
                         break;
                 case KSTAT2_NVVT_STR:
                         (void) printf("%s = %s\n", val->name, val->kstat2_string);
                         break;
                 case KSTAT2_NVVT_STRS:
                         (void) printf("%s = ", val->name);
                         for (uint32_t i = 0, sp = val->kstat2_strings.array;
                             i < val->kstat2_strings.length;
                             i++, sp++) {
                                 if (i > 0) {
                                         (void) printf(",");
                                 }
                                 (void) printf("%s\n", *sp);
                         }
                         (void) printf("\n");
                         break;
                 default:
                         (void) printf("unexpected type\n");
                         exit(1);
                 }



   Obtaining the URI for a Map
       Given  a reference to a map, the URI string representing the map can be
       obtained with the #kstat2_map_uri() function. After use,  the  returned
       value should be disposed of with a call to free(3C).

       Example 4 Obtaining the URI for a Map



                 char *uri;
                 stat = kstat2_map_uri(map, &uri);
                 if (stat != KSTAT2_S_OK) {
                     (void) printf("can't get map name: %s\n",
                       kstat2_status_string(stat));
                     exit(1);
                 } else {
                     (void) printf("map URI is %s\n", uri);
                     free(uri);
                 }



   URI Encoding and Decoding
       Any URI-unsafe characters need to be escaped and unescaped when manipu‐
       lating  kstat  URIs.  The  utility  functions  kstat2_uri_encode()  and
       kstat2_uri_decode()  can  be used to do that. Note that these functions
       can only be used on individual components  of  a  kstat  URI,  not  the
       entire  URI.  After use the returned encoded or unencoded string should
       be disposed of with a call to free(3C).

       Example 5 URI Encoding and Decoding



                 char *enc, *unenc;
                 if (kstat2_uri_encode("foo=bar", &enc) == KSTAT2_S_OK) {
                     /* Do something with the encoded value */
                     free(enc);
                 }
                 if (kstat2_uri_decode("foo%3Dbar", &unenc) == KSTAT2_S_OK) {
                     /* Do something with the unencoded value */
                     free(unenc);
                 }



   Finding the Number of Elements in a Map
       Maps can contain three types of values, those holding kernel kstat val‐
       ues   (KSTAT2_NVK_SYS),   those   holding   application-defined  values
       (KSTAT2_NVK_USR, see "User-Defined Map  Values"  below),  and  sub-maps
       (KSTAT2_NVK_MAP).  The number of values of the different types in a map
       can be queried by ORing together with the required KSTAT2_NVK_*  flags,
       or the total number of entries can be queried by using KSTAT2_NVK_ALL.

       Example 6 Finding the Number of Elements in a Map



         uint32_t size;
         stat = kstat2_map_size(map, KSTAT2_NVK_ALL, &size);



   Kstat Metadata
       Metadata  is  stored  at  two levels, both on the kstat maps and in the
       individual name/value pairs within the maps. Map level metadata can  be
       retrieved  by  calling  the  kstat2_map_meta() function, passing in the
       address of a kstat2_map_meta_t structure into which the  metadata  will
       be copied. An example is as follows:


                 kstat2_map_t map = ...
                 kstat2_map_meta_t map_meta;
                 stat = kstat2_map_meta(map, &map_meta);



       The   map   level  metadata  which  is  available  is  defined  in  the
       kstat2_map_meta_t structure:


                 typedef struct kstat2_map_meta {
                     const uint16_t type;     /* Metadata type value */
                     const uint32_t flags;    /* Metadata flag values */
                     const char *const desc;  /* Descriptive string */
                 } *kstat2_map_meta_t;



       Within that structure, the type field identifies the  kstat  type,  for
       example,  an  IO kstat and the flags field holds a set of flags for the
       kstat. desc is a human readable description of the kstat, and  will  be
       NULL if no description is available.


       kstat2_metatype_t  and kstat2_metaflag_t define the possible values for
       the type and flags fields respectively.


                 typedef enum kstat2_metatype {
                     KSTAT2_MT_NONE,     /* Kstat data has no specific type
                     KSTAT2_MT_QUEUE,    /* Queue data */
                     KSTAT2_MT_IO,       /* IO data */
                     KSTAT2_MT_INTR,     /* Interrupt data */
                     KSTAT2_MT_TIMER,    /* Timer data */
                     KSTAT2_MT_HIST      /* Histogram data */
                 } kstat2_metatype_t;



       The type field is used to indicate that all kstats of a given type will
       contain  the  same  set of name or values, for example, those needed to
       describe an IO queue. This enables applications to discern the type and
       purpose  of  a kstat without examining each individual name or value in
       the kstat.


                 typedef enum kstat2_metaflag {
                     KSTAT2_MF_NONE   = 0x00, /* No metaflags are set */
                     KSTAT2_MF_STABLE = 0x01  /* Kstat is stable across releases */
                     KSTAT2_MF_PRIV   = 0x02  /* Kstat can only be read with privileged access */
         } kstat2_metaflag_t;



       Name or value metadata can be retrieved by calling the kstat2_nv_meta()
       function,  passing in the map containing the name or value, the name of
       the name or value pair and the address of a kstat2_nv_meta_t  structure
       into which the metadata will be copied. An example is as follows:


                 kstat2_map_t map = ...
                 kstat2_nv_meta_t nv_meta;
                 stat = kstat2_nv_meta(map, "cpu_ticks_idle", &map_meta);



       The name/value-level metadata which is available is:


                 typedef struct kstat2_nv_meta {
                     const uint16_t type;     /* Metadata type value */
                     const uint32_t flags;    /* Metadata flag values */
                     const uint64_t units;    /* Value units */
                     const char *const desc;  /* Descriptive string */
                 } *kstat2_nv_meta_t;



       Within  that  structure,  the  type  field identifies the name or value
       type, for example, a count and the flags field holds a set of flags for
       the  name/value.  units hold the units of the associated numeric value,
       for example, 512 for a count of 0.5 Kbyte disk blocks.  The  associated
       KSTAT2_NVMF_FRACT flag in the flags field specifies how the units field
       should be interpreted. If KSTAT2_NVMF_FRACT is unset then  units  is  a
       multiplier  (for  example,  disk  IO size), if KSTAT2_NVMF_FRACT is set
       then units is a divisor (for example 10^9 for  nanoseconds).  An  units
       value  of  0  is  invalid.  desc is a human readable description of the
       name/value pair, and will be NULL if no description is available.


       kstat2_nv_metatype_t and kstat2_nv_metaflag_t define the possible  val‐
       ues for the type and flags fields respectively:


                 typedef enum kstat2_nv_metatype {
                     KSTAT2_NVMT_UNK,      /* Unknown type */
                     KSTAT2_NVMT_CNT,      /* Count, e.g. packets, disk blocks */
                     KSTAT2_NVMT_T_EPOCH,  /* Time since UNIX epoch */
                     KSTAT2_NVMT_T_REL,    /* Time relative to boot */
                     KSTAT2_NVMT_T_ACC,    /* Accumulated time since boot */
                     KSTAT2_NVMT_PCT,      /* Percentage, 0-100 */
                     KSTAT2_NVMT_ADDR,     /* Memory address */
                     KSTAT2_NVMT_TEMP_C,   /* Temperature in centigrade */
                     KSTAT2_NVMT_RPM,      /* Revolutions per minute */
                     KSTAT2_NVMT_VOLT,     /* Voltage */
                     KSTAT2_NVMT_WATT,     /* Power consumption */
                     KSTAT2_NVMT_CURR,     /* Current */
                     KSTAT2_NVMT_BYTES,    /* Byte count */
                     KSTAT2_NVMT_BITS,     /* Bit count */
                     KSTAT2_NVMT_ID,       /* Identifier, e.g. CPU type, CPU chip id */
                     KSTAT2_NVMT_STATE,    /* State, e.g. CPU state */
                     KSTAT2_NVMT_FREQ,     /* Frequency (Hz) */
                     KSTAT2_NVMT_FLAGS     /* Bitwise flags */
                 } kstat2_nv_metatype_t;


                 typedef enum kstat2_nv_metaflag {
                     KSTAT2_NVMF_NONE   = 0x00,  /* No metaflags are set */
                     KSTAT2_NVMF_FRACT  = 0x01,  /* Units is a divisor */
                     KSTAT2_NVMF_IMMUT  = 0x02,  /* Value is immutable */
                     KSTAT2_NVMF_STABLE = 0x04,   /* Kval is stable across releases */
                     KSTAT2_NVMF_LIMIT  = 0x08   /* Kval represents limit(s) */
                 } kstat2_nv_metaflag_t;


   Kstat and kval Stability
       If   a   kstat  has  the  KSTAT_NMF_STABLE  flag  or  a  kval  has  the
       KSTAT2_NVMF_STABLE flag set, it indicates that the  kstat  or  name  or
       value will be stable across Oracle Solaris releases. That does not pre‐
       clude the kstat or name or value ever being removed, but  such  removal
       will  be  preceded by a notification and obsolescence period. Kstats or
       names or values that do not have the flag set may be removed any  time,
       and their existence should not be relied on.

   Iterating Over Maps and Values
       As  well  as accessing individual map values, it is possible to iterate
       over all the values in a map. If a full traversal of the kstat tree  is
       required,   the   topmost   map   can   be   obtained   by  a  call  to
       kstat2_lookup_map() using the root kstat URI of "kstat:/". If the  tra‐
       versal  is  only  part  of the map, the URL of the relevant subtree can
       used. Having obtained a reference to a map, the next step is to  create
       an iterator for it. An example is as follows:


                 kstat2_map_t map;
                 stat = kstat2_lookup_map(handle, "kstat:/", &map);
                 if (stat != KSTAT2_S_OK) {
                     (void) printf("can't retrieve map: %s\n"),
                       kstat2_status_string(stat));
                     exit(1);
                 }
                 kstat2_mapiter_t iter;
                 stat = kstat2_mapiter_start(map, &iter);
                 if (stat != KSTAT2_S_OK) {
                     (void) printf("can't create iterator: %s\n"),
                       kstat2_status_string(stat));
                     exit(1);
                 }



       Once  an iterator has been obtained, it can be used to iterate over the
       map. Note that the contents of the map are not returned in any particu‐
       lar  order. If no changes are made to the map, both successive and con‐
       current iterations over the map will return  the  values  in  the  same
       order. An example is as follows:


                 kstat2_map_t map;
                 stat = kstat2_lookup_map(handle, "kstat:/", &map);
                 if (stat != KSTAT2_S_OK) {
                     (void) printf("can't retrieve map: %s\n",
                 kstat2_status_string(stat));
                     exit(1);
                 }
                 kstat2_mapiter_t iter;
                 stat = kstat2_mapiter_start(map, KSTAT2_NVK_USR, &iter);
                 if (stat != KSTAT2_S_OK) {
                     (void) printf("can't create iterator: %s\n",
                 kstat2_status_string(stat));
                     exit(1);
                 }



       The second parameter to kstat2_mapiter_start() function specifies which
       type of values should be iterated over and should be an  ORed  combina‐
       tion  of  the  required types. The iterator is to return KSTAT2_NVK_SYS
       for  kernel  kstat  values,  KSTAT2_NVK_USR  for   user-added   values,
       KSTAT2_NVK_MAP  for  sub-maps,  or  KSTAT2_NVK_ALL  to iterate over all
       three types of values at the same time.


       Whilst iterating over the map  the  current  item  can  be  deleted  if
       required,  provided  it  is  an  user-added  value (KSTAT2_NVK_USR, see
       "User-defined Map Values" section below for  details).  An  example  is
       follows:


                 boolean_t has_next;
                 int matched = 0;
                 while (kstat2_mapiter_hasnext(iter, &has_next) == KSTAT2_S_OK
                   && has_next) {
                     kstat2_nv_t val;
                     (void) kstat2_mapiter_next(iter, &val);
                     if (need_to_delete(val)) {
                         (void) kstat2_mapiter_remove(iter);
                     }
                 }
                 (void) kstat2_mapiter_end(&iter);



       Note  that  it  is safe to have multiple iterators open on a map at any
       one time, provided no changes are made to the map, either  directly  or
       through  an  iterator.  If  the  map  is  modified, subsequent accesses
       through a different iterator will fail  returning  a  KSTAT2_S_CONC_MOD
       error.  Once this error occurs, any affected iterators should be closed
       with kstat2_mapiter_end() function.

       Note -




         A call to kstat2_update() will invalidate any open iterators. So, all
         iterators must be closed with kstat2_mapiter_end() before calling the
         kstat2_update() function.



   Obtaining the URI for a Map Element
       Given a reference to a map and the name of an element in the  map,  the
       URI  string  representing  the  map  element  can  be obtained with the
       kstat2_nv_uri() function. After use, the returned value should be  dis‐
       posed of with a call to free(3C). An example is as follows:


                 char *uri;
                 stat = kstat2_nv_uri(map, "some_element", &uri);
                 if (stat != KSTAT2_S_OK) {
                     (void) printf("can't get nv name: %s\n",
                 kstat2_status_string(stat));
                     exit(1);
                 } else {
                     (void) printf("nv URI is %s\n", uri);
                     free(uri);
                 }


   Obtaining all the Values in a Map
       Sometimes it may be necessary to obtain all of the values in a map, for
       example, to sort them alphabetically  before  displaying  them.  Rather
       than having to iterate over the map, the kstat2_map_to_array() function
       is provided to return all the values in the map as an array. This array
       may  be pre-allocated with malloc(3C) or can optionally be allocated by
       the API. After use, the array should be freed to prevent a memory leak.
       An example is as follows:


                 kstat2_status_t stat;
                 kstat2_nv_t *ary = NULL;
                 uint32_t size = 0;
                 uint32_t ent = 0;
                 stat = kstat2_map_to_array(map, KSTAT2_NVK_SYS, &ary, &size, &ent);
                 if (stat != KSTAT2_S_OK) {
                     exit(1);
                 }
                 qsort(ary, ent, sizeof (kstat2_nv_t *), &nv_strcmp);
                 for (kstat2_nv_t *val = ary; ent > 0; val++, ent--) {
                     print_entry(*val);
                 }
                 free(ary);



       The  second  parameter  of  KSTAT2_NVK_SYS specifies that in this case,
       only kernel values are to be copied into the supplied array.

   Updating the kstat Data
       Most kstat consumers operate in a loop, fetching and  displaying  kstat
       values  before  waiting  for a period, re-sampling the data and looping
       round.  In  order  to  trigger  an  update  of  the  kstat  data,   the
       kstat2_update()  function  should  be  called. This re-synchronises the
       kstat map tree with the kstats available from Oracle Solaris and  marks
       the  leaf maps so that their data will be re-read from the OS when they
       are next accessed. See the "Data Retrieval and Updates"  section  above
       for more details. An example is as follows:


                 (void) sleep(interval);
                 stat = kstat2_update(handle);
                 if (stat != KSTAT2_S_OK) {
                     (void) printf"can't update kstats: %s\n",
                       kstat2_status_string(stat));
                     exit(1);
                 }



       Note that all data updates are in place, so if the application has ref‐
       erences to either maps or name/value pairs, those data  items  will  be
       updated by a call to kstat2_update() function. If the application needs
       to store values across calls to kstat2_update() (for example, for  cal‐
       culating  deltas  between  updates) it needs to copy those values else‐
       where, either into an application managed storage or by storing them in
       user-defined  map  values,  see "User-defined Map Values" section below
       for more details of that facility.

       Note -




         Re-synchronising the kstat map tree with the  kstats  available  from
         the  kernel  through  the kstat2_update() function does NOT guarantee
         that all the kstats in the tree  will  be  available  for  subsequent
         reading.  The kstat2_update() function takes a snapshot of the kstats
         in the kernel and between that snapshot and a subsequent access  (for
         example,  through  kstat2_lookup_map()) it is possible that the kstat
         may be deleted by the kernel. Applications must therefore be coded in
         a  manner that allows for kstat lookup operations to fail. However, a
         kstat is read atomically, so once it has been  established  that  the
         kstat  is  present,  all  the name or value pairs it contains will be
         available.



   User-defined Map Values
       Processing of kstat values often requires the calculation of intermedi‐
       ate values such as deltas, averages, running totals and so on. Applica‐
       tions have to manage any such data themselves, including allocating and
       reclaiming  the  storage needed to hold them as Oracle Solaris adds and
       deletes kstats.


       The kstat2 API allows applications  to  store  their  own  data  values
       inside  the  same  map  that  it uses to store the Oracle Solaris kstat
       data. This can be used to remove much of  the  data  management  burden
       from applications. The API imposes the following restrictions:

           o      Values  may only be added to existing maps, and new maps may
                  not be created.


           o      The names of any application name/value pairs  must  not  be
                  the same as any existing kernel-provided names in the map.


           o      Modification of kernel-provided values is not allowed.

                  An example for user-defined map values is as follows:


                            uint64_t my_int;
                            char *my_str;

                            /* ... */

                            (void) kstat2_map_put_integer(map, "myint", my_int);
                            (void) kstat2_map_put_string(map, "mystr", my_str);

                            /* ... */

                            kstat2_nv_t val;
                            (void) kstat2_map_get(map, "my_int", &val);



   Update-safe Map References
       Rather  than  requiring that every map access is done through a lookup,
       it is permissible to  retain  a  reference  to  either  a  map  or  the
       name/value  pairs  obtained  from the map. When an update is performed,
       the name/value pair values will be updated in place so the  new  values
       will  be  available  through  the data fields of the kstat2_nv_t struc‐
       tures. However, kstats can be deleted (for example, if a CPU  goes  off
       line)  and  a  call  to kstat2_update() will then result in any related
       kstat  maps  being  deleted,  leaving  the   application   with   stale
       kstat2_map_t  and  kstat2_nv_t  references. So that the application can
       detect this and drop any affected references, a mechanism  is  provided
       to allow the application to detect this situation.


       Before  accessing  any cached map references or the name or value pairs
       obtained from them, the application should check  that  the  map  still
       exists.  It  can  do  this by first obtaining a map reference, and then
       checking that the reference is still valid after an update  and  before
       dereferencing  any  cached  name or value pairs from within the map. An
       example is as follows:


                 /* Look up a map, retrieve a data value */
                 kstat2_map_t map = NULL;
                 (void) kstat2_lookup_map(handle, "kstat:/system/cpu/0/sys", &map);
                 kstat2_nv_t syscall = NULL;
                 (void) kstat2_map_get(map, "syscall", &syscall));

                 /* Allocate a reference to the map */
                 kstat2_mapref_t ref = NULL;
                 kstat2_mapref_alloc(map, &ref);

                 /* Update kstats */
                 (void) kstat2_update(handle);

                 /*
                  * Check the reference is still valid,
                  * if so the data item is also still valid.
                  */
                 if (kstat2_mapref_deref(ref, &map) == KSTAT2_S_OK) {
                     printf("cpu 0 syscall = %lld\n", syscall->kstat2_integer);
                 } else {
                     /* Clean up */
                 }


   Handling kstat Tree Modifications
       When the kstat2_update() function is called, the kstat tree  maintained
       by  the library is resynchronised with the kstat state held by the ker‐
       nel. The kernel may have added or removed kstats since the last update,
       in  which  case the changes will be reflected in the tree maintained by
       the library. Applications may need to  respond  to  such  changes,  for
       example, redrawing GUI components or recalculating statistics. In order
       to avoid applications having to scan the kstat tree on every update,  a
       callback mechanism is provided to allow applications to receive notifi‐
       cations of any such changes. These callbacks are triggered  during  any
       call  to kstat2_update() that causes a mutation to the kstat tree below
       the point at which they are registered.


       Two types of mutation events may occur. The first is  the  addition  or
       removal  of  maps to the kstat tree. The second is addition and removal
       of kernel kstat data to or from those maps (see KSTAT2_NVK_SYS  above).
       To cater for both situations, two notification callbacks are provided.

   Kstat Tree Mutations
       The  application  may register callbacks which will be called when maps
       are added to or removed from the kstat tree. The callbacks must be reg‐
       istered  at a level above the map for which notifications are required.
       For example, for notifications of all changes  the  callback  would  be
       registered  against  the  kstat:/  map. For changes to the misc/cpu sys
       kstats, the callback would be registered on the kstat:/misc/cpu map.


       All tree mutation callbacks registered above a map will be called  when
       a  map  is  added or removed and callbacks are made in bottom-up order.
       The callbacks are passed three parameters, the  first  is  the  map  on
       which  the  callback  is  registered, the second is the newly added sub
       map, and the third is an enumeration denoting the event  as  either  an
       addition  or a removal. Callbacks can only access user keys in the map,
       system keys (representing kstat values) cannot be  accessed.  For  more
       information, see the kstat2_mapiter_start(3KSTAT2) man page.


       When  multiple  levels  of sub maps are being added, the maps are added
       parent-first and callbacks registered above the addition point will  be
       notified  of  the  additions in that order. When multiple levels of sub
       maps are being removed, the maps are removed child-first and  callbacks
       registered above the removal point will be notified of the additions in
       that order. An example is as follows:


                 /* Tree mutation callback function */
                 static void
                 tree_cb(kstat2_map_t map, kstat2_map_t sub_map,
                   kstat2_tree_cb_event_t event)
                 {
                     char *map_uri = NULL;
                     char *submap_uri = NULL;
                     (void) kstat2_map_uri(map, &map_uri);
                     (void) kstat2_map_uri(sub_map, &submap_uri);
                     printf("tree: %s: child %s: %s\n", map_uri, submap_uri,
                       event == KSTAT2_TREE_ADD ? "added" : "removed");
                     free(map_uri);
                     free(submap_uri);
                 }

                 /* Register tree callback in main routine */
                 kstat2_map_t root = NULL;
                 (void) kstat2_lookup_map(handle, "kstat:/", &root);
                 (void) kstat2_map_set_tree_cb(root, &tree_cb);



       Callbacks may be  deregistered  by  passing  NULL  as  a  parameter  to
       kstat2_map_set_tree_cb()  function.  Only  one addition callback may be
       registered per node. If multiple calls to kstat2_map_set_tree_cb()  are
       made, any previously registered callback will be replaced.

   Kstat Data Mutations
       kstat data mutation callbacks operate in a similar manner to kstat tree
       mutation callbacks. Data mutation  callbacks  are  called  when  kernel
       kstat  data  is  added  to or removed from an existing map in the kstat
       tree.


       All data mutation callbacks registered on  and  above  a  map  will  be
       called when a map is added or removed and callbacks are made in bottom-
       up order. The callbacks are passed three parameters, the first  is  the
       map  on which the callback is registered, the second is the newly added
       sub map, and the third is an enumeration denoting the event  as  either
       an  addition  or  a  removal. Callbacks can access any keys in the map.
       Callbacks above the affected map will be called in  child-first  order.
       An example is as follows:


                 /* Data mutation callback function */
                 static void
                 data_cb(kstat2_map_t map, kstat2_map_t sub_map,
                   kstat2_data_cb_event_t event)
                 {
                     char *map_uri = NULL;
                     char *submap_uri = NULL;
                     (void) kstat2_map_uri(map, &map_uri);
                     (void) kstat2_map_uri(sub_map, &submap_uri);
                     printf("data: %s: child %s: %s\n", map_uri, submap_uri,
                       event == KSTAT2_TREE_ADD ? "added" : "removed");
                     free(map_uri);
                     free(submap_uri);
                 }

                 /* Register callback in main routine */
                 kstat2_map_t root = NULL;
                 (void) kstat2_lookup_map(handle, "kstat:/", &root);
                 (void) kstat2_map_set_data_cb(root, &data_cb);



       Callbacks  may  be  deregistered  by  passing  NULL  as  a parameter to
       kstat2_map_set_data_cb() function. Only one  removal  callback  may  be
       registered  per node, if multiple calls to kstat2_map_set_data_cb() are
       made, any previously registered callback will be replaced.

   Storing Arbitrary Application Data in the kstat Tree
       Applications may want to store their own data  within  the  kstat  data
       tree,  for example, the filehandle a kstat is being logged to or a ref‐
       erence to a GUI component being used to display the callback.  To  make
       that  possible,  arbitrary user data in the form of a void* pointer may
       be associated with each kstat node as follows:


                 kstat2_map_t map;
                 void* mydata;

                 /* Add user data to a map */
                 (void) kstat2_map_set_userdata(map, mydata);

                 /* Retrieve user data from a map */
                 (void) kstat2_map_get_userdata(map, &data);


   Application Data and kstat Deletion
       Application data may require cleanup actions when the kstat it is asso‐
       ciated  with  is deleted. For example, a filehandle may need closing, a
       GUI component may need closing, or memory may have to be deallocated. A
       destroy  callback  is provided for this purpose. The callback is passed
       two parameters, the kstat the callback was registered against  and  the
       void*  pointer  that  is  stored in the node, or NULL if no application
       data was stored. The destroy callback is called after any removal call‐
       backs  have been called and immediately before the kstat node itself is
       removed. An example is as follows:


                 /* Destruction callback function */
                 static void
                 destroy_cb(kstat2_map_t map, void* data)
                 {
                     char *uri = NULL;
                     (void) kstat2_map_uri(map, &uri);
                     printf("%s destroyed, user data: \"%s\"\n", uri, data);
                     free(uri);
                 }

                 /* Store user data and register callback in main routine */
                 kstat2_map_set_userdata(map, "goodbye!");
                 kstat2_map_set_destroy_cb(map, &destroy_cb);



       A callback function pointer of NULL may be used to remove any  existing
       callback.

   Calling kstat2 APIs From Inside Callbacks
       All  three  callback  mechanisms  are  triggered  during  calls  to the
       kstat2_update() function.  To  prevent  infinite  recursion,  calls  to
       kstat2_update()  are therefore forbidden from inside callbacks and will
       fail with an error code  of  KSTAT2_S_INVAL_STATE.  In  addition,  tree
       mutation  callbacks  described  above  are not allowed to access kernel
       kstat data (KSTAT2_NVK_SYS) as it may not be available at the time  the
       callback  is  made.  All other kstat2 API calls are allowed from within
       callbacks, including the registration of callbacks and the addition and
       removal of application data from the kstat maps.

   Closing the kstat2 Session
       After use, the kstat handle should be closed to reclaim the handles and
       memory that it allocated on open. Note that this  will  invalidate  all
       current  map  and value references. kstat removal callbacks will not be
       called, but kstat  destruction  callbacks  will  be  called,  to  allow
       cleanup of any application data stored in the kstat tree. An example is
       as follows:


                 stat = kstat2_close(&handle);
                 if (stat != KSTAT2_S_OK) {
                     (void) printf("can't close kstats: %s\n",
                       kstat2_status_string(stat));
                     exit(1);
                 }


   kstat2 Tree Node Lifecycles
       Nodes in the kstat tree are dynamically created and updated in response
       to  changes  in the kstats collected in the kernel. As noted above, the
       kstat tree maintained by the library is resynchronised with the  kernel
       kstats  on  each  call to kstat2_update(). This means that applications
       need to be prepared to respond to additions and removals  of  both  map
       nodes and kernel kstats within the tree. Of particular note is the case
       where the last remaining kstat in a subtree is  removed.  For  example,
       given the following partial generic kstat tree:


         kstat:/class/module/name/instance0
         kstat:/class/module/name/instance1



       If  both instance0 and instance1 are deleted then the parent node, name
       will become empty and it will also be deleted, as will any parent  maps
       that  have  now  also become empty as a result of the deletion of name.
       This means that applications that make use  of  callbacks  need  to  be
       aware  that  maps containing callbacks may be deleted, even if they are
       not terminal maps within the tree.


       If callbacks have been registered and  the  kstat_close()  function  is
       called,  only destruction callbacks will be called, to allow the recla‐
       mation of any resources that  have  been  associated  with  kstat  maps
       through  kstat2_map_set_userdata().  Tree  and  data mutation callbacks
       will not be made.

   Making kstat2 Consumers Robust in the Face of Change
       In the future, new enumeration and flag values  may  be  added  to  the
       kstat  types  such  as kstat2_nv_type_t and kstat2_nv_metatype_t. It is
       recommended that applications are written  in  such  a  way  that  they
       either  warn or ignore when encountering unknown values, for example by
       use of default blocks in case statements.

   Cross Architecture and 32/64 bit Safety
       Note that the kstat2 data structures will be different sizes on differ‐
       ent  architectures,  and  between  32-bit and 64-bit applications. This
       means the structures are not safe to pass  between  applications  which
       differ  in  this  way,  for  example through a network socket or a door
       call.

   Demonstration of the Use of kstat2 Features
       The following example makes use of multiple kstat2 features:

           o      Retrieving and displaying data


           o      Update safe map references


           o      Storing user data values


           o      kstat update callbacks


       Example 7 Demonstrating the use of the kstat2 interface



                      /*
                  * Demonstration of the use of the kstat2 interface, including
                  * map references, user-supplied kstat values and callbacks.
                  *
                  * Loop, printing out the syscall data for cpu0 in the last
                  * second.  If cpu0 goes offline, will print a message and
                  * keep looking every second until it comes back online, when
                  * it will resume printing the syscall data.
                  */

                 #include <stdio.h>
                 #include <stdlib.h>
                 #include <unistd.h>
                 #include <signal.h>
                 #include <sys/varargs.h>
                 #include <kstat2.h>
                 #include <note.h>

                 /* Format for printing unsigned 64-bit integers */
                 #ifdef _LP64
                 #define UI64F "%lu"
                 #else
                 #define UI64F "%llu"
                 #endif

                 /* Set to true on interrupt */
                 static volatile int stop = 0;

                 /* Signal handler */
                 static void
                 sig(int sig)
                 {
                     NOTE(ARGUNUSED(sig))
                     (void) printf("\ninterrupted\n");
                     stop = 1;
                 }

                 /* Print an error message and exit */
                 static void
                 fatal(const char *msg, kstat2_status_t stat)
                 {
                     (void) fprintf(stderr, "%s: %s\n", msg,
                       kstat2_status_string(stat));
                     exit(1);
                 }

                 /* Tree mutation callback function */
                 static void
                 tree_cb(kstat2_map_t map, kstat2_map_t sub_map,
                   kstat2_tree_cb_event_t event)
                 {
                     char *map_uri = NULL;
                     char *submap_uri = NULL;
                     (void) kstat2_map_uri(map, &map_uri);
                     (void) kstat2_map_uri(sub_map, &submap_uri);
                     printf("tree: %s: child %s: %s\n", map_uri, submap_uri,
                       event == KSTAT2_TREE_ADD ? "added" : "removed");
                     free(map_uri);
                     free(submap_uri);
                 }

                 /* Data mutation callback function */
                 static void
                 data_cb(kstat2_map_t map, kstat2_map_t sub_map,
                   kstat2_data_cb_event_t event)
                 {
                     char *map_uri = NULL;
                     char *submap_uri = NULL;
                     (void) kstat2_map_uri(map, &map_uri);
                     (void) kstat2_map_uri(sub_map, &submap_uri);
                     printf("data: %s: child %s: %s\n", map_uri, submap_uri,
                       event == KSTAT2_DATA_ADD ? "added" : "removed");
                     free(map_uri);
                     free(submap_uri);
                 }

                 /* Destruction callback function */
                 static void
                 destroy_cb(kstat2_map_t map, void* data)
                 {
                     char *uri = NULL;
                     (void) kstat2_map_uri(map, &uri);
                     (void) printf("%s destroyed, user data: \"%s\"\n",
                       uri, (char *)data);
                     free(uri);
                 }

                 /* Main routine - loop until interrupted */
                 int
                 main(int argc, char **argv)
                 {
                     NOTE(ARGUNUSED(argc, argv))

                     /* Open a kstats handle */
                     kstat2_status_t stat;
                     kstat2_handle_t handle;
                     stat = kstat2_open(&handle);
                     if (stat != KSTAT2_S_OK) {
                         fatal("Can't open kstats", stat);
                     }

                     /* Trap stop signals */
                     (void) signal(SIGINT, &sig);
                     (void) signal(SIGHUP, &sig);
                     (void) signal(SIGTERM, &sig);

                     /* Add addition and removal callbacks to top level */
                     kstat2_map_t root = NULL;
                     stat = kstat2_lookup_map(handle, "kstat:/", &root);
                     if (stat != KSTAT2_S_OK) {
                         fatal("Can't retrieve kstat root", stat);
                     }
                     (void) kstat2_map_set_tree_cb(root, &tree_cb);
                     (void) kstat2_map_set_data_cb(root, &data_cb);

                     /* Loop until interrupted */
                     while (! stop) {
                         kstat2_map_t cpusys0 = NULL;
                         kstat2_nv_t curr = NULL;
                         kstat2_nv_t prev = NULL;

                         /* Loop until the cpu/0/sys kstat is available */
                         while (! stop) {
                             /* Try to retrieve the cpu/0/sys kstat */
                             stat = kstat2_lookup_map(handle,
                               "kstat:/system/cpu/0/sys", &cpusys0);
                             if (stat == KSTAT2_S_NOT_FOUND) {
                                 (void) printf("CPU 0 offline\n");
                                 goto wait;
                             } else if (stat != KSTAT2_S_OK) {
                                 fatal("Can't retrieve cpu/0/sys kstat", stat);
                             }

                             /* Get the current syscall value from the kstat */
                             if ((stat = kstat2_map_get(cpusys0, "syscall", &curr))
                               != KSTAT2_S_OK) {
                                 /* The kstat has been deleted */
                                 (void) printf("Can't retrieve syscall value: %s\n",
                                   kstat2_status_string(stat));
                                 goto wait;
                             }
                             break;

                         wait:
                             (void) sleep(1);
                             stat = kstat2_update(handle);
                             if (stat != KSTAT2_S_OK) {
                                 fatal("kstat update failed", stat);
                             }
                         }

                         /* Stop immediately if interrupted */
                         if (stop) {
                             break;
                         }

                         /* Save the current syscall value as an user entry */
                         (void) kstat2_map_put_integer(cpusys0, "prev_syscall",
                           curr->kstat2_integer);

                         /* Get a reference to the saved value */
                         (void) kstat2_map_get(cpusys0, "prev_syscall", &prev);

                         /* Set a destroy callback on the kstat */
                         (void) kstat2_map_set_userdata(cpusys0, "goodbye!");
                         (void) kstat2_map_set_destroy_cb(cpusys0, &destroy_cb);

                         /* Allocate a reference to the map */
                         kstat2_mapref_t ref = NULL;
                         (void) kstat2_mapref_alloc(cpusys0, &ref);

                         /* Loop until the cpu/0/sys kstat disappears */
                         while (! stop) {
                             /* Wait and then update the kstats */
                             (void) sleep(1);
                             stat = kstat2_update(handle);
                             if (stat != KSTAT2_S_OK) {
                                 fatal("kstat update failed", stat);
                             }

                             /* Check the cpu/0/sys kstat is still present */
                             stat = kstat2_mapref_deref(ref, &cpusys0);
                             if (stat != KSTAT2_S_OK) {
                                 break;
                             }

                             /* Display the syscall values */
                             uint64_t c = curr->kstat2_integer;
                             uint64_t p = prev->kstat2_integer;
                             (void) printf("syscalls: prev=" UI64F " curr="
                               UI64F " delta="  UI64F "\n", p, c, c - p);
                             (void) kstat2_map_put_integer(cpusys0,
                               "prev_syscall", c);
                         }

                         /* Deallocate the map reference */
                         (void) kstat2_mapref_free(&ref);
                     }

                     /* Clean up & exit */
                     (void) kstat2_close(&handle);
                     return (0);
                 }

                 Example output:

                 syscalls: prev=31326193 curr=31326673 delta=480
                 syscalls: prev=31326673 curr=31327091 delta=418
                 syscalls: prev=31327091 curr=31329309 delta=2218
                 syscalls: prev=31329309 curr=31331165 delta=1856
                 syscalls: prev=31331165 curr=31332590 delta=1425
                 syscalls: prev=31332590 curr=31333574 delta=984
                 data: kstat:/: child kstat:/system/cpu/0/sys: removed
                 tree: kstat:/: child kstat:/system/cpu/0/sys: removed
                 kstat:/system/cpu/0/sys destroyed, user data: "goodbye!"
                 data: kstat:/: child kstat:/system/cpu/0/vm: removed
                 tree: kstat:/: child kstat:/system/cpu/0/vm: removed
                 data: kstat:/: child kstat:/system/cpu/0/intr: removed
                 tree: kstat:/: child kstat:/system/cpu/0/intr: removed
                 data: kstat:/: child kstat:/zones/cpu/sys_zone_0/0: removed
                 tree: kstat:/: child kstat:/zones/cpu/sys_zone_0/0: removed
                 CPU 0 offline
                 CPU 0 offline
                 CPU 0 offline
                 CPU 0 offline
                 CPU 0 offline
                 tree: kstat:/: child kstat:/system/cpu/0/sys: added
                 tree: kstat:/: child kstat:/system/cpu/0/vm: added
                 tree: kstat:/: child kstat:/misc/cpu_stat: added
                 tree: kstat:/: child kstat:/misc/cpu_stat/cpu_stat0: added
                 tree: kstat:/: child kstat:/misc/cpu_stat/cpu_stat0/0: added
                 tree: kstat:/: child kstat:/system/cpu/0/intr: added
                 tree: kstat:/: child kstat:/zones/cpu/sys_zone_0/0: added
                 data: kstat:/: child kstat:/zones/cpu/sys_zone_0/0: added
                 data: kstat:/: child kstat:/system/cpu/0/intr: added
                 data: kstat:/: child kstat:/misc/cpu_stat/cpu_stat0/0: added
                 data: kstat:/: child kstat:/system/cpu/0/vm: added
                 data: kstat:/: child kstat:/system/cpu/0/sys: added
                 syscalls: prev=31334194 curr=31334485 delta=291
                 syscalls: prev=31334485 curr=31334648 delta=163
                 syscalls: prev=31334648 curr=31335571 delta=923
                 syscalls: prev=31335571 curr=31336559 delta=988
                 ^C
                 interrupted
                 syscalls: prev=31336559 curr=31336608 delta=49
                 kstat:/system/cpu/0/sys destroyed, user data: "goodbye!"



FILES
       /dev/kstat               Kernel statistics driver


       /usr/include/kstat2.h    Header



ATTRIBUTES
       See attributes(7) for descriptions of the following attributes:


       tab() box; cw(2.75i) |cw(2.75i) lw(2.75i) |lw(2.75i) ATTRIBUTE  TYPEAT‐
       TRIBUTE  VALUE  _  Interface  StabilityCommitted _ MT-LevelMT-Safe with
       exceptions


SEE ALSO
       kstat2_close(3KSTAT2),              kstat2_alloc_matcher_list(3KSTAT2),
       kstat2_add_matcher(3KSTAT2)          kstat2_free_matcher_list(3KSTAT2),
       kstat2_lookup_map(3KSTAT2),                  kstat2_map_flags(3KSTAT2),
       kstat2_map_get(3KSTAT2),              kstat2_map_get_userdata(3KSTAT2),
       kstat2_map_meta(3KSTAT2),                   kstat2_map_parent(3KSTAT2),
       kstat2_map_put_integer(3KSTAT2),      kstat2_map_put_integers(3KSTAT2),
       kstat2_map_put_string(3KSTAT2),        kstat2_map_put_strings(3KSTAT2),
       kstat2_map_remove(3KSTAT2),            kstat2_map_set_data_cb(3KSTAT2),
       kstat2_map_set_destroy_cb(3KSTAT2),    kstat2_map_set_tree_cb(3KSTAT2),
       kstat2_map_set_userdata(3KSTAT2),             kstat2_map_size(3KSTAT2),
       kstat2_map_to_array(3KSTAT2),                  kstat2_map_uri(3KSTAT2),
       kstat2_mapiter_end(3KSTAT2),           kstat2_mapiter_hasnext(3KSTAT2),
       kstat2_mapiter_next(3KSTAT2),           kstat2_mapiter_remove(3KSTAT2),
       kstat2_mapiter_start(3KSTAT2),            kstat2_mapref_alloc(3KSTAT2),
       kstat2_mapref_deref(3KSTAT2),              kstat2_mapref_free(3KSTAT2),
       kstat2_nv_meta(3KSTAT2),        kstat2_open(3KSTAT2),       kstat2_sta‐
       tus_string(3KSTAT2),                            kstat2_update(3KSTAT2),
       kstat2_uri_decode(3KSTAT2), kstat2_uri_encode(3KSTAT2), libkstat2(3LIB)

NOTES
       The  kstat2  functions  are  MT-Safe  with  the exception that only one
       thread may actively use  a  kstat2_handle_t,  or  any  object  obtained
       through  it,  at  any one time. Synchronization is required if multiple
       threads intend to  share  a  kstat2_handle_t  or  any  object  obtained
       through it. Synchronization is left to the application.



Oracle Solaris 11.4               12 Jul 2018                  kstat2(3KSTAT2)
맨 페이지 내용의 저작권은 맨 페이지 작성자에게 있습니다.
RSS ATOM XHTML 5 CSS3