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 */
dtop_format_dp_names(struct dtop_data_point * dp,const char * prefix,FILE * fw)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 */
dtop_format_dp_values(struct dtop_data_point * dp,FILE * fw)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 */
dtop_format_text_for_snapshot(struct dtop_data_point_gatherer * dpset,struct dtop_data_point dp)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 */
dtop_print_dp_csv(struct dtop_data_point * dp,FILE * fw)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 */
dtop_print_dp(struct dtop_data_point * dp,const char * prefix)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 */
dtop_handle_dp_type_for_snapshot(struct dtop_data_point_gatherer * dpset,struct dtop_data_point dp)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 */
dtop_print_dpg_csv(struct dtop_data_point_gatherer * dpg,FILE * fw)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 */
dtop_print_dpg_names_csv(struct dtop_data_point_gatherer * dpg,FILE * fw)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 */
dtop_write_pollingdata_csv(struct dtop_linked_list * dpg_list,FILE * fw)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 */
dtop_print_dpg(struct dtop_data_point_gatherer * dpg)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 */
dtop_store_dp(struct dtop_data_point * dp,const char * str)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 */
dtop_print_time_at_poll(FILE * fw)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 */
dtop_poll(struct dtop_linked_list * dpg_list)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 */
dtop_print_snapshot_diff(struct dtop_linked_list * dpg_list)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 */
dtop_reset_dp_initial_values(struct dtop_linked_list * dpg_list)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 */
deconstruct_dpgs(struct dtop_linked_list * dpg_list)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