Improve perfmon json table picker
[vpp.git] / src / plugins / perfmon / parse_util.c
1 /*
2  * parse_util.c - halfhearted json parser
3  *
4  * Copyright (c) 2018 Cisco Systems and/or its affiliates
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <perfmon/perfmon.h>
19 #include <vppinfra/unix.h>
20
21 typedef enum
22 {
23   STATE_START,
24   STATE_READ_NAME,
25   STATE_READ_VALUE,
26 } parse_state_t;
27
28 static u8 *
29 downcase (u8 * s)
30 {
31   u8 *rv = 0;
32   u8 c;
33   int i;
34
35   for (i = 0; i < vec_len (s); i++)
36     {
37       c = s[i];
38       if (c >= 'A' && c <= 'Z')
39         c = c + ('a' - 'A');
40       vec_add1 (rv, c);
41     }
42   return (rv);
43 }
44
45 uword *
46 perfmon_parse_table (perfmon_main_t * pm, char *path, char *table_name)
47 {
48   u8 *cp;
49   u8 *event_name;
50   int state = STATE_START;
51   uword *ht;
52   name_value_pair_t *nvp = 0;
53   name_value_pair_t **nvps = 0;
54   u8 *v;
55   int i;
56   u8 *json_filename;
57   clib_error_t *error;
58
59   /* Create the name/value hash table in any case... */
60   ht = hash_create_string (0, sizeof (uword));
61
62   json_filename = format (0, "%s/%s%c", path, table_name, 0);
63
64   vlib_log_debug (pm->log_class, "Try to read perfmon events from %s",
65                   json_filename);
66
67   error = unix_proc_file_contents ((char *) json_filename, &cp);
68
69   if (error)
70     {
71       vlib_log_err (pm->log_class,
72                     "Failed to read CPU-specific counter table %s",
73                     json_filename);
74       vlib_log_err (pm->log_class,
75                     "Please install the vpp-dev package and then:");
76       vlib_log_err
77         (pm->log_class, "cd %s; sudo tar Jxf PerfmonTables.tar.xz", path);
78       vlib_log_err (pm->log_class, "and restart vpp.");
79
80       vec_free (json_filename);
81       clib_error_report (error);
82       return ht;
83     }
84   vlib_log_debug (pm->log_class, "Read OK, parse the event table...");
85   vec_free (json_filename);
86
87 again:
88   while (*cp)
89     {
90       switch (state)
91         {
92         case STATE_START:
93           while (*cp && *cp != '{' && *cp != '}' && *cp != ',')
94             cp++;
95           if (*cp == 0)
96             goto done;
97
98           /* Look for a new event */
99           if (*cp == '{')
100             {
101               if (*cp == 0)
102                 {
103                 error:
104                   clib_warning ("parse fail");
105                   hash_free (ht);
106                   return 0;
107                 }
108               cp++;
109               state = STATE_READ_NAME;
110               goto again;
111             }
112           else if (*cp == '}')  /* end of event */
113             {
114               /* Look for the "EventName" nvp */
115               for (i = 0; i < vec_len (nvps); i++)
116                 {
117                   nvp = nvps[i];
118                   if (!strncmp ((char *) nvp->name, "EventName", 9))
119                     {
120                       event_name = nvp->value;
121                       goto found;
122                     }
123                 }
124               /* no name? */
125               for (i = 0; i < vec_len (nvps); i++)
126                 {
127                   vec_free (nvps[i]->name);
128                   vec_free (nvps[i]->value);
129                 }
130               vec_free (nvps);
131               cp++;
132               goto again;
133
134             found:
135               event_name = downcase (event_name);
136               hash_set_mem (ht, event_name, nvps);
137               nvp = 0;
138               nvps = 0;
139               cp++;
140               goto again;
141             }
142           else if (*cp == ',')  /* punctuation */
143             {
144               cp++;
145               goto again;
146             }
147           else                  /* should never happen... */
148             cp++;
149           goto again;
150
151         case STATE_READ_NAME:
152           vec_validate (nvp, 0);
153           v = 0;
154           while (*cp && *cp != '"')
155             cp++;
156
157           if (*cp == 0)
158             {
159               vec_free (nvp);
160               goto error;
161             }
162
163           cp++;
164           while (*cp && *cp != '"')
165             {
166               vec_add1 (v, *cp);
167               cp++;
168             }
169           if (*cp == 0)
170             {
171               vec_free (v);
172               goto error;
173             }
174           cp++;
175           vec_add1 (v, 0);
176           nvp->name = v;
177           state = STATE_READ_VALUE;
178           goto again;
179
180         case STATE_READ_VALUE:
181           while (*cp && *cp != ':')
182             cp++;
183           if (*cp == 0)
184             {
185               vec_free (nvp->name);
186               goto error;
187             }
188           while (*cp && *cp != '"')
189             cp++;
190           if (*cp == 0)
191             {
192               vec_free (nvp->name);
193               goto error;
194             }
195           else
196             cp++;
197           v = 0;
198           while (*cp && *cp != '"')
199             {
200               vec_add1 (v, *cp);
201               cp++;
202             }
203           if (*cp == 0)
204             {
205               vec_free (nvp->name);
206               vec_free (v);
207               goto error;
208             }
209           vec_add1 (v, 0);
210           nvp->value = v;
211           vec_add1 (nvps, nvp);
212           while (*cp && *cp != ',' && *cp != '}')
213             cp++;
214           if (*cp == 0)
215             {
216               vec_free (nvp->name);
217               vec_free (nvp->value);
218               goto error;
219             }
220           else if (*cp == '}')
221             state = STATE_START;
222           else
223             {
224               cp++;
225               state = STATE_READ_NAME;
226             }
227           nvp = 0;
228           goto again;
229         }
230     }
231
232 done:
233   return (ht);
234 }
235
236 /*
237  * fd.io coding-style-patch-verification: ON
238  *
239  * Local Variables:
240  * eval: (c-set-style "gnu")
241  * End:
242  */