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