mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-15 22:29:38 +00:00
515 lines
11 KiB
C++
515 lines
11 KiB
C++
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "config.h"
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include "Filter.h"
|
|
#include "util.h"
|
|
#include "i18n.h"
|
|
#include "data_pckts.h"
|
|
#include "StringBuilder.h"
|
|
#include "Experiment.h"
|
|
|
|
|
|
// ========================================================================
|
|
// Subclass: FilterNumeric
|
|
// Public Methods
|
|
|
|
FilterNumeric::FilterNumeric (Experiment *_exp, const char *_cmd,
|
|
const char *_name)
|
|
{
|
|
exp = _exp;
|
|
cmd = dbe_strdup (_cmd);
|
|
name = dbe_strdup (_name);
|
|
pattern = NULL;
|
|
status = NULL;
|
|
items = NULL;
|
|
prop_name = NULL;
|
|
first = (uint64_t) - 1;
|
|
last = (uint64_t) - 1;
|
|
nselected = 0;
|
|
nitems = 0;
|
|
}
|
|
|
|
FilterNumeric::~FilterNumeric ()
|
|
{
|
|
free (cmd);
|
|
free (name);
|
|
free (pattern);
|
|
free (status);
|
|
Destroy (items);
|
|
}
|
|
|
|
// sets min and max for this filter; should be called when the range is
|
|
// known -- that comes after the first PathTree build, in the current
|
|
// sequence of things
|
|
void
|
|
FilterNumeric::set_range (uint64_t findex, uint64_t lindex, uint64_t total)
|
|
{
|
|
if (first == findex && last == lindex)
|
|
return;
|
|
first = findex;
|
|
last = lindex;
|
|
nitems = total;
|
|
nselected = nitems;
|
|
if (pattern)
|
|
{
|
|
free (pattern);
|
|
pattern = NULL;
|
|
}
|
|
if (status)
|
|
{
|
|
free (status);
|
|
status = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
FilterNumeric::update_range ()
|
|
{
|
|
if (exp == NULL)
|
|
return;
|
|
if (streq (cmd, NTXT ("sample")))
|
|
set_range (1, (uint64_t) exp->nsamples (), exp->nsamples ());
|
|
else if (streq (cmd, NTXT ("thread")))
|
|
set_range (exp->min_thread, exp->max_thread, exp->thread_cnt);
|
|
else if (streq (cmd, NTXT ("LWP")))
|
|
set_range (exp->min_lwp, exp->max_lwp, exp->lwp_cnt);
|
|
else if (streq (cmd, NTXT ("cpu")))
|
|
{
|
|
if (exp->min_cpu != (uint64_t) - 1)
|
|
set_range (exp->min_cpu, exp->max_cpu, exp->cpu_cnt);
|
|
}
|
|
}
|
|
|
|
// get_advanced_filter -- returns a string matching the current setting
|
|
char *
|
|
FilterNumeric::get_advanced_filter ()
|
|
{
|
|
if (items == NULL)
|
|
return NULL;
|
|
if (items->size () == 0)
|
|
return dbe_strdup (NTXT ("0"));
|
|
|
|
StringBuilder sb;
|
|
if (items->size () > 1)
|
|
sb.append ('(');
|
|
for (int i = 0; i < items->size (); i++)
|
|
{
|
|
RangePair *rp = items->fetch (i);
|
|
if (i > 0)
|
|
sb.append (NTXT (" || "));
|
|
sb.append ('(');
|
|
sb.append (prop_name);
|
|
if (rp->first == rp->last)
|
|
{
|
|
sb.append (NTXT ("=="));
|
|
sb.append ((long long) rp->first);
|
|
}
|
|
else
|
|
{
|
|
sb.append (NTXT (">="));
|
|
sb.append ((long long) rp->first);
|
|
sb.append (NTXT (" && "));
|
|
sb.append (prop_name);
|
|
sb.append (NTXT ("<="));
|
|
sb.append ((long long) rp->last);
|
|
}
|
|
sb.append (')');
|
|
}
|
|
if (items->size () > 1)
|
|
sb.append (')');
|
|
return sb.toString ();
|
|
}
|
|
|
|
|
|
// get_pattern -- returns a string matching the current setting
|
|
|
|
char *
|
|
FilterNumeric::get_pattern ()
|
|
{
|
|
update_range ();
|
|
if (pattern)
|
|
return pattern;
|
|
StringBuilder sb;
|
|
if (items == NULL)
|
|
{
|
|
if (last == (uint64_t) - 1 && last == first)
|
|
// neither set; data not available
|
|
sb.append (GTXT ("(data not recorded)"));
|
|
else
|
|
sb.append (GTXT ("all"));
|
|
}
|
|
else if (items->size () == 0)
|
|
sb.append (GTXT ("none"));
|
|
else
|
|
{
|
|
for (int i = 0; i < items->size (); i++)
|
|
{
|
|
RangePair *rp = items->fetch (i);
|
|
if (i > 0)
|
|
sb.append (',');
|
|
sb.append ((long long) rp->first);
|
|
if (rp->first != rp->last)
|
|
{
|
|
sb.append ('-');
|
|
sb.append ((long long) rp->last);
|
|
}
|
|
}
|
|
}
|
|
pattern = sb.toString ();
|
|
return pattern;
|
|
}
|
|
|
|
char *
|
|
FilterNumeric::get_status ()
|
|
{
|
|
update_range ();
|
|
if (status == NULL)
|
|
update_status ();
|
|
return dbe_strdup (status);
|
|
}
|
|
|
|
// set_pattern -- set the filter to a new pattern
|
|
// set error true/false if there was or was not an error parsing string
|
|
// Returns true/false if the filter changed, implying a rebuild of data
|
|
bool
|
|
FilterNumeric::set_pattern (char *str, bool *error)
|
|
{
|
|
update_range ();
|
|
// save the old filter
|
|
Vector<RangePair *> *olditems = items;
|
|
*error = false;
|
|
if (strcmp (str, NTXT ("all")) == 0)
|
|
// if all, leave items NULL
|
|
items = NULL;
|
|
else if (strcmp (str, NTXT ("none")) == 0)
|
|
// if none, leave items as a zero-length vector
|
|
items = new Vector<RangePair *>(0);
|
|
else
|
|
{
|
|
uint64_t val, val2;
|
|
char *s = str;
|
|
char *nexts = s;
|
|
items = NULL;
|
|
for (bool done = false; done == false;)
|
|
{
|
|
// tokenize the string
|
|
// Does it start with a "-" ?
|
|
if (*nexts == '-')
|
|
val = first; // yes, set val to first, and see what follows
|
|
else
|
|
{
|
|
// it must start with a number
|
|
val = get_next_number (s, &nexts, error);
|
|
if (*error == true)
|
|
break;
|
|
}
|
|
|
|
// look at the next character
|
|
switch (*nexts)
|
|
{
|
|
case ',':
|
|
s = ++nexts;
|
|
*error = include_range (val, val);
|
|
if (*error == true)
|
|
done = true;
|
|
break;
|
|
case '-':
|
|
s = ++nexts;
|
|
if (*nexts == ',' || *nexts == '\0')
|
|
val2 = last;
|
|
else
|
|
{
|
|
val2 = get_next_number (s, &nexts, error);
|
|
if (*error == true)
|
|
{
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
if (val > val2)
|
|
{
|
|
*error = true;
|
|
done = true;
|
|
break;
|
|
}
|
|
*error = include_range (val, val2);
|
|
if (*error == true)
|
|
{
|
|
done = true;
|
|
break;
|
|
}
|
|
if (*nexts == ',')
|
|
{
|
|
s = ++nexts;
|
|
break;
|
|
}
|
|
if (*nexts == '\0')
|
|
{
|
|
done = true;
|
|
break;
|
|
}
|
|
break;
|
|
case '\0':
|
|
*error = include_range (val, val);
|
|
done = true;
|
|
break;
|
|
default:
|
|
*error = true;
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
// if there was a parser error leave old setting
|
|
if (*error == true)
|
|
{
|
|
if (items)
|
|
{
|
|
items->destroy ();
|
|
delete items;
|
|
}
|
|
items = olditems;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (first != (uint64_t) - 1 && last != (uint64_t) - 1)
|
|
{
|
|
for (long i = VecSize (items) - 1; i >= 0; i--)
|
|
{
|
|
RangePair *rp = items->get (i);
|
|
if ((rp->first > last) || (rp->last < first))
|
|
{
|
|
delete rp;
|
|
items->remove (i);
|
|
continue;
|
|
}
|
|
if (rp->first < first)
|
|
rp->first = first;
|
|
if (rp->last > last)
|
|
rp->last = last;
|
|
}
|
|
if (VecSize (items) == 1)
|
|
{
|
|
RangePair *rp = items->get (0);
|
|
if ((rp->first == first) && (rp->last == last))
|
|
{
|
|
// All, leave items NULL
|
|
items->destroy ();
|
|
delete items;
|
|
items = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// no error, delete the old setting
|
|
if (olditems != NULL)
|
|
{
|
|
olditems->destroy ();
|
|
delete olditems;
|
|
}
|
|
|
|
bool changed;
|
|
// regenerate the pattern
|
|
if (pattern == NULL)
|
|
changed = true;
|
|
else
|
|
{
|
|
char *oldpattern = pattern;
|
|
pattern = NULL; // to force a recompute with new values
|
|
(void) get_pattern ();
|
|
changed = strcmp (pattern, oldpattern) != 0;
|
|
free (oldpattern);
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
//================================================================
|
|
// Protected methods
|
|
|
|
// set_status -- regenerate the status line, describing the current setting
|
|
void
|
|
FilterNumeric::update_status ()
|
|
{
|
|
// regenerate the status line
|
|
free (status);
|
|
nselected = 0;
|
|
if (items == NULL)
|
|
{
|
|
if (last == (uint64_t) - 1 && last == first)
|
|
// neither set; data not available
|
|
status = dbe_sprintf (GTXT ("(data not recorded)"));
|
|
else if (first == (uint64_t) - 1 || last == (uint64_t) - 1)
|
|
// range was not set
|
|
status = dbe_sprintf (GTXT ("(all)"));
|
|
else
|
|
// range was set, compute percentage
|
|
status = dbe_sprintf (GTXT ("total %lld, range: %lld-%lld"),
|
|
(long long) nitems, (long long) first,
|
|
(long long) last);
|
|
}
|
|
else
|
|
{
|
|
// some are selected
|
|
int index;
|
|
RangePair *rp;
|
|
Vec_loop (RangePair *, items, index, rp)
|
|
{
|
|
nselected += rp->last - rp->first + 1;
|
|
}
|
|
if (last == (uint64_t) - 1)
|
|
// range was not set
|
|
status = dbe_sprintf (GTXT ("(%lld items selected)"),
|
|
(long long) nselected);
|
|
else
|
|
// range was set
|
|
status = dbe_sprintf (GTXT ("total %lld, range: %lld-%lld"),
|
|
(long long) nitems, (long long) first,
|
|
(long long) last);
|
|
}
|
|
}
|
|
|
|
// Add a range to the filter; called from set_pattern for each index,
|
|
// or index pair
|
|
bool
|
|
FilterNumeric::include_range (uint64_t findex, uint64_t lindex)
|
|
{
|
|
int index;
|
|
RangePair *rp;
|
|
if (findex > lindex)
|
|
return true;
|
|
|
|
bool done = false;
|
|
if (items == NULL)
|
|
items = new Vector<RangePair *>(0);
|
|
|
|
Vec_loop (RangePair *, items, index, rp)
|
|
{
|
|
if (findex < rp->first)
|
|
{
|
|
// Case where the new pair starts before the old
|
|
if (lindex + 1 < rp->first)
|
|
{
|
|
// this pair comes cleanly in front of the current item
|
|
RangePair *rp2 = new RangePair ();
|
|
rp2->first = findex;
|
|
rp2->last = lindex;
|
|
items->insert (index, rp2);
|
|
done = true;
|
|
break;
|
|
}
|
|
// This new one extends the previous from the front
|
|
rp->first = findex;
|
|
chkextend:
|
|
if (lindex <= rp->last)
|
|
{
|
|
// but does not extend the back
|
|
done = true;
|
|
break;
|
|
}
|
|
// extend this one out
|
|
rp->last = lindex;
|
|
|
|
// does it go into the next range?
|
|
if (index == items->size () - 1)
|
|
{
|
|
// this is the last range, so it does not
|
|
done = true;
|
|
break;
|
|
}
|
|
RangePair *next = items->fetch (index + 1);
|
|
if (lindex + 1 < next->first)
|
|
{
|
|
// no extension, we're done
|
|
done = true;
|
|
break;
|
|
}
|
|
// it does extend the next one
|
|
next->first = rp->first;
|
|
rp = next;
|
|
// remove the current one, promoting next
|
|
items->remove (index);
|
|
goto chkextend;
|
|
}
|
|
else if (findex > rp->last + 1)
|
|
// the new one is completely beyond the current
|
|
continue;
|
|
else
|
|
{
|
|
// the new one may start at or after the current, but it
|
|
// extends it out; set the current
|
|
// this pair overlaps the current item
|
|
// rp-> first is OK -- it's equal or less than findex
|
|
goto chkextend;
|
|
}
|
|
}
|
|
|
|
if (done != true)
|
|
{
|
|
// fall through -- append to list
|
|
rp = new RangePair ();
|
|
rp->first = findex;
|
|
rp->last = lindex;
|
|
items->append (rp);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Scan the filter to see if the number given is filtered in or out
|
|
// return true if number is in, false if it's out
|
|
bool
|
|
FilterNumeric::is_selected (uint64_t number)
|
|
{
|
|
int index;
|
|
RangePair *rp;
|
|
if (items == NULL)
|
|
return true;
|
|
if (items->size () == 0)
|
|
return false;
|
|
|
|
Vec_loop (RangePair *, items, index, rp)
|
|
{
|
|
if (number >= rp->first && number <= rp->last)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// get_next_number
|
|
// Called from parser to extract a number from the current string position
|
|
// Sets fail true if there was an error, false otherwise
|
|
// returns the number as parsed
|
|
uint64_t
|
|
FilterNumeric::get_next_number (char *s, char **e, bool *fail)
|
|
{
|
|
errno = 0;
|
|
*fail = false;
|
|
uint64_t val = strtoll (s, e, 10);
|
|
if (errno == EINVAL)
|
|
*fail = true;
|
|
return (val);
|
|
}
|