1
2 /*
3 * Copyright (C) Texas Instruments - http://www.ti.com/
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 #include "perf_config.h"
22 #include "perf_common.h"
23 #include <ctype.h>
24
25 #ifdef ANDROID
26 /* Log for Android system*/
27 #include <utils/Log.h>
28 #endif
29
30 /* pre-declare helper functions */
31 static int assign_string(char **psMember, char const *sValue);
32 static int assign_string_if_matches(char const *line, char const *argument,
33 char **psMember);
34 static int assign_long(unsigned long *piMember, char const *sValue);
35 static int assign_long_if_matches(char const *line, char const *argument,
36 unsigned long *piMember);
37 static void read_line(PERF_Config *sConfig, char const *line, char const *tag);
38 static char const *get_value_if_matches(char const *line, char const *argument);
39
40 /*-----------------------------------------------------------------------------
41 CONFIGURATION METHODS FUNCTIONS
42 -----------------------------------------------------------------------------*/
43 /* default configuration */
PERF_Config_Init(PERF_Config * sConfig)44 void PERF_Config_Init(PERF_Config *sConfig)
45 {
46 /* initialize default configuration */
47
48 sConfig->mask = 0;
49
50 /* logging interface */
51 sConfig->trace_file = NULL;
52 sConfig->delayed_open = 0;
53 sConfig->buffer_size = 65536;
54
55 /* debug interface */
56 sConfig->debug = FALSE;
57 sConfig->detailed_debug = FALSE;
58 sConfig->csv = 1;
59 sConfig->log_file = NULL;
60
61 /* replay interface */
62 sConfig->replay_file = strdup("STDOUT");
63
64 /* real-time interface */
65 sConfig->realtime = 0;
66 sConfig->rt_granularity = 1;
67 sConfig->rt_summary = 1;
68 sConfig->rt_debug = 0;
69 sConfig->rt_detailed = 0;
70 sConfig->rt_file = strdup("STDERR");
71 }
72
73 /* release configuration memory */
PERF_Config_Release(PERF_Config * sConfig)74 void PERF_Config_Release(PERF_Config *sConfig)
75 {
76 /* release all allocated members */
77 if (sConfig->trace_file)
78 {
79 free(sConfig->trace_file);
80 sConfig->trace_file = NULL;
81 }
82 if (sConfig->log_file)
83 {
84 free(sConfig->log_file);
85 sConfig->log_file = NULL;
86 }
87 if (sConfig->replay_file)
88 {
89 free(sConfig->replay_file);
90 sConfig->replay_file = NULL;
91 }
92 if (sConfig->rt_file)
93 {
94 free(sConfig->rt_file);
95 sConfig->rt_file = NULL;
96 }
97 }
98
99 /** Method read_line
100 *
101 * Arg1 pointer to configuration
102 *
103 * Arg2 configuration line (trimmed of trailing white
104 * spaces)
105 *
106 * Arg3 tag - restrict matches to this tag or no-tag
107 *
108 * Effects compares configuration lines to assignments to each
109 * configuration variable. If tags are specified before the
110 * configuration variable, they are ignored unless they match
111 * the supplied tag. If it matches, the assignment is performed
112 * to the variable. Otherwise, an error message is printed.
113 * */
114
115 static
read_line(PERF_Config * cfg,char const * line,char const * tag)116 void read_line(PERF_Config *cfg, char const *line, char const *tag)
117 {
118 char const *ptr;
119
120 /* skip leading spaces */
121 while (*line && isspace(*line)) line++;
122
123 /* ignore comment lines and empty lines */
124 if (!*line || *line == '#') return;
125
126 /* check to see if there is a tag prefix */
127
128 /* find first white-space or . in the line */
129 for (ptr = line; *ptr && !isspace(*ptr) && *ptr != '.' && *ptr != '='; ptr++);
130
131 if (*ptr == '.')
132 {
133 /* ignore lines where the tag does not match */
134 if (!tag || strncmp(line, tag, ptr - line)) return;
135
136 /* otherwise, skip the tag for the match */
137 line = ptr + 1;
138 }
139
140 /* check for known member names */
141
142 if (!(assign_long_if_matches(line, "mask", &cfg->mask) ||
143 /* logging configuration */
144 assign_string_if_matches(line, "trace_file", &cfg->trace_file) ||
145 assign_long_if_matches(line, "delayed_open", &cfg->delayed_open) ||
146 assign_long_if_matches(line, "buffer_size", &cfg->buffer_size) ||
147 /* debug configuration */
148 assign_string_if_matches(line, "log_file", &cfg->log_file) ||
149 assign_long_if_matches(line, "debug", &cfg->debug) ||
150 assign_long_if_matches(line, "detailed_debug",&cfg->detailed_debug) ||
151 assign_long_if_matches(line, "csv", &cfg->csv) ||
152 /* replay configuration */
153 assign_string_if_matches(line, "replay_file", &cfg->replay_file) ||
154 /* real-time configuration */
155 assign_long_if_matches(line, "realtime", &cfg->realtime) ||
156 assign_long_if_matches(line, "rt_granularity", &cfg->rt_granularity) ||
157 assign_long_if_matches(line, "rt_debug", &cfg->rt_debug) ||
158 assign_long_if_matches(line, "rt_detailed", &cfg->rt_detailed) ||
159 assign_long_if_matches(line, "rt_summary", &cfg->rt_summary) ||
160 assign_string_if_matches(line, "rt_file", &cfg->rt_file)
161 ))
162
163 {
164 fprintf(stderr,
165 "warning: incorrect line in configuration file:\n%s\n", line);
166 }
167 }
168
169 /*
170 Effects: reads each line of the perf.ini file and processes configuration
171 assignments in linear order. Maximum line length is enforced, and all
172 lines longer than this are ignored. Also, all lines must end in new-line
173 If ulID is specified, lines starting with the fourCC ULID. will also be
174 read. Lines starting with # will be ignored.
175 */
PERF_Config_Read(PERF_Config * sConfig,char const * tag)176 void PERF_Config_Read(PERF_Config *sConfig, char const *tag)
177 {
178 FILE *config_file = NULL;
179 char line[PERF_CONFIG_LINELENGTH];
180 int ignore = FALSE;
181
182 if (sConfig)
183 {
184 /* open config file */
185 config_file = fopen(PERF_CONFIG_FILE, "rt");
186 if (config_file)
187 {
188 /* read each line */
189 while (fgets(line, PERF_CONFIG_LINELENGTH, config_file))
190 {
191 if (/* strlen(line) == PERF_CONFIG_LINELENGTH && */
192 *line && line[strlen(line)-1] != '\n')
193 {
194 /* ignore lines that reach the max length */
195 ignore = TRUE;
196 }
197 else if (!ignore)
198 {
199 /* remove new-line and trailing spaces from end of line */
200 while (*line && isspace(line [strlen(line)-1]))
201 {
202 line[strlen(line)-1] = 0;
203 }
204
205 /* process un-ignored lines */
206 read_line(sConfig, line, tag);
207 }
208 else
209 {
210 /* no longer ignore lines after they are completely read */
211 ignore = FALSE;
212 }
213 }
214
215 /* done */
216 fclose(config_file);
217 }
218 }
219 }
220
221 /*-----------------------------------------------------------------------------
222 HELPER FUNCTIONS
223 -----------------------------------------------------------------------------*/
224
225 /** Method get_value_if_matches
226 *
227 * Arg1 configuration line
228 *
229 * Arg2 configuration variable name
230 *
231 * Effects if the configuration line is <variable name> =
232 * <value>, it returns the <value>. Otherwise, it returns NULL
233 *
234 * */
235 static
get_value_if_matches(char const * line,char const * argument)236 char const *get_value_if_matches(char const *line,
237 char const *argument)
238 {
239 /* skip leading spaces */
240 while (*line && isspace(*line)) line++;
241
242 /* return NULL if argument name does not match */
243 if (strncasecmp(line, argument, strlen(argument))) return (NULL);
244 line += strlen(argument);
245
246 /* there must be an = after argument name */
247
248 /* skip trailing spaces before = */
249 while (*line && isspace(*line)) line++;
250
251 /* return NULL if = not found */
252 if (*line != '=') return (NULL);
253 line++;
254
255 /* skip leading spaces before value */
256 while (*line && isspace(*line)) line++;
257
258 /* if reached the end of line, return NULL; otherwise, return value */
259 return(*line ? line : NULL);
260 }
261
262 /** Method assign_string
263 *
264 * Arg1 pointer to string configuration member
265 *
266 * Arg2 configuration value
267 *
268 * Effects Assigns the value to the configuration member.
269 * */
270
271 static
assign_string(char ** psMember,char const * sValue)272 int assign_string(char **psMember, char const *sValue)
273 {
274 /* delete any prior value */
275 if (*psMember)
276 {
277 free(*psMember);
278 *psMember = NULL;
279 }
280
281 /* set new value unless it is NULL */
282 if (strcasecmp(sValue, "NULL"))
283 {
284 *psMember = strdup(sValue);
285 }
286
287 return (1);
288 }
289
290 /** Method assign_long
291 *
292 * Arg1 pointer to configuration member
293 *
294 * Arg2 configuration value (string)
295 *
296 * Effects Assigns the integer value of the string to the
297 * configuration member. If value starts with '$' or '0x', it
298 * interprets the remaining digits as a hexadecimal number. If
299 * value starts with -, or with a digit, it is interpreted as a
300 * decimal (can be signed or unsigned). Otherwise, if it
301 * matches 'enabled', 'on' or 'true', the member is assigned 1.
302 * In all other cases, it is assigned 0.
303 * */
304
305 static
assign_long(unsigned long * piMember,char const * sValue)306 int assign_long(unsigned long *piMember, char const *sValue)
307 {
308 /* set new value */
309
310 /* hexadecimal value */
311 if (!strncasecmp(sValue, "0x", 2)) sscanf(sValue + 2, "%lx", piMember);
312 else if (*sValue == '$') sscanf(sValue + 1, "%lx", piMember);
313
314 /* decimal value */
315 else if (*sValue == '-') sscanf(sValue, "%ld", piMember);
316 else if (isdigit(*sValue)) sscanf(sValue, "%lu", piMember);
317
318 /* boolean value */
319 else *piMember = (!strcasecmp(sValue, "enabled") ||
320 !strcasecmp(sValue, "on") ||
321 !strcasecmp(sValue, "true"));
322
323 return (1);
324 }
325
326 /** Method assign_string_if_matches
327 *
328 * Arg1 configuration line
329 *
330 * Arg2 configuration variable name
331 *
332 * Arg3 pointer to string configuration member
333 *
334 * Effects if the configuration line is <variable name> =
335 * <value>, it assigns the value to the configuration
336 * member.
337 *
338 * Returns 1, if assignment occured. 0 otherwise.
339 * */
340
341 static
assign_string_if_matches(char const * line,char const * argument,char ** target)342 int assign_string_if_matches(char const *line, char const *argument,
343 char **target)
344 {
345 char const *value = get_value_if_matches(line, argument);
346 return (value ? (assign_string(target, value), 1) : 0);
347 }
348
349 /** Method assign_long_if_matches
350 *
351 * Arg1 configuration line
352 *
353 * Arg2 configuration variable name
354 *
355 * Arg3 pointer to string configuration member
356 *
357 * Effects if the configuration line is <variable name> =
358 * <value>, it assigns the integer value of the string to the
359 * configuration member in the following manner: If value
360 * starts with '$' or '0x', it interprets the remaining digits
361 * as a hexadecimal number. If value starts with -, or with a
362 * digit, it is interpreted as a decimal (can be signed or
363 * unsigned). Otherwise, if it matches 'enabled', 'on' or
364 * 'true', the member is assigned 1. In all other cases, it is
365 * assigned 0.
366 *
367 * Returns 1, if assignment occured. 0 otherwise (if config
368 * line was not an assignment to variable name).
369 * */
370
371 static
assign_long_if_matches(char const * line,char const * argument,unsigned long * target)372 int assign_long_if_matches(char const *line, char const *argument,
373 unsigned long *target)
374 {
375 char const *value = get_value_if_matches(line, argument);
376 return (value ? (assign_long(target, value), 1) : 0);
377 }
378
379
380