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