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

개요

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

kstat2(3kstat2)

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 ex‐
       tract the values you are interested by using the kstat2_map_get() func‐
       tion. The values are returned in a C structure where  all  the  members
       are  const.  The values should not be modified as doing so will corrupt
       the internal state of the library. The structure contains the name  and
       value,  as a union. The type field discriminates between the union mem‐
       bers, 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 en‐
       tire 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 in‐
       dividual  name/value  pairs  within the maps. Map level metadata can be
       retrieved by calling the kstat2_map_meta() function, passing in the ad‐
       dress 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, KSTAT2_NVK_ALL, &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 or‐
       der. 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  re‐
       quired,  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 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_up‐
       date() 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  in‐
       side  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  ap‐
       plications. 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 ex‐
       ists. 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  ex‐
       ample,  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  mu‐
       tation callbacks described above are not allowed to access kernel kstat
       data  (KSTAT2_NVK_SYS) as it may not be available at the time the call‐
       back is made. All other kstat2 API calls are allowed from within  call‐
       backs, including the registration of callbacks and the addition and re‐
       moval 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  ei‐
       ther  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, NULL);
                 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 ex‐
       ceptions


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_de‐
       code(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               21 Apr 2025                  kstat2(3KSTAT2)
맨 페이지 내용의 저작권은 맨 페이지 작성자에게 있습니다.
RSS ATOM XHTML 5 CSS3