btrace: Use function segment index in call iterator.

Remove FUNCTION pointer in struct btrace_call_iterator and use an index into
the list of function segments instead.
This commit is contained in:
Tim Wiederhake 2017-05-30 12:47:37 +02:00
parent 521103fd00
commit f158f20875
4 changed files with 101 additions and 119 deletions

View File

@ -1,3 +1,16 @@
2017-05-30 Tim Wiederhake <tim.wiederhake@intel.com>
* btrace.c (btrace_ends_with_single_insn): New function.
(btrace_call_get, btrace_call_number, btrace_call_begin,
btrace_call_end, btrace_call_next, btrace_call_prev,
btrace_find_call_by_number): Use index into call segment vector
instead of pointer.
(btrace_call_cmp): Simplify.
* btrace.h (struct btrace_call_iterator): Replace function call segment
pointer with index into vector.
* record-btrace.c (record_btrace_call_history): Use index instead of
pointer.
2017-05-30 Tim Wiederhake <tim.wiederhake@intel.com>
* btrace.c (btrace_insn_begin, btrace_insn_end,

View File

@ -2527,12 +2527,33 @@ btrace_find_insn_by_number (struct btrace_insn_iterator *it,
return 1;
}
/* Returns true if the recording ends with a function segment that
contains only a single (i.e. the current) instruction. */
static bool
btrace_ends_with_single_insn (const struct btrace_thread_info *btinfo)
{
const btrace_function *bfun;
if (btinfo->functions.empty ())
return false;
bfun = btinfo->functions.back ();
if (bfun->errcode != 0)
return false;
return ftrace_call_num_insn (bfun) == 1;
}
/* See btrace.h. */
const struct btrace_function *
btrace_call_get (const struct btrace_call_iterator *it)
{
return it->function;
if (it->index >= it->btinfo->functions.size ())
return NULL;
return it->btinfo->functions[it->index];
}
/* See btrace.h. */
@ -2540,28 +2561,14 @@ btrace_call_get (const struct btrace_call_iterator *it)
unsigned int
btrace_call_number (const struct btrace_call_iterator *it)
{
const struct btrace_thread_info *btinfo;
const struct btrace_function *bfun;
unsigned int insns;
const unsigned int length = it->btinfo->functions.size ();
btinfo = it->btinfo;
bfun = it->function;
if (bfun != NULL)
return bfun->number;
/* If the last function segment contains only a single instruction (i.e. the
current instruction), skip it. */
if ((it->index == length) && btrace_ends_with_single_insn (it->btinfo))
return length;
/* For the end iterator, i.e. bfun == NULL, we return one more than the
number of the last function. */
bfun = btinfo->end;
insns = VEC_length (btrace_insn_s, bfun->insn);
/* If the function contains only a single instruction (i.e. the current
instruction), it will be skipped and its number is already the number
we seek. */
if (insns == 1)
return bfun->number;
/* Otherwise, return one more than the number of the last function. */
return bfun->number + 1;
return it->index + 1;
}
/* See btrace.h. */
@ -2570,14 +2577,11 @@ void
btrace_call_begin (struct btrace_call_iterator *it,
const struct btrace_thread_info *btinfo)
{
const struct btrace_function *bfun;
bfun = btinfo->begin;
if (bfun == NULL)
if (btinfo->functions.empty ())
error (_("No trace."));
it->btinfo = btinfo;
it->function = bfun;
it->index = 0;
}
/* See btrace.h. */
@ -2586,14 +2590,11 @@ void
btrace_call_end (struct btrace_call_iterator *it,
const struct btrace_thread_info *btinfo)
{
const struct btrace_function *bfun;
bfun = btinfo->end;
if (bfun == NULL)
if (btinfo->functions.empty ())
error (_("No trace."));
it->btinfo = btinfo;
it->function = NULL;
it->index = btinfo->functions.size ();
}
/* See btrace.h. */
@ -2601,35 +2602,35 @@ btrace_call_end (struct btrace_call_iterator *it,
unsigned int
btrace_call_next (struct btrace_call_iterator *it, unsigned int stride)
{
const struct btrace_function *bfun;
unsigned int steps;
const unsigned int length = it->btinfo->functions.size ();
bfun = it->function;
steps = 0;
while (bfun != NULL)
if (it->index + stride < length - 1)
/* Default case: Simply advance the iterator. */
it->index += stride;
else if (it->index + stride == length - 1)
{
const struct btrace_function *next;
unsigned int insns;
/* We land exactly at the last function segment. If it contains only one
instruction (i.e. the current instruction) it is not actually part of
the trace. */
if (btrace_ends_with_single_insn (it->btinfo))
it->index = length;
else
it->index = length - 1;
}
else
{
/* We land past the last function segment and have to adjust the stride.
If the last function segment contains only one instruction (i.e. the
current instruction) it is not actually part of the trace. */
if (btrace_ends_with_single_insn (it->btinfo))
stride = length - it->index - 1;
else
stride = length - it->index;
next = bfun->flow.next;
if (next == NULL)
{
/* Ignore the last function if it only contains a single
(i.e. the current) instruction. */
insns = VEC_length (btrace_insn_s, bfun->insn);
if (insns == 1)
steps -= 1;
}
if (stride == steps)
break;
bfun = next;
steps += 1;
it->index = length;
}
it->function = bfun;
return steps;
return stride;
}
/* See btrace.h. */
@ -2637,48 +2638,33 @@ btrace_call_next (struct btrace_call_iterator *it, unsigned int stride)
unsigned int
btrace_call_prev (struct btrace_call_iterator *it, unsigned int stride)
{
const struct btrace_thread_info *btinfo;
const struct btrace_function *bfun;
unsigned int steps;
const unsigned int length = it->btinfo->functions.size ();
int steps = 0;
bfun = it->function;
steps = 0;
gdb_assert (it->index <= length);
if (bfun == NULL)
if (stride == 0 || it->index == 0)
return 0;
/* If we are at the end, the first step is a special case. If the last
function segment contains only one instruction (i.e. the current
instruction) it is not actually part of the trace. To be able to step
over this instruction, we need at least one more function segment. */
if ((it->index == length) && (length > 1))
{
unsigned int insns;
if (btrace_ends_with_single_insn (it->btinfo))
it->index = length - 2;
else
it->index = length - 1;
btinfo = it->btinfo;
bfun = btinfo->end;
if (bfun == NULL)
return 0;
/* Ignore the last function if it only contains a single
(i.e. the current) instruction. */
insns = VEC_length (btrace_insn_s, bfun->insn);
if (insns == 1)
bfun = bfun->flow.prev;
if (bfun == NULL)
return 0;
steps += 1;
steps = 1;
stride -= 1;
}
while (steps < stride)
{
const struct btrace_function *prev;
stride = std::min (stride, it->index);
prev = bfun->flow.prev;
if (prev == NULL)
break;
bfun = prev;
steps += 1;
}
it->function = bfun;
return steps;
it->index -= stride;
return steps + stride;
}
/* See btrace.h. */
@ -2687,12 +2673,8 @@ int
btrace_call_cmp (const struct btrace_call_iterator *lhs,
const struct btrace_call_iterator *rhs)
{
unsigned int lnum, rnum;
lnum = btrace_call_number (lhs);
rnum = btrace_call_number (rhs);
return (int) (lnum - rnum);
gdb_assert (lhs->btinfo == rhs->btinfo);
return (int) (lhs->index - rhs->index);
}
/* See btrace.h. */
@ -2702,26 +2684,14 @@ btrace_find_call_by_number (struct btrace_call_iterator *it,
const struct btrace_thread_info *btinfo,
unsigned int number)
{
const struct btrace_function *bfun;
const unsigned int length = btinfo->functions.size ();
for (bfun = btinfo->end; bfun != NULL; bfun = bfun->flow.prev)
{
unsigned int bnum;
if ((number == 0) || (number > length))
return 0;
bnum = bfun->number;
if (number == bnum)
{
it->btinfo = btinfo;
it->function = bfun;
return 1;
}
/* Functions are ordered and numbered consecutively. We could bail out
earlier. On the other hand, it is very unlikely that we search for
a nonexistent function. */
}
return 0;
it->btinfo = btinfo;
it->index = number - 1;
return 1;
}
/* See btrace.h. */

View File

@ -172,7 +172,7 @@ struct btrace_function
segment in control-flow order. */
unsigned int insn_offset;
/* The function number in control-flow order.
/* The 1-based function number in control-flow order.
If INSN is empty indicating a gap in the trace due to a decode error,
we still count the gap as a function. */
unsigned int number;
@ -209,9 +209,8 @@ struct btrace_call_iterator
/* The branch trace information for this thread. Will never be NULL. */
const struct btrace_thread_info *btinfo;
/* The branch trace function segment.
This will be NULL for the iterator pointing to the end of the trace. */
const struct btrace_function *function;
/* The index of the function segment in BTINFO->FUNCTIONS. */
unsigned int index;
};
/* Branch trace iteration state for "record instruction-history". */

View File

@ -1101,8 +1101,8 @@ record_btrace_call_history (struct target_ops *self, int size, int int_flags)
replay = btinfo->replay;
if (replay != NULL)
{
begin.function = replay->function;
begin.btinfo = btinfo;
begin.index = replay->function->number - 1;
}
else
btrace_call_end (&begin, btinfo);