Go to main content

man pages section 3: Extended Library Functions, Volume 4

Exit Print View

Updated: Wednesday, July 27, 2022
 
 

sstore_data_iter_next (3SSTORE)

Name

sstore_data_read, sstore_data_iter_next - Read statistics and events

Synopsis

     cc [ flag... ] file... -lsstore [ library... ]
     #include <libsstore.h>

     sstore_err_t sstore_data_read(sstore_handle_t hdl,
         const char **ids, uint32_t id_count,
         sstore_range_t range, sstore_walk_t walk,
         sstore_iter_t *iterp);

     sstore_err_t sstore_data_iter_next(sstore_handle_t hdl,
         sstore_iter_t iter, char **idp, uint64_t *timep,
         sstore_value_t *valp);

Parameters

hdl

Handle to libsstore

ids

Array of Statistics Store identifiers

id_count

Total number of Statistics Store identifiers

range

Time range or data range.

Passing NULL for range implies:

  • start-time = SS_TIME_NOW

  • end-time = SS_TIME_NOW

  • step = (None - raw data)

walk

Format of the iteration. The following formats are supported:

SSTORE_WALK_ID

Walks the data records by identifier

SSTORE_WALK_TS

Walks the data records by timestamps

iterp

Address to store the starting address of the iterator returned from batch request execution

iter

Iterator returned from the sstore_data_read() function.

idp

Address to store the starting address of the Statistics Store identifier.

timep

Address to store the time in microseconds since epoch.

valp

Address to store the handle to a typed value.

Description

The sstore_data_read() function retrieves the statistics and events associated with the given identifiers and range. The retrieved data is returned in the form of an iterator that can be used to read the data records. Once all the data records have been read from the iterator, the iterator must be freed using the sstore_iter_free(3SSTORE) function.

If the start-time or end-time in the given range is SS_TIME_NOW, indicating that the range includes current time, then the sstore_data_read() function also starts recording data for the ssids in the ids array if they are not being recorded already. The sstore_data_read() function continues to record this data for 300 seconds after the last sstore_data_read() function call for the given ssids with a range that includes current time.

Data point interpolation may be applied for non-zero values of the step parameter (gives the granularity in seconds). For more information, see the sstore_range_alloc(3SSTORE) man page.

The value of the walk parameter determines the order in which the data records are returned when you walk the iterator. The walk parameter can have the following values:

SSTORE_WALK_ID

Walks the result by Statistics Store identifier. For each identifier, walks all the data records associated with that identifier.

SSTORE_WALK_TS

Walks the result by the time stamp of the data records in chronological order.

The sstore_data_iter_next(3SSTORE) function retrieves the next data record of the iteration. Each data record consists of an ssid, a time stamp, and a value. The reference pointers passed to this call are populated if the call succeeds. The identifier, time stamp, and value populated on success do not need to be freed. They are freed on the next call to the sstore_data_iter_next(3SSTORE) function.

Authorizations

See the sstore-security(7) man page for a description of the authorizations required to read statistics.

Return Values

Upon successful completion, the sstore_data_read() and sstore_data_iter_next() functions return ESSTORE_OK. Otherwise, they return an error code, which is also cached in the given libsstore handle.

Errors

The sstore_data_read() function might return ESSTORE_ARG_INVALID, ESSTORE_HANDLE_INVALID, ESSTORE_RETRY, ESSTORE_CONNECTION_FAILED, ESSTORE_UNAUTHORIZED, ESSTORE_TOO_BIG, or ESSTORE_NOMEM.

The sstore_data_iter_next() function might return ESSTORE_ARG_INVALID, ESSTORE_HANDLE_INVALID, or ESSTORE_ITER_DONE.

ESSTORE_NOMEM

There is insufficient memory.

ESSTORE_ARG_INVALID

One of the following reasons:

  • Required arguments are missing.

  • The format is not valid.

  • The range is not valid.

ESSTORE_HANDLE_INVALID

The libsstore handle is invalid.

ESSTORE_CONNECTION_FAILED

Failed to connect to the statistics store daemon.

