Home | History | Annotate | Download | only in src
      1 /************************************************************************
      2 Copyright (c) 2015, The Linux Foundation. All rights reserved.
      3 
      4 Redistribution and use in source and binary forms, with or without
      5 modification, are permitted provided that the following conditions are
      6 met:
      7     * Redistributions of source code must retain the above copyright
      8       notice, this list of conditions and the following disclaimer.
      9     * Redistributions in binary form must reproduce the above
     10       copyright notice, this list of conditions and the following
     11       disclaimer in the documentation and/or other materials provided
     12       with the distribution.
     13     * Neither the name of The Linux Foundation nor the names of its
     14       contributors may be used to endorse or promote products derived
     15       from this software without specific prior written permission.
     16 
     17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20 ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 ************************************************************************/
     29 
     30 /**
     31  * @file datatop_helpers.c
     32  * @brief Contains functions which output data.
     33  *
     34  * Contains functions which are used for printing data to output streams.
     35  * Handles all formatting for data output. Also contains functions which
     36  * are responsible for data gathering and collection.
     37  */
     38 
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <stdint.h>
     42 #include <time.h>
     43 #include <sys/time.h>
     44 #include <string.h>
     45 #include <errno.h>
     46 #include "datatop_interface.h"
     47 #include "datatop_linked_list.h"
     48 #include "datatop_fileops.h"
     49 
     50 /**
     51  * @brief Prints the name and prefix of a datapoint.
     52  *
     53  * @param dp Dp whose name and prefix is printed.
     54  * @param prefix Directory where dp is contained.
     55  * @param fw File to print the information to.
     56  * @return FILE_ERROR - Writing to file was unsuccessful.
     57  * @return FILE_SUCCESS - Writing to file was successful.
     58  */
     59 static int dtop_format_dp_names(struct dtop_data_point *dp, const char
     60 						*prefix, FILE *fw)
     61 {
     62 	if (dp->prefix) {
     63 		if (fprintf(fw, "\"%s:%s:%s\",", prefix, dp->prefix,
     64 							dp->name) < 0)
     65 			return FILE_ERROR;
     66 	} else {
     67 		if (fprintf(fw, "\"%s::%s\",", prefix, dp->name) < 0)
     68 			return FILE_ERROR;
     69 	}
     70 	return FILE_SUCCESS;
     71 }
     72 
     73 /**
     74  * @brief Prints the value of a datapoint.
     75  *
     76  * Checks the type of the value and will print it accordingly.
     77  *
     78  * @param dp Pointer to the data_point struct which holds the value that will
     79  *           be printed.
     80  * @param fw File to print the information to.
     81  * @return FILE_ERROR - Writing to file was unsuccessful.
     82  * @return FILE_SUCCESS - Writing to file was successful.
     83  */
     84 static int dtop_format_dp_values(struct dtop_data_point *dp, FILE *fw)
     85 {
     86 	switch (dp->type) {
     87 	case DTOP_ULONG:
     88 		if (fprintf(fw, "%"PRIu64, dp->data.d_ulong) < 0)
     89 			return FILE_ERROR;
     90 	break;
     91 	case DTOP_LONG:
     92 		if (fprintf(fw, "%"PRId64, dp->data.d_long) < 0)
     93 			return FILE_ERROR;
     94 	break;
     95 	case DTOP_UINT:
     96 		if (fprintf(fw, "%d", dp->data.d_uint) < 0)
     97 			return FILE_ERROR;
     98 	break;
     99 	case DTOP_INT:
    100 		if (fprintf(fw, "%u", dp->data.d_uint) < 0)
    101 			return FILE_ERROR;
    102 	break;
    103 	case DTOP_UCHAR:
    104 		if (fprintf(fw, "%c,", dp->data.d_uchar) < 0)
    105 			return FILE_ERROR;
    106 		if (fprintf(fw, "(0x%02X)", dp->data.d_uchar) < 0)
    107 			return FILE_ERROR;
    108 	break;
    109 	case DTOP_CHAR:
    110 		if (fprintf(fw, "%c,", dp->data.d_char) < 0)
    111 			return FILE_ERROR;
    112 		if (fprintf(fw, "(%d)", dp->data.d_char) < 0)
    113 			return FILE_ERROR;
    114 	break;
    115 	case DTOP_STR:
    116 		if (fprintf(fw, "\"%s\"", dp->data.d_str) < 0)
    117 			return FILE_ERROR;
    118 	break;
    119 	default:
    120 		if (fprintf(fw, "UNKNOWN_TYPE") < 0)
    121 			return FILE_ERROR;
    122 	break;
    123 	}
    124 	return FILE_SUCCESS;
    125 }
    126 
    127 /**
    128  * @brief Prints the name and prefix of a dp, formatted appropriately.
    129  *
    130  * @param dpset data_point_gatherer used to access dp directory.
    131  * @param dp data_point used to get datapoint prefix if available.
    132  */
    133 static void dtop_format_text_for_snapshot
    134 	(struct dtop_data_point_gatherer *dpset, struct dtop_data_point dp)
    135 {
    136 	printf("%s:", dpset->prefix);
    137 	if (dp.prefix)
    138 		printf("%s:", dp.prefix);
    139 
    140 	printf("%s::", dp.name);
    141 }
    142 
    143 /**
    144  * @brief Prints a datapoint value to a specified csv file.
    145  *
    146  * @param dp Datapoint that holds the value to be printed.
    147  * @param fw File to print to.
    148  * @return FILE_ERROR - Writing to file was unsuccessful.
    149  * @return FILE_SUCCESS - Writing to file was successful.
    150  */
    151 static int dtop_print_dp_csv(struct dtop_data_point *dp, FILE *fw)
    152 {
    153 	if (dtop_format_dp_values(dp, fw) == FILE_ERROR)
    154 		return FILE_ERROR;
    155 	if (fprintf(fw, ",") < 0)
    156 		return FILE_ERROR;
    157 	return FILE_SUCCESS;
    158 }
    159 
    160 /**
    161  * @brief Prints a datapoint value to the terminal.
    162  *
    163  * @param dp Holds the value to be printed print.
    164  * @param prefix Used to print prefix of the data_point.
    165  */
    166 static void dtop_print_dp(struct dtop_data_point *dp, const char *prefix)
    167 {
    168 	dtop_format_dp_names(dp, prefix, stdout);
    169 	printf(" ");
    170 	dtop_format_dp_values(dp, stdout);
    171 	printf("\n");
    172 }
    173 
    174 /**
    175  * @brief Finds delta(value) of a datapoint.
    176  *
    177  * Function accounts for different types that values may be.
    178  *
    179  * @param dpset Pointer to a data_point used as another parameter for printing.
    180  * @param dp Datapoint which contains the value to find the difference of.
    181  */
    182 static void dtop_handle_dp_type_for_snapshot(
    183 	struct dtop_data_point_gatherer *dpset, struct dtop_data_point dp)
    184 {
    185 	int64_t int64;
    186 
    187 	switch (dp.type) {
    188 	case DTOP_ULONG:
    189 	default:
    190 		/* This is less than ideal. Replace with 128-bit ops later */
    191 		int64 = (int64_t)dp.data.d_ulong
    192 			- (int64_t)dp.initial_data.d_ulong;
    193 		if (int64 != 0) {
    194 			dtop_format_text_for_snapshot(dpset, dp);
    195 			printf("%"PRId64"\n", int64);
    196 		}
    197 	break;
    198 
    199 	case DTOP_LONG:
    200 		/* This is less than ideal. Replace with 128-bit ops later */
    201 		int64 = (int64_t)dp.data.d_long
    202 			- (int64_t)dp.initial_data.d_long;
    203 		if (int64 != 0) {
    204 			dtop_format_text_for_snapshot(dpset, dp);
    205 			printf("%"PRId64"\n", int64);
    206 		}
    207 	break;
    208 
    209 	case DTOP_UINT:
    210 		int64 = (int64_t)dp.data.d_uint
    211 			- (int64_t)dp.initial_data.d_uint;
    212 		if (int64 != 0) {
    213 			dtop_format_text_for_snapshot(dpset, dp);
    214 			printf("%"PRId64"\n", int64);
    215 		}
    216 	break;
    217 
    218 	case DTOP_INT:
    219 		int64 = (int64_t)dp.data.d_int
    220 			- (int64_t)dp.initial_data.d_int;
    221 		if (int64 != 0) {
    222 			dtop_format_text_for_snapshot(dpset, dp);
    223 			printf("%"PRId64"\n", int64);
    224 		}
    225 	break;
    226 	}
    227 }
    228 
    229 /**
    230  * @brief Calls the dtop_print_dp_csv function for each data_point a dpg has access to.
    231  *
    232  * @param dpg A data_point_gatherer struct that is iterated through for each datapoint.
    233  * @param fw File to print datapoint values to.
    234  * @return FILE_ERROR - Writing to file was unsuccessful.
    235  * @return FILE_SUCCESS - Writing to file was successful.
    236  */
    237 static int dtop_print_dpg_csv(struct dtop_data_point_gatherer *dpg, FILE *fw)
    238 {
    239 	int i;
    240 
    241 	for (i = 0; i < dpg->data_points_len; i++)
    242 		if (dtop_print_dp_csv(&(dpg->data_points[i]), fw) == FILE_ERROR)
    243 			return FILE_ERROR;
    244 	return FILE_SUCCESS;
    245 }
    246 
    247 /**
    248  * @brief Calls the dtop_format_dp_names function for each data_point a dpg has access to.
    249  *
    250  * @param dpg A data_point_gatherer struct that is iterated through for each datapoint.
    251  * @param fw File to printg datapoint names and prefixes to.
    252  * @return FILE_ERROR - Writing to file was unsuccessful.
    253  * @return FILE_SUCCESS - Writing to file was successful.
    254  */
    255 int dtop_print_dpg_names_csv(struct dtop_data_point_gatherer *dpg, FILE *fw)
    256 {
    257 	int i;
    258 
    259 	for (i = 0; i < dpg->data_points_len; i++)
    260 		if (dtop_format_dp_names(&(dpg->data_points[i]),
    261 		dpg->prefix, fw) == FILE_ERROR)
    262 			return FILE_ERROR;
    263 
    264 	return FILE_SUCCESS;
    265 }
    266 
    267 /**
    268  * @brief Prints all dp values to a specified file.
    269  *
    270  * This function is responsible for the printing of all data_point values
    271  * to a specified file. It will iterate through the linked list which contains
    272  * all of the dpgs and will print each dp value, being sure to flush the buffer.
    273  *
    274  * @param dpg_list Pointer to first node of linked list which contains all dpgs.
    275  * @param fw File that data prints to.
    276  * @return FILE_ERROR - Writing to file was unsuccessful.
    277  * @return FILE_SUCCESS - Writing to file was successful.
    278  */
    279 int dtop_write_pollingdata_csv(struct dtop_linked_list *dpg_list, FILE *fw)
    280 {
    281 	struct dtop_linked_list *curr_ptr = dpg_list;
    282 	struct dtop_data_point_gatherer *dpset;
    283 
    284 	while (curr_ptr) {
    285 		dpset = (struct dtop_data_point_gatherer *) curr_ptr->data;
    286 		if (dtop_print_dpg_csv(dpset, fw) == FILE_ERROR)
    287 			return FILE_ERROR;
    288 		curr_ptr = curr_ptr->next_ptr;
    289 		fflush(fw);
    290 	}
    291 
    292 	if (fprintf(fw, "\n") < 0)
    293 		return FILE_ERROR;
    294 
    295 	return FILE_SUCCESS;
    296 }
    297 
    298 /**
    299  * @brief Calls the dtop_print_dp function for each data_point a dpg has access to.
    300  *
    301  * @param dpg A data_point_gatherer struct that is iterated through for each datapoint.
    302  */
    303 void dtop_print_dpg(struct dtop_data_point_gatherer *dpg)
    304 {
    305 	int i;
    306 	for (i = 0; i < dpg->data_points_len; i++)
    307 		dtop_print_dp(&(dpg->data_points[i]), dpg->prefix);
    308 }
    309 
    310 /**
    311  * @brief Stores the values for the datapoints and populates the initial value.
    312  *
    313  * @param dp A datapoint whose value will be stored.
    314  * @param str Str used for sscanf function call to find value of dp.
    315  */
    316 void dtop_store_dp(struct dtop_data_point *dp, const char *str)
    317 {
    318 	switch (dp->type) {
    319 	case DTOP_ULONG:
    320 		sscanf(str, "%"PRIu64, &(dp->data.d_ulong));
    321 		if (dp->initial_data_populated == NOT_POPULATED) {
    322 			dp->initial_data.d_ulong = dp->data.d_ulong;
    323 			dp->initial_data_populated = POPULATED;
    324 		}
    325 	break;
    326 	case DTOP_LONG:
    327 		sscanf(str, "%"PRId64, &(dp->data.d_long));
    328 		if (dp->initial_data_populated == NOT_POPULATED) {
    329 			dp->initial_data.d_long = dp->data.d_long;
    330 			dp->initial_data_populated = POPULATED;
    331 		}
    332 	break;
    333 	case DTOP_UINT:
    334 		sscanf(str, "%u",  &(dp->data.d_uint));
    335 		if (dp->initial_data_populated == NOT_POPULATED) {
    336 			dp->initial_data.d_uint = dp->data.d_uint;
    337 			dp->initial_data_populated = POPULATED;
    338 		}
    339 	break;
    340 	case DTOP_INT:
    341 		sscanf(str, "%d",  &(dp->data.d_int));
    342 		if (dp->initial_data_populated == NOT_POPULATED) {
    343 			dp->initial_data.d_int = dp->data.d_int;
    344 			dp->initial_data_populated = POPULATED;
    345 		}
    346 	break;
    347 	case DTOP_UCHAR:
    348 		sscanf(str, "%c",  &(dp->data.d_uchar));
    349 		if (dp->initial_data_populated == NOT_POPULATED) {
    350 			dp->initial_data.d_uchar = dp->data.d_uchar;
    351 			dp->initial_data_populated = POPULATED;
    352 		}
    353 	break;
    354 	case DTOP_CHAR:
    355 		sscanf(str, "%c",  &(dp->data.d_char));
    356 		if (dp->initial_data_populated == NOT_POPULATED) {
    357 			dp->initial_data.d_char = dp->data.d_char;
    358 			dp->initial_data_populated = POPULATED;
    359 		}
    360 	break;
    361 	case DTOP_STR:
    362 		sscanf(str, "%s",  dp->data.d_str);
    363 		if (dp->initial_data_populated == NOT_POPULATED) {
    364 			memcpy(dp->initial_data.d_str, dp->data.d_str,
    365 			       DTOP_DP_MAX_STR_LEN);
    366 			dp->initial_data_populated = POPULATED;
    367 		}
    368 	break;
    369 	default:
    370 	break;
    371 	}
    372 }
    373 
    374 /**
    375  * @brief Responsible for calculating and printing current time to file.
    376  *
    377  * Prints the time since 1970, in Seconds and Milliseconds.
    378  *
    379  * @param fw File that time is printed to.
    380  * @return FILE_ERROR - Writing to file was unsuccessful.
    381  * @return FILE_SUCCESS - Writing to file was successful.
    382  */
    383 int dtop_print_time_at_poll(FILE *fw)
    384 {
    385 	struct timeval tv;
    386 	gettimeofday(&tv, NULL);
    387 
    388 	if (fprintf(fw, "%10ld", tv.tv_sec) < 0)
    389 		return FILE_ERROR;
    390 
    391 	if (fprintf(fw, ".%06ld,", tv.tv_usec) < 0)
    392 		return FILE_ERROR;
    393 
    394 	return FILE_SUCCESS;
    395 }
    396 
    397 /**
    398  * @brief Polls all dp values and updates each value.
    399  *
    400  * @param dpg_list Pointer to first node of linked list which contains all dpgs.
    401  */
    402 void dtop_poll(struct dtop_linked_list *dpg_list)
    403 {
    404 	struct dtop_linked_list *curr_ptr = dpg_list;
    405 	struct dtop_data_point_gatherer *dpset;
    406 
    407 	while (curr_ptr) {
    408 		dpset = (struct dtop_data_point_gatherer *) curr_ptr->data;
    409 		dpset->poll(dpset);
    410 		curr_ptr = curr_ptr->next_ptr;
    411 	}
    412 }
    413 
    414 /**
    415  * @brief Prints the delta(value) of all data_points to terminal.
    416  *
    417  * @param dpg_list Pointer to first node of linked list which contains all dpgs.
    418  */
    419 void dtop_print_snapshot_diff(struct dtop_linked_list *dpg_list)
    420 {
    421 	int i;
    422 
    423 	struct dtop_linked_list *curr_ptr = dpg_list;
    424 	struct dtop_data_point_gatherer *dpset;
    425 	printf("\n");
    426 	printf("Change In Datapoint Values\n");
    427 	printf("---------------------------\n");
    428 	while (curr_ptr) {
    429 		dpset = (struct dtop_data_point_gatherer *) curr_ptr->data;
    430 		for (i = 0; i < dpset->data_points_len; i++)
    431 			dtop_handle_dp_type_for_snapshot(dpset,
    432 					  dpset->data_points[i]);
    433 		curr_ptr = curr_ptr->next_ptr;
    434 	}
    435 	printf("\n");
    436 }
    437 
    438 /**
    439  * @brief Resets the initial values of all data_points.
    440  *
    441  * @param dpg_list Pointer to first node of linked list which contains all dpgs.
    442  */
    443 void dtop_reset_dp_initial_values(struct dtop_linked_list *dpg_list)
    444 {
    445 	int i;
    446 
    447 	struct dtop_linked_list *curr_ptr = dpg_list;
    448 	struct dtop_data_point_gatherer *dpset;
    449 
    450 	while (curr_ptr) {
    451 		dpset = (struct dtop_data_point_gatherer *) curr_ptr->data;
    452 		for (i = 0; i < dpset->data_points_len; i++)
    453 			dpset->data_points[i].initial_data_populated
    454 							= NOT_POPULATED;
    455 		curr_ptr = curr_ptr->next_ptr;
    456 	}
    457 }
    458 
    459 /**
    460  * @brief Calls deconstructor method for all dpgs dynamically created.
    461  *
    462  * Checks to see if each dpg created has a deconstructor method. If not null,
    463  * function calls the appropiate deconstructor method to deallocate memory.
    464  *
    465  * @param dpg_list Pointer to first node of linked list which contains all dpgs.
    466  */
    467 void deconstruct_dpgs(struct dtop_linked_list *dpg_list)
    468 {
    469 	struct dtop_linked_list *curr_ptr = dpg_list;
    470 	struct dtop_data_point_gatherer *dpset;
    471 
    472 	while (curr_ptr) {
    473 		dpset = (struct dtop_data_point_gatherer *) curr_ptr->data;
    474 		if (dpset->deconstruct)
    475 			dpset->deconstruct(dpset);
    476 		curr_ptr = curr_ptr->next_ptr;
    477 	}
    478 }
    479