Add x86_64 perfmon tables
[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");
73       vlib_log_err (pm->log_class,
74                     "Please install the vpp-dev package and then:");
75       vlib_log_err
76         (pm->log_class, "cd %s; sudo tar Jxf PerfmonTables.tar.xz", path);
77       vlib_log_err (pm->log_class, "and restart vpp.");
78
79       vec_free (json_filename);
80       clib_error_report (error);
81       return ht;
82     }
83   vlib_log_debug (pm->log_class, "Read OK, parse the event table...");
84   vec_free (json_filename);
85
86 again:
87   while (*cp)
88     {
89       switch (state)
90         {
91         case STATE_START:
92           while (*cp && *cp != '{' && *cp != '}' && *cp != ',')
93             cp++;
94           if (*cp == 0)
95             goto done;
96
97           /* Look for a new event */
98           if (*cp == '{')
99             {
100               if (*cp == 0)
101                 {
102                 error:
103                   clib_warning ("parse fail");
104                   hash_free (ht);
105                   return 0;
106                 }
107               cp++;
108               state = STATE_READ_NAME;
109               goto again;
110             }
111           else if (*cp == '}')  /* end of event */
112             {
113               /* Look for the "EventName" nvp */
114               for (i = 0; i < vec_len (nvps); i++)
115                 {
116                   nvp = nvps[i];
117                   if (!strncmp ((char *) nvp->name, "EventName", 9))
118                     {
119                       event_name = nvp->value;
120                       goto found;
121                     }
122                 }
123               /* no name? */
124               for (i = 0; i < vec_len (nvps); i++)
125                 {
126                   vec_free (nvps[i]->name);
127                   vec_free (nvps[i]->value);
128                 }
129               vec_free (nvps);
130               cp++;
131               goto again;
132
133             found:
134               event_name = downcase (event_name);
135               hash_set_mem (ht, event_name, nvps);
136               nvp = 0;
137               nvps = 0;
138               cp++;
139               goto again;
140             }
141           else if (*cp == ',')  /* punctuation */
142             {
143               cp++;
144               goto again;
145             }
146           else                  /* should never happen... */
147             cp++;
148           goto again;
149
150         case STATE_READ_NAME:
151           vec_validate (nvp, 0);
152           v = 0;
153           while (*cp && *cp != '"')
154             cp++;
155
156           if (*cp == 0)
157             {
158               vec_free (nvp);
159               goto error;
160             }
161
162           cp++;
163           while (*cp && *cp != '"')
164             {
165               vec_add1 (v, *cp);
166               cp++;
167             }
168           if (*cp == 0)
169             {
170               vec_free (v);
171               goto error;
172             }
173           cp++;
174           vec_add1 (v, 0);
175           nvp->name = v;
176           state = STATE_READ_VALUE;
177           goto again;
178
179         case STATE_READ_VALUE:
180           while (*cp && *cp != ':')
181             cp++;
182           if (*cp == 0)
183             {
184               vec_free (nvp->name);
185               goto error;
186             }
187           while (*cp && *cp != '"')
188             cp++;
189           if (*cp == 0)
190             {
191               vec_free (nvp->name);
192               goto error;
193             }
194           else
195             cp++;
196           v = 0;
197           while (*cp && *cp != '"')
198             {
199               vec_add1 (v, *cp);
200               cp++;
201             }
202           if (*cp == 0)
203             {
204               vec_free (nvp->name);
205               vec_free (v);
206               goto error;
207             }
208           vec_add1 (v, 0);
209           nvp->value = v;
210           vec_add1 (nvps, nvp);
211           while (*cp && *cp != ',' && *cp != '}')
212             cp++;
213           if (*cp == 0)
214             {
215               vec_free (nvp->name);
216               vec_free (nvp->value);
217               goto error;
218             }
219           else if (*cp == '}')
220             state = STATE_START;
221           else
222             {
223               cp++;
224               state = STATE_READ_NAME;
225             }
226           nvp = 0;
227           goto again;
228         }
229     }
230
231 done:
232   return (ht);
233 }
234
235 /*
236  * fd.io coding-style-patch-verification: ON
237  *
238  * Local Variables:
239  * eval: (c-set-style "gnu")
240  * End:
241  */