ESSTORE_RETRY

The statistics store daemon is busy. Retry later.

ESSTORE_TOO_BIG

The total size of all the resulting statistics records is larger than the maximum size limit set in libsstore handle.

Warnings

The sstore_data_read() function might set the following:

SS_WARN_INVALID SSID

This is syntactically or semantically invalid.

SS_WARN_NOENT

Unable to resolve the ssid.

Examples

Example 1 Reading CPU Statistics at Intervals

Read CPU statistics for CPU 0 for count times and sleep for interval seconds between each read as follows:

     #include <libsstore.h>
     #include <stdio.h>
     #include <unistd.h>

     /* List of statistical identifiers */
     const char *ids[] = {
         "//:class.cpu//:stat.xcalls",
         "//:class.cpu//:stat.usage//:part.mode(idle)",
         "//:class.cpu//:stat.interrupt-//:s.[count,time]",
     };

     /* Total number of statistical identifiers */
     uint32_t id_count = 3;

     /* Number of seconds to sleep between 2 reads */ 
     int interval = 1;

     /* Number of times the statistics need to be read */
     int count = 3;

     sstore_handle_t hdl = NULL;

     /*
      * Prints the value in the value handle.
      */
     int print_value(sstore_value_t val)
     {
         uint64_t val_u64;
         char *keyp;
         sstore_value_t valp;

         switch(sstore_value_type(val)) {
         case SSTORE_VALUE_NUMBER:
             if (sstore_value_number(hdl, val, &val_u64) != ESSTORE_OK) {
                return (sstore_err_code(hdl));
             }
             printf("%llu\n", val_u64);
             break;
    
         case SSTORE_VALUE_DICTIONARY:
             while (sstore_value_dictionary_next(hdl, val, &keyp,
                 &valp) == ESSTORE_OK) {
                     (void) printf("%s ", keyp);
                     (void) print_value(valp);
             }
             break;

         case SSTORE_VALUE_NODATA:
             printf("NO_DATA\n");
             break;

         default:
             printf("Invalid value type %d\n", sstore_value_type(val));
         }

         return (ESSTORE_OK);
     }

     /*
      * Reads and iterate through the statistics for the given identifiers
      * every second for 'count' number of times.
      */
     void read_data()
     {
         sstore_iter_t iter = NULL;
         sstore_value_t val;
         int i = 0;
         char *id, *desc;
         uint64_t ts;

         printf("%-58s %-16s %s\n", "IDENTIFIER", "TIMESTAMP", "VALUE");

         while (i++ < count) {
             /* Read the most recent value for the given identifiers */
             if (sstore_data_read(hdl, ids, id_count, NULL, SSTORE_WALK_ID,
                 &iter) != ESSTORE_OK)
                     break;

             /* Check and print any warnings */
             while (sstore_warning_next(hdl, &id, &desc) != SS_WARN_OK) {
                     fprintf(stderr, "Failed to read stats for %s. Error: %s\n",
                         id, desc);
             }

             /* Iterate and print the returned statistical records */
             while (sstore_data_iter_next(hdl, iter, &id, &ts,
                 &val) == ESSTORE_OK) {
                    printf("%-58s %16llu ", id, ts);
                    if (print_value(val) != ESSTORE_OK)
                        break;
             }

             /* Free the iterator */
             sstore_iter_free(iter);
             iter = NULL;

             /* Check if the iteration was successful */
             if (sstore_err_code(hdl) != ESSTORE_ITER_DONE)
                     break;

             sleep(interval);
             printf("\n");
         }

         /* Check for errors */
         if (sstore_err_code(hdl) != ESSTORE_OK &&
             sstore_err_code(hdl) != ESSTORE_ITER_DONE) {
                sstore_iter_free(iter);
                fprintf(stderr, "%s. Error: %s.\n", sstore_err_action(hdl),
                 sstore_err_description(hdl));
         }
     }

     int main()
     {
         /* Allocate a libsstore handle */
         if ((hdl = sstore_alloc()) == NULL) {
             printf("Failed to allocate handle\n");
             return (-1);
         }

         /* Read and print the statistics */
         read_data();

         /* Free the libsstore handle */
         sstore_free(hdl);

         return (0);
     }


     Output:

     IDENTIFIER                                      TIMESTAMP        VALUE
     //:class.cpu//:stat.xcalls                      1424815728214187 68027
     //:class.cpu//:stat.usage//:part.mode(idle) 1424815727214132 idle 3206077270089
     //:class.cpu//:stat.interrupt-count             1424815728960968 total 1479974
     //:class.cpu//:stat.interrupt-time              1424815728960968 total 5329198050

     //:class.cpu//:stat.xcalls                      1424815728214187 68027
     //:class.cpu//:stat.usage//:part.mode(idle) 1424815728214187 idle 3207073755382
     //:class.cpu//:stat.interrupt-count             1424815728960968 total 1479974
     //:class.cpu//:stat.interrupt-time              1424815728960968 total 5329198050

     //:class.cpu//:stat.xcalls                      1424815729214360 68053
     //:class.cpu//:stat.usage//:part.mode(idle) 1424815729214360 idle 3208069183506
     //:class.cpu//:stat.interrupt-count             1424815729214363 total 1480104
     //:class.cpu//:stat.interrupt-time              1424815729214363 total 5329702612
Example 2 Reading Historical CPU Statistics and Walking the Result

Read historical statistics for CPU 0 and walk the result with different walk types as follows:

     #include <libsstore.h>
     #include <stdio.h>
     #include <sys/time.h>
     #include <unistd.h>

     #define    MICRO   1000000

     /* List of statistical identifiers */
     const char *ids[] = {
         "//:class.cpu//:stat.usage",
         "//:class.cpu//:stat.xcalls",
     };

     /* Total number of statistical identifiers */
     uint32_t id_count = 2;

     /* Interval for data capture */
     int interval = 3;

     sstore_handle_t hdl = NULL;

     /*
      * Prints the value in the value handle.
      */
     int print_value(sstore_value_t val)
     {
         uint64_t val_u64;
         double val_real;
         char *keyp;
         sstore_value_t valp;

         switch(sstore_value_type(val)) {
         case SSTORE_VALUE_NUMBER:
             if (sstore_value_number(hdl, val, &val_u64) != ESSTORE_OK) {
                 return (sstore_err_code(hdl));
             }
             printf("%llu\n", val_u64);
             break;
 
         case SSTORE_VALUE_REAL:
             if (sstore_value_real(hdl, val, &val_real) != ESSTORE_OK) {
                 return (sstore_err_code(hdl));
             }
             printf("%6.2f\n", val_real);
             break;

         case SSTORE_VALUE_DICTIONARY:
             while (sstore_value_dictionary_next(hdl, val, &keyp,
                 &valp) == ESSTORE_OK) {
                     (void) printf("%s ", keyp);
                     (void) print_value(valp);
             }
             break;
   
         case SSTORE_VALUE_NODATA:
             printf("NO_DATA\n");
             break;

         default:
             printf("Invalid value type %d\n", sstore_value_type(val));
         }

         return (ESSTORE_OK);
     }

     /*
      * Reads and iterate through the statistics for the given identifiers
      * every second for 'count' number of times.
      */
     void read_data(sstore_range_t range, sstore_walk_t walk,
         int print_data)
     {
         sstore_iter_t iter = NULL;
         sstore_value_t val;
         char *id, *desc;
         uint64_t ts;

        /* Read the statistics collected during the interval */
        if (sstore_data_read(hdl, ids, id_count, range, walk,
            &iter) != ESSTORE_OK)
                goto error;

        /* Check if we need to print the data */
        if (print_data == 0)
                goto cleanup;

        /* Iterate through data records and print */
        printf("%-42s %-16s %s\n", "IDENTIFIER", "TIMESTAMP", "VALUE");
        while (sstore_data_iter_next(hdl, iter, &id, &ts,
             &val) == ESSTORE_OK) {
                /* Round out the times */
                ts = (ts / MICRO) * MICRO;
                printf("%-42s %16llu ", id, ts);
                if (print_value(val) != ESSTORE_OK)
                        goto cleanup;
        }

cleanup:
        /* Free the iterator */
        sstore_iter_free(iter);
        if (sstore_err_code(hdl) == ESSTORE_OK ||
            sstore_err_code(hdl) == ESSTORE_ITER_DONE)
               return;

error:
        fprintf(stderr, "%s. Error: %s\n", sstore_err_action(hdl),
            sstore_err_description(hdl));
     }

     int main()
     {
        uint64_t init_time, start_time, end_time, step;
        sstore_range_t range = NULL;

        if ((init_time = time(NULL)) == (time_t)-1) {
                fprintf(stderr, "Could not find time\n");
                return (-1);
        }

        /* Allocate a libsstore handle */
        if ((hdl = sstore_alloc()) == NULL) {
                fprintf(stderr, "Failed to allocate handle\n");
                return (-1);
        }

        /* Allocate a range struct */
        if ((range = sstore_range_alloc()) == NULL) {
                sstore_free(hdl);
                fprintf(stderr, "Failed to allocate range\n");
                return (-1);
        }

        /*
         * Start a dynamic log job to record stats in sstored.
         * Wait 'interval' seconds to allow some data to be collected.
         *
         * Note: Passing NULL for 'range' implies start = SS_TIME_NOW,
         * end = SS_TIME_NOW and step = 1.
         */
        printf("Capturing data for %d seconds...\n", interval);
        read_data(NULL, SSTORE_WALK_ID, 0);
        sleep(interval);

        /* Convert init_time into microseconds and get the time range */
        start_time = init_time * MICRO;
        end_time = ((init_time + interval) * MICRO) - 1;
        step = 1;

        /*
         * Initialize the range struct
         * Note: The following call will not fail since we are
         * reusing the range struct allocated earlier.
         */
        range = sstore_range_by_time(range, start_time, end_time, step);

        /* Read and print the statistics while walking by ID */
        printf("\nWalking data by TS...\n");
        read_data(range, SSTORE_WALK_TS, 1);

        /* Read and print the statistics while walking by TS */
        printf("\nWalking data by ID...\n");
        read_data(range, SSTORE_WALK_ID, 1);

        /* Free the libsstore handle */
        sstore_free(hdl);

        /* Free the range struct */
        sstore_range_free(range);

        return (0);
     }

     Output:

     Capturing data for 3 seconds...

     Walking data by TS...
     IDENTIFIER                      TIMESTAMP        VALUE
     //:class.cpu//:stat.usage   1424815732000000 total 3243831735969
     //:class.cpu//:stat.xcalls      1424815732000000 68122.89
     //:class.cpu//:stat.usage   1424815733000000 total 3244833333130
     //:class.cpu//:stat.xcalls      1424815733000000 80431.19
     //:class.cpu//:stat.usage   1424815734000000 total 3244833333587
     //:class.cpu//:stat.xcalls      1424815734000000 80629.86

     Walking data by ID...
     IDENTIFIER                      TIMESTAMP        VALUE
     //:class.cpu//:stat.usage   1424815732000000 total 3243831735969
     //:class.cpu//:stat.usage   1424815733000000 total 3244833333130
     //:class.cpu//:stat.usage   1424815734000000 total 3244833333587
     //:class.cpu//:stat.xcalls      1424815732000000 68122.89
     //:class.cpu//:stat.xcalls      1424815733000000 80431.19
     //:class.cpu//:stat.xcalls      1424815734000000 80629.86

Attributes

See the attributes(7) man page for descriptions of the following attributes:

ATTRIBUTE TYPE
ATTRIBUTE VALUE
Availability
pkg:/service/system/sstore
Interface Stability
Committed
MT-Level
Safe

See Also

libnvpair(3LIB), libsstore(3LIB), sstore_alloc(3SSTORE), sstore_data_attach(3SSTORE), sstore_err_action(3SSTORE), sstore_range_alloc(3SSTORE), attributes(7), privileges(7), sstore(7), sstore-security(7)