]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gprofng/src/Filter.cc
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gprofng / src / Filter.cc
1 /* Copyright (C) 2021-2024 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 }