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_meminfo_file_poll.c
     32  * @brief Adds ability for data collection from /proc/meminfo
     33  *
     34  * File contains methods for searching and polling data from
     35  * "/proc/meminfo"
     36  */
     37 
     38 #include <stdio.h>
     39 #include <stdint.h>
     40 #include <string.h>
     41 #include <stdlib.h>
     42 #include <inttypes.h>
     43 #include "datatop_interface.h"
     44 #include "datatop_fileops.h"
     45 #include "datatop_str.h"
     46 
     47 #define DTOP_MEM_SIZE 8192
     48 #define DTOP_MEM_LINE (DTOP_MEM_SIZE>>2)
     49 
     50 /**
     51 * @struct dtop_meminfo_vars
     52 * @brief Struct used to hold necessary variables for /proc/meminfo dpg
     53 *
     54 * @var dtop_meminfo_vars::line
     55 * Array of strings where necessary dp names and values are held.
     56 * @var dtop_meminfo_vars::line_count
     57 * Number of lines the file is that the dpg represents.
     58 */
     59 struct dtop_meminfo_vars {
     60 	char **line;
     61 	int line_count;
     62 };
     63 
     64 /**
     65  * @brief Parses lines with data in "/proc/meminfo"
     66  *
     67  * @param line1 Line to parse to find datapoint names and values.
     68  * @param len1 Length of line1.
     69  * @param l Index in the dictionary the key/value pair is added to.
     70  * @param dict Dictionary the keys and values are added to.
     71  */
     72 int dt_meminfo_parse(char *line1, int len1,
     73 			int l, struct dt_procdict *dict)
     74 {
     75 	int i, k, n;
     76 	if (len1 < 1)
     77 		return 0;
     78 
     79 	if (line1 == 0 || dict == 0)
     80 		return 0;
     81 
     82 	k = l;
     83 	dict->key[k] = &line1[0];
     84 	for (i = 0; i < len1 && k < DTOP_DICT_SIZE; i++) {
     85 		if (line1[i] == ' ' || line1[i] == '	') {
     86 			line1[i] = 0;
     87 			n = i+1;
     88 			while (line1[n] == '	' || line1[n] == ' ')
     89 				n++;
     90 			dict->val[k] = &line1[n];
     91 			while (line1[n] != ' ')
     92 				n++;
     93 			line1[n] = 0;
     94 			break;
     95 		}
     96 	}
     97 	k++;
     98 	dict->max = k;
     99 	return k;
    100 }
    101 
    102 /**
    103  * @brief Stores the data collected from a "/proc/meminfo"
    104  *
    105  * @param dpg Struct that polled data is added to.
    106  * @return DTOP_POLL_IO_ERR - Poll of dpg unsuccessful.
    107  * @return DTOP_POLL_OK - Poll of dpg successful.
    108  */
    109 int dtop_meminfo_poll(struct dtop_data_point_gatherer *dpg)
    110 {
    111 	char *data;
    112 	int *line_len = malloc(sizeof(int) *
    113 			((struct dtop_meminfo_vars *)
    114 			(dpg->priv))->line_count);
    115 	int read;
    116 	struct dt_procdict dict;
    117 	int i, j, n, sum;
    118 
    119 	read = dt_read_file(dpg->file, &data, DTOP_MEM_SIZE);
    120 	if (read == 0 || data == 0)
    121 		return DTOP_POLL_IO_ERR;
    122 
    123 	sum = 0;
    124 	/* Assigns each line read from the file, a length */
    125 	for (n = 0; n < ((struct dtop_meminfo_vars *)
    126 				(dpg->priv))->line_count; n++) {
    127 		line_len[n] = dt_read_line(((struct dtop_meminfo_vars *)
    128 					(dpg->priv))->line[n],
    129 					   DTOP_MEM_LINE, data,
    130 					   DTOP_MEM_SIZE, sum);
    131 		if (n <= (((struct dtop_meminfo_vars *)
    132 			(dpg->priv))->line_count - 1)) {
    133 			sum += (line_len[n] + 1);
    134 		}
    135 
    136 	}
    137 
    138 	/* Stores dp names and values in dictionary */
    139 	for (i = 0; i < dpg->data_points_len; i++)
    140 		dt_meminfo_parse(((struct dtop_meminfo_vars *)
    141 			(dpg->priv))->line[i], line_len[i], i, &dict);
    142 
    143 	/* Assigns the dp value to the dp struct */
    144 	for (j = 0; j < dpg->data_points_len; j++) {
    145 		i = dt_find_dict_idx(dpg->data_points[j].name, &dict);
    146 		if (i >= 0 && i < dict.max) {
    147 			sscanf(dict.val[i], "%" PRIu64,
    148 			       &(dpg->data_points[i].data.d_ulong));
    149 			dpg->data_points[i].data.d_ulong *= 1024;
    150 			if (dpg->data_points[i].
    151 				initial_data_populated == NOT_POPULATED) {
    152 				dpg->data_points[i].initial_data.d_ulong
    153 					= dpg->data_points[i].data.d_ulong;
    154 				dpg->data_points[i].initial_data_populated
    155 					= POPULATED;
    156 			}
    157 		}
    158 	}
    159 
    160 	dt_free(&data);
    161 	free(line_len);
    162 	return DTOP_POLL_OK;
    163 }
    164 
    165 /**
    166  * @brief Frees dynamically allocated "/proc/meminfo" dpg.
    167  *
    168  * Frees the memory of the dpg along with it's data_points
    169  * and other malloc'd memory no longer needed.
    170  *
    171  * @param dpg Dpg to deconstruct and deallocate memory for.
    172  */
    173 static void dtop_meminfo_dpg_deconstructor
    174 			(struct dtop_data_point_gatherer *dpset)
    175 {
    176 	int i;
    177 	free(dpset->data_points);
    178 	for (i = 0; i < ((struct dtop_meminfo_vars *)
    179 				(dpset->priv))->line_count; i++)
    180 		free(((struct dtop_meminfo_vars *)(dpset->priv))->line[i]);
    181 	free(((struct dtop_meminfo_vars *)(dpset->priv))->line);
    182 	free(((struct dtop_meminfo_vars *)(dpset->priv)));
    183 	free(dpset);
    184 }
    185 
    186 /**
    187  * @brief Creates a dpg for "/proc/meminfo" file
    188  *
    189  * Dynamically allocates memory for dpg which is then added to a linked list
    190  * via the dtop_register(dpg) function call.
    191  *
    192  * @param data_points dtop_data_point struct that dpg points to.
    193  * @param storage dtop_meminfo_vars struct that holds relevant dpg variables.
    194  */
    195 static void construct_meminfo_file_dpg(struct dtop_data_point
    196 		*data_points, struct dtop_meminfo_vars *storage)
    197 {
    198 	struct dtop_data_point_gatherer *dpg = malloc
    199 		(sizeof(struct dtop_data_point_gatherer));
    200 	dpg->prefix = "/proc/meminfo";
    201 	dpg->file = "/proc/meminfo";
    202 	dpg->poll = dtop_meminfo_poll;
    203 	dpg->data_points = data_points;
    204 	dpg->priv = (struct dtop_meminfo_vars *)storage;
    205 	dpg->data_points_len = storage->line_count;
    206 	dpg->deconstruct = dtop_meminfo_dpg_deconstructor;
    207 
    208 	dtop_register(dpg);
    209 }
    210 
    211 /**
    212  * @brief Scans "/proc/meminfo in order to autodetect dps.
    213  *
    214  * Searches through "/proc/meminfo" file for all available data
    215  * points to create as dp structs.
    216  *
    217  * @param storage dtop_meminfo_vars struct where relevant variables are stored.
    218  */
    219 int dtop_meminfo_search(struct dtop_meminfo_vars *storage)
    220 {
    221 	int i, k, n, sum;
    222 	char *data;
    223 	int *line_len = malloc(sizeof(int) * storage->line_count);
    224 	int read;
    225 	struct dt_procdict dict;
    226 	struct dtop_data_point *data_points;
    227 
    228 	storage->line = malloc(storage->line_count * sizeof(*storage->line));
    229 
    230 	for (i = 0; i < storage->line_count; i++)
    231 		storage->line[i] = malloc(sizeof(char) * DTOP_MEM_LINE);
    232 
    233 	read = dt_read_file("/proc/meminfo", &data, DTOP_MEM_SIZE);
    234 	if (read == 0 || data == 0)
    235 		return DTOP_POLL_IO_ERR;
    236 
    237 	sum = 0;
    238 	/* Assigns each line read from the file, a length */
    239 	for (n = 0; n < storage->line_count; n++) {
    240 		line_len[n] = dt_read_line(storage->line[n],
    241 					   DTOP_MEM_LINE, data,
    242 					   DTOP_MEM_SIZE, sum);
    243 		if (n < (storage->line_count - 1))
    244 			sum += (line_len[n] + 1);
    245 	}
    246 
    247 	/* Stores dp names in dictionary */
    248 	for (i = 0; i < (storage->line_count); i++)
    249 		dt_parse_proc_same_line_key_and_val(storage->line[i],
    250 						line_len[i], i, &dict);
    251 
    252 	data_points = malloc
    253 		       (storage->line_count * sizeof(struct dtop_data_point));
    254 
    255 	k = 0;
    256 	/* Creates a dtop_data_point struct for each dp found in the file */
    257 	for (i = 0; i < dict.max; i++) {
    258 		data_points[i].name = dict.key[i];
    259 		data_points[i].prefix = NULL;
    260 		data_points[i].type = DTOP_ULONG;
    261 		k++;
    262 	}
    263 
    264 	/* Calls dpg constructor, dpg will point to the dp struct */
    265 	construct_meminfo_file_dpg(data_points, storage);
    266 
    267 	free(line_len);
    268 	dt_free(&data);
    269 
    270 	return DTOP_POLL_OK;
    271 }
    272 
    273 /**
    274  * @brief Calls dtop_search for "/proc/meminfo" file.
    275  */
    276 void dtop_meminfo_init(void)
    277 {
    278 	struct dtop_meminfo_vars *storage = malloc
    279 			(sizeof(struct dtop_meminfo_vars));
    280 	storage->line_count = dtop_get_file_line_amount("/proc/meminfo");
    281 	dtop_meminfo_search(storage);
    282 }
    283