Merge branch 'perf/test' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/random-tracing into perf/core
This commit is contained in:
@ -98,7 +98,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
|
||||
self->unknown_events = 0;
|
||||
self->machines = RB_ROOT;
|
||||
self->repipe = repipe;
|
||||
self->ordered_samples.flush_limit = ULLONG_MAX;
|
||||
INIT_LIST_HEAD(&self->ordered_samples.samples_head);
|
||||
machine__init(&self->host_machine, "", HOST_KERNEL_ID);
|
||||
|
||||
@ -195,6 +194,18 @@ static int process_event_stub(event_t *event __used,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_finished_round_stub(event_t *event __used,
|
||||
struct perf_session *session __used,
|
||||
struct perf_event_ops *ops __used)
|
||||
{
|
||||
dump_printf(": unhandled!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_finished_round(event_t *event,
|
||||
struct perf_session *session,
|
||||
struct perf_event_ops *ops);
|
||||
|
||||
static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
|
||||
{
|
||||
if (handler->sample == NULL)
|
||||
@ -223,6 +234,12 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
|
||||
handler->tracing_data = process_event_stub;
|
||||
if (handler->build_id == NULL)
|
||||
handler->build_id = process_event_stub;
|
||||
if (handler->finished_round == NULL) {
|
||||
if (handler->ordered_samples)
|
||||
handler->finished_round = process_finished_round;
|
||||
else
|
||||
handler->finished_round = process_finished_round_stub;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *event__name[] = {
|
||||
@ -360,16 +377,14 @@ struct sample_queue {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define FLUSH_PERIOD (2 * NSEC_PER_SEC)
|
||||
|
||||
static void flush_sample_queue(struct perf_session *s,
|
||||
struct perf_event_ops *ops)
|
||||
{
|
||||
struct list_head *head = &s->ordered_samples.samples_head;
|
||||
u64 limit = s->ordered_samples.flush_limit;
|
||||
u64 limit = s->ordered_samples.next_flush;
|
||||
struct sample_queue *tmp, *iter;
|
||||
|
||||
if (!ops->ordered_samples)
|
||||
if (!ops->ordered_samples || !limit)
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe(iter, tmp, head, list) {
|
||||
@ -388,6 +403,55 @@ static void flush_sample_queue(struct perf_session *s,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When perf record finishes a pass on every buffers, it records this pseudo
|
||||
* event.
|
||||
* We record the max timestamp t found in the pass n.
|
||||
* Assuming these timestamps are monotonic across cpus, we know that if
|
||||
* a buffer still has events with timestamps below t, they will be all
|
||||
* available and then read in the pass n + 1.
|
||||
* Hence when we start to read the pass n + 2, we can safely flush every
|
||||
* events with timestamps below t.
|
||||
*
|
||||
* ============ PASS n =================
|
||||
* CPU 0 | CPU 1
|
||||
* |
|
||||
* cnt1 timestamps | cnt2 timestamps
|
||||
* 1 | 2
|
||||
* 2 | 3
|
||||
* - | 4 <--- max recorded
|
||||
*
|
||||
* ============ PASS n + 1 ==============
|
||||
* CPU 0 | CPU 1
|
||||
* |
|
||||
* cnt1 timestamps | cnt2 timestamps
|
||||
* 3 | 5
|
||||
* 4 | 6
|
||||
* 5 | 7 <---- max recorded
|
||||
*
|
||||
* Flush every events below timestamp 4
|
||||
*
|
||||
* ============ PASS n + 2 ==============
|
||||
* CPU 0 | CPU 1
|
||||
* |
|
||||
* cnt1 timestamps | cnt2 timestamps
|
||||
* 6 | 8
|
||||
* 7 | 9
|
||||
* - | 10
|
||||
*
|
||||
* Flush every events below timestamp 7
|
||||
* etc...
|
||||
*/
|
||||
static int process_finished_round(event_t *event __used,
|
||||
struct perf_session *session,
|
||||
struct perf_event_ops *ops)
|
||||
{
|
||||
flush_sample_queue(session, ops);
|
||||
session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __queue_sample_end(struct sample_queue *new, struct list_head *head)
|
||||
{
|
||||
struct sample_queue *iter;
|
||||
@ -456,17 +520,12 @@ static void __queue_sample_event(struct sample_queue *new,
|
||||
}
|
||||
|
||||
static int queue_sample_event(event_t *event, struct sample_data *data,
|
||||
struct perf_session *s,
|
||||
struct perf_event_ops *ops)
|
||||
struct perf_session *s)
|
||||
{
|
||||
u64 timestamp = data->time;
|
||||
struct sample_queue *new;
|
||||
u64 flush_limit;
|
||||
|
||||
|
||||
if (s->ordered_samples.flush_limit == ULLONG_MAX)
|
||||
s->ordered_samples.flush_limit = timestamp + FLUSH_PERIOD;
|
||||
|
||||
if (timestamp < s->ordered_samples.last_flush) {
|
||||
printf("Warning: Timestamp below last timeslice flush\n");
|
||||
return -EINVAL;
|
||||
@ -489,23 +548,8 @@ static int queue_sample_event(event_t *event, struct sample_data *data,
|
||||
__queue_sample_event(new, s);
|
||||
s->ordered_samples.last_inserted = new;
|
||||
|
||||
/*
|
||||
* We want to have a slice of events covering 2 * FLUSH_PERIOD
|
||||
* If FLUSH_PERIOD is big enough, it ensures every events that occured
|
||||
* in the first half of the timeslice have all been buffered and there
|
||||
* are none remaining (we need that because of the weakly ordered
|
||||
* event recording we have). Then once we reach the 2 * FLUSH_PERIOD
|
||||
* timeslice, we flush the first half to be gentle with the memory
|
||||
* (the second half can still get new events in the middle, so wait
|
||||
* another period to flush it)
|
||||
*/
|
||||
flush_limit = s->ordered_samples.flush_limit;
|
||||
|
||||
if (new->timestamp > flush_limit &&
|
||||
new->timestamp - flush_limit > FLUSH_PERIOD) {
|
||||
s->ordered_samples.flush_limit += FLUSH_PERIOD;
|
||||
flush_sample_queue(s, ops);
|
||||
}
|
||||
if (new->timestamp > s->ordered_samples.max_timestamp)
|
||||
s->ordered_samples.max_timestamp = new->timestamp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -521,7 +565,7 @@ static int perf_session__process_sample(event_t *event, struct perf_session *s,
|
||||
bzero(&data, sizeof(struct sample_data));
|
||||
event__parse_sample(event, s->sample_type, &data);
|
||||
|
||||
queue_sample_event(event, &data, s, ops);
|
||||
queue_sample_event(event, &data, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -573,6 +617,8 @@ static int perf_session__process_event(struct perf_session *self,
|
||||
return ops->tracing_data(event, self);
|
||||
case PERF_RECORD_HEADER_BUILD_ID:
|
||||
return ops->build_id(event, self);
|
||||
case PERF_RECORD_FINISHED_ROUND:
|
||||
return ops->finished_round(event, self, ops);
|
||||
default:
|
||||
self->unknown_events++;
|
||||
return -1;
|
||||
@ -651,15 +697,18 @@ more:
|
||||
p = &event;
|
||||
p += sizeof(struct perf_event_header);
|
||||
|
||||
err = do_read(self->fd, p, size - sizeof(struct perf_event_header));
|
||||
if (err <= 0) {
|
||||
if (err == 0) {
|
||||
pr_err("unexpected end of event stream\n");
|
||||
goto done;
|
||||
}
|
||||
if (size - sizeof(struct perf_event_header)) {
|
||||
err = do_read(self->fd, p,
|
||||
size - sizeof(struct perf_event_header));
|
||||
if (err <= 0) {
|
||||
if (err == 0) {
|
||||
pr_err("unexpected end of event stream\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
pr_err("failed to read event data\n");
|
||||
goto out_err;
|
||||
pr_err("failed to read event data\n");
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (size == 0 ||
|
||||
@ -787,7 +836,7 @@ more:
|
||||
done:
|
||||
err = 0;
|
||||
/* do the final flush for ordered samples */
|
||||
self->ordered_samples.flush_limit = ULLONG_MAX;
|
||||
self->ordered_samples.next_flush = ULLONG_MAX;
|
||||
flush_sample_queue(self, ops);
|
||||
out_err:
|
||||
ui_progress__delete(progress);
|
||||
|
Reference in New Issue
Block a user