]> Git Repo - binutils.git/blob - gprofng/src/Filter.cc
Automatic date update in version.in
[binutils.git] / gprofng / src / Filter.cc
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3
4    This file is part of GNU Binutils.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10
11    This program 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
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20
21 #include "config.h"
22 #include <ctype.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <errno.h>
27 #include "Filter.h"
28 #include "util.h"
29 #include "i18n.h"
30 #include "data_pckts.h"
31 #include "StringBuilder.h"
32 #include "Experiment.h"
33
34
35 // ========================================================================
36 // Subclass: FilterNumeric
37 // Public Methods
38
39 FilterNumeric::FilterNumeric (Experiment *_exp, const char *_cmd,
40                               const char *_name)
41 {
42   exp = _exp;
43   cmd = dbe_strdup (_cmd);
44   name = dbe_strdup (_name);
45   pattern = NULL;
46   status = NULL;
47   items = NULL;
48   prop_name = NULL;
49   first = (uint64_t) - 1;
50   last = (uint64_t) - 1;
51   nselected = 0;
52   nitems = 0;
53 }
54
55 FilterNumeric::~FilterNumeric ()
56 {
57   free (cmd);
58   free (name);
59   free (pattern);
60   free (status);
61   Destroy (items);
62 }
63
64 // sets min and max for this filter; should be called when the range is
65 //      known -- that comes after the first PathTree build, in the current
66 //      sequence of things
67 void
68 FilterNumeric::set_range (uint64_t findex, uint64_t lindex, uint64_t total)
69 {
70   if (first == findex && last == lindex)
71     return;
72   first = findex;
73   last = lindex;
74   nitems = total;
75   nselected = nitems;
76   if (pattern)
77     {
78       free (pattern);
79       pattern = NULL;
80     }
81   if (status)
82     {
83       free (status);
84       status = NULL;
85     }
86 }
87
88 void
89 FilterNumeric::update_range ()
90 {
91   if (exp == NULL)
92     return;
93   if (streq (cmd, NTXT ("sample")))
94     set_range (1, (uint64_t) exp->nsamples (), exp->nsamples ());
95   else if (streq (cmd, NTXT ("thread")))
96     set_range (exp->min_thread, exp->max_thread, exp->thread_cnt);
97   else if (streq (cmd, NTXT ("LWP")))
98     set_range (exp->min_lwp, exp->max_lwp, exp->lwp_cnt);
99   else if (streq (cmd, NTXT ("cpu")))
100     {
101       if (exp->min_cpu != (uint64_t) - 1)
102         set_range (exp->min_cpu, exp->max_cpu, exp->cpu_cnt);
103     }
104 }
105
106 // get_advanced_filter -- returns a string matching the current setting
107 char *
108 FilterNumeric::get_advanced_filter ()
109 {
110   if (items == NULL)
111     return NULL;
112   if (items->size () == 0)
113     return dbe_strdup (NTXT ("0"));
114
115   StringBuilder sb;
116   if (items->size () > 1)
117     sb.append ('(');
118   for (int i = 0; i < items->size (); i++)
119     {
120       RangePair *rp = items->fetch (i);
121       if (i > 0)
122         sb.append (NTXT (" || "));
123       sb.append ('(');
124       sb.append (prop_name);
125       if (rp->first == rp->last)
126         {
127           sb.append (NTXT ("=="));
128           sb.append ((long long) rp->first);
129         }
130       else
131         {
132           sb.append (NTXT (">="));
133           sb.append ((long long) rp->first);
134           sb.append (NTXT (" && "));
135           sb.append (prop_name);
136           sb.append (NTXT ("<="));
137           sb.append ((long long) rp->last);
138         }
139       sb.append (')');
140     }
141   if (items->size () > 1)
142     sb.append (')');
143   return sb.toString ();
144 }
145
146
147 // get_pattern -- returns a string matching the current setting
148
149 char *
150 FilterNumeric::get_pattern ()
151 {
152   update_range ();
153   if (pattern)
154     return pattern;
155   StringBuilder sb;
156   if (items == NULL)
157     {
158       if (last == (uint64_t) - 1 && last == first)
159         // neither set; data not available
160         sb.append (GTXT ("(data not recorded)"));
161       else
162         sb.append (GTXT ("all"));
163     }
164   else if (items->size () == 0)
165     sb.append (GTXT ("none"));
166   else
167     {
168       for (int i = 0; i < items->size (); i++)
169         {
170           RangePair *rp = items->fetch (i);
171           if (i > 0)
172             sb.append (',');
173           sb.append ((long long) rp->first);
174           if (rp->first != rp->last)
175             {
176               sb.append ('-');
177               sb.append ((long long) rp->last);
178             }
179         }
180     }
181   pattern = sb.toString ();
182   return pattern;
183 }
184
185 char *
186 FilterNumeric::get_status ()
187 {
188   update_range ();
189   if (status == NULL)
190     update_status ();
191   return dbe_strdup (status);
192 }
193
194 // set_pattern -- set the filter to a new pattern
195 //      set error true/false if there was or was not an error parsing string
196 //      Returns true/false if the filter changed, implying a rebuild of data
197 bool
198 FilterNumeric::set_pattern (char *str, bool *error)
199 {
200   update_range ();
201   // save the old filter
202   Vector<RangePair *> *olditems = items;
203   *error = false;
204   if (strcmp (str, NTXT ("all")) == 0)
205     // if all, leave items NULL
206     items = NULL;
207   else if (strcmp (str, NTXT ("none")) == 0)
208     // if none, leave items as a zero-length vector
209     items = new Vector<RangePair *>(0);
210   else
211     {
212       uint64_t val, val2;
213       char *s = str;
214       char *nexts = s;
215       items = NULL;
216       for (bool done = false; done == false;)
217         {
218           // tokenize the string
219           // Does it start with a "-" ?
220           if (*nexts == '-')
221             val = first; // yes, set val to first, and see what follows
222           else
223             {
224               // it must start with a number
225               val = get_next_number (s, &nexts, error);
226               if (*error == true)
227                 break;
228             }
229
230           // look at the next character
231           switch (*nexts)
232             {
233             case ',':
234               s = ++nexts;
235               *error = include_range (val, val);
236               if (*error == true)
237                 done = true;
238               break;
239             case '-':
240               s = ++nexts;
241               if (*nexts == ',' || *nexts == '\0')
242                 val2 = last;
243               else
244                 {
245                   val2 = get_next_number (s, &nexts, error);
246                   if (*error == true)
247                     {
248                       done = true;
249                       break;
250                     }
251                 }
252               if (val > val2)
253                 {
254                   *error = true;
255                   done = true;
256                   break;
257                 }
258               *error = include_range (val, val2);
259               if (*error == true)
260                 {
261                   done = true;
262                   break;
263                 }
264               if (*nexts == ',')
265                 {
266                   s = ++nexts;
267                   break;
268                 }
269               if (*nexts == '\0')
270                 {
271                   done = true;
272                   break;
273                 }
274               break;
275             case '\0':
276               *error = include_range (val, val);
277               done = true;
278               break;
279             default:
280               *error = true;
281               done = true;
282               break;
283             }
284         }
285       // if there was a parser error leave old setting
286       if (*error == true)
287         {
288           if (items)
289             {
290               items->destroy ();
291               delete items;
292             }
293           items = olditems;
294           return false;
295         }
296     }
297
298   if (first != (uint64_t) - 1 && last != (uint64_t) - 1)
299     {
300       for (long i = VecSize (items) - 1; i >= 0; i--)
301         {
302           RangePair *rp = items->get (i);
303           if ((rp->first > last) || (rp->last < first))
304             {
305               delete rp;
306               items->remove (i);
307               continue;
308             }
309           if (rp->first < first)
310             rp->first = first;
311           if (rp->last > last)
312             rp->last = last;
313         }
314       if (VecSize (items) == 1)
315         {
316           RangePair *rp = items->get (0);
317           if ((rp->first == first) && (rp->last == last))
318             {
319               // All, leave items NULL
320               items->destroy ();
321               delete items;
322               items = NULL;
323             }
324         }
325     }
326
327   // no error, delete the old setting
328   if (olditems != NULL)
329     {
330       olditems->destroy ();
331       delete olditems;
332     }
333
334   bool changed;
335   // regenerate the pattern
336   if (pattern == NULL)
337     changed = true;
338   else
339     {
340       char *oldpattern = pattern;
341       pattern = NULL; // to force a recompute with new values
342       (void) get_pattern ();
343       changed = strcmp (pattern, oldpattern) != 0;
344       free (oldpattern);
345     }
346   return changed;
347 }
348
349 //================================================================
350 // Protected methods
351
352 // set_status -- regenerate the status line, describing the current setting
353 void
354 FilterNumeric::update_status ()
355 {
356   // regenerate the status line
357   free (status);
358   nselected = 0;
359   if (items == NULL)
360     {
361       if (last == (uint64_t) - 1 && last == first)
362         // neither set; data not available
363         status = dbe_sprintf (GTXT ("(data not recorded)"));
364       else if (first == (uint64_t) - 1 || last == (uint64_t) - 1)
365         // range was not set
366         status = dbe_sprintf (GTXT ("(all)"));
367       else
368         // range was set, compute percentage
369         status = dbe_sprintf (GTXT ("total %lld, range: %lld-%lld"),
370                               (long long) nitems, (long long) first,
371                               (long long) last);
372     }
373   else
374     {
375       // some are selected
376       int index;
377       RangePair *rp;
378       Vec_loop (RangePair *, items, index, rp)
379       {
380         nselected += rp->last - rp->first + 1;
381       }
382       if (last == (uint64_t) - 1)
383         // range was not set
384         status = dbe_sprintf (GTXT ("(%lld items selected)"),
385                               (long long) nselected);
386       else
387         // range was set
388         status = dbe_sprintf (GTXT ("total %lld, range: %lld-%lld"),
389                               (long long) nitems, (long long) first,
390                               (long long) last);
391     }
392 }
393
394 // Add a range to the filter; called from set_pattern for each index,
395 //      or index pair
396 bool
397 FilterNumeric::include_range (uint64_t findex, uint64_t lindex)
398 {
399   int index;
400   RangePair *rp;
401   if (findex > lindex)
402     return true;
403
404   bool done = false;
405   if (items == NULL)
406     items = new Vector<RangePair *>(0);
407
408   Vec_loop (RangePair *, items, index, rp)
409   {
410     if (findex < rp->first)
411       {
412         // Case where the new pair starts before the old
413         if (lindex + 1 < rp->first)
414           {
415             // this pair comes cleanly in front of the current item
416             RangePair *rp2 = new RangePair ();
417             rp2->first = findex;
418             rp2->last = lindex;
419             items->insert (index, rp2);
420             done = true;
421             break;
422           }
423         // This new one extends the previous from the front
424         rp->first = findex;
425 chkextend:
426         if (lindex <= rp->last)
427           {
428             // but does not extend the back
429             done = true;
430             break;
431           }
432         // extend this one out
433         rp->last = lindex;
434
435         // does it go into the next range?
436         if (index == items->size () - 1)
437           {
438             // this is the last range, so it does not
439             done = true;
440             break;
441           }
442         RangePair *next = items->fetch (index + 1);
443         if (lindex + 1 < next->first)
444           {
445             // no extension, we're done
446             done = true;
447             break;
448           }
449         // it does extend the next one
450         next->first = rp->first;
451         rp = next;
452         // remove the current one, promoting next
453         items->remove (index);
454         goto chkextend;
455       }
456     else if (findex > rp->last + 1)
457       // the new one is completely beyond the current
458       continue;
459     else
460       {
461         // the new one may start at or after the current, but it
462         // extends it out;  set the current
463         // this pair overlaps the current item
464         // rp-> first is OK -- it's equal or less than findex
465         goto chkextend;
466       }
467   }
468
469   if (done != true)
470     {
471       // fall through -- append to list
472       rp = new RangePair ();
473       rp->first = findex;
474       rp->last = lindex;
475       items->append (rp);
476     }
477
478   return false;
479 }
480
481 // Scan the filter to see if the number given is filtered in or out
482 //      return true if number is in, false if it's out
483 bool
484 FilterNumeric::is_selected (uint64_t number)
485 {
486   int index;
487   RangePair *rp;
488   if (items == NULL)
489     return true;
490   if (items->size () == 0)
491     return false;
492
493   Vec_loop (RangePair *, items, index, rp)
494   {
495     if (number >= rp->first && number <= rp->last)
496       return true;
497   }
498   return false;
499 }
500
501 // get_next_number
502 //      Called from parser to extract a number from the current string position
503 //      Sets fail true if there was an error, false otherwise
504 //      returns the number as parsed
505 uint64_t
506 FilterNumeric::get_next_number (char *s, char **e, bool *fail)
507 {
508   errno = 0;
509   *fail = false;
510   uint64_t val = strtoll (s, e, 10);
511   if (errno == EINVAL)
512     *fail = true;
513   return (val);
514 }
This page took 0.051376 seconds and 4 git commands to generate.