Harout Hedeshian | 6202ba7 | 2015-04-13 19:02:25 -0600 | [diff] [blame] | 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> |
Harout Hedeshian | 0abce00 | 2015-07-22 14:53:41 -0600 | [diff] [blame] | 39 | #include <stdint.h> |
Harout Hedeshian | 6202ba7 | 2015-04-13 19:02:25 -0600 | [diff] [blame] | 40 | #include <string.h> |
| 41 | #include <stdlib.h> |
Harout Hedeshian | 0abce00 | 2015-07-22 14:53:41 -0600 | [diff] [blame] | 42 | #include <inttypes.h> |
Harout Hedeshian | 6202ba7 | 2015-04-13 19:02:25 -0600 | [diff] [blame] | 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) { |
Harout Hedeshian | 0abce00 | 2015-07-22 14:53:41 -0600 | [diff] [blame] | 147 | sscanf(dict.val[i], "%" PRIu64, |
Harout Hedeshian | 6202ba7 | 2015-04-13 19:02:25 -0600 | [diff] [blame] | 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 | } |