Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 87 additions & 35 deletions src/perf.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <sys/ioctl.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>

#include "target.h"
#include "hwinfo.h"
Expand Down Expand Up @@ -85,7 +86,7 @@
}

static struct perf_group_cpu_context *
perf_group_cpu_context_create(void)
perf_group_cpu_context_create(size_t event_count)
{
struct perf_group_cpu_context *ctx = (struct perf_group_cpu_context *) malloc(sizeof(struct perf_group_cpu_context));

Expand All @@ -96,7 +97,24 @@
zlistx_set_duplicator(ctx->perf_fds, (zlistx_duplicator_fn *) intptrdup);
zlistx_set_destructor(ctx->perf_fds, (zlistx_destructor_fn *) perf_event_fd_destroy);

ctx->sample_size = offsetof(struct perf_read_format, values) + sizeof(struct perf_counter_value) * event_count;
ctx->baseline_sample = (struct perf_read_format *) malloc(ctx->sample_size);
ctx->scratch_sample = (struct perf_read_format *) malloc(ctx->sample_size);

if (!ctx->baseline_sample || !ctx->scratch_sample)
goto error;

memset(ctx->baseline_sample, 0, ctx->sample_size);
memset(ctx->scratch_sample, 0, ctx->sample_size);

return ctx;

error:
zlistx_destroy(&ctx->perf_fds);
free(ctx->baseline_sample);
free(ctx->scratch_sample);
free(ctx);
return NULL;
}

static void
Expand All @@ -106,6 +124,8 @@
return;

zlistx_destroy(&(*ctx)->perf_fds);
free((*ctx)->baseline_sample);
free((*ctx)->scratch_sample);
free(*ctx);
*ctx = NULL;
}
Expand Down Expand Up @@ -280,7 +300,7 @@

for (cpu_id = (const char *) zlistx_first(pkg->cpus_id); cpu_id; cpu_id = (const char *) zlistx_next(pkg->cpus_id)) {
/* create cpu context */
cpu_ctx = perf_group_cpu_context_create();
cpu_ctx = perf_group_cpu_context_create(zlistx_size(events_group->events));
if (!cpu_ctx) {
zsys_error("perf<%s>: failed to create cpu context for group=%s pkg=%s cpu=%s", ctx->target_name, events_group_name, pkg_id, cpu_id);
goto error;
Expand Down Expand Up @@ -355,24 +375,30 @@
}

static int
perf_events_group_read_cpu(struct perf_group_cpu_context *cpu_ctx, struct perf_read_format *buffer, size_t buffer_size)
perf_events_group_read_cpu(struct perf_group_cpu_context *cpu_ctx)
{
int *group_leader_fd = NULL;

group_leader_fd = (int *) zlistx_first(cpu_ctx->perf_fds);
if (!group_leader_fd)
return -1;

if (read(*group_leader_fd, buffer, buffer_size) != (ssize_t) buffer_size)
return -1;

/* counters need to be reset in order to count the events per tick */
if (ioctl(*group_leader_fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP))
if (read(*group_leader_fd, cpu_ctx->scratch_sample, cpu_ctx->sample_size) != (ssize_t) cpu_ctx->sample_size)
return -1;

return 0;
}

static void
perf_group_cpu_context_advance_baseline(struct perf_group_cpu_context *cpu_ctx)
{
struct perf_read_format *old_baseline = NULL;

old_baseline = cpu_ctx->baseline_sample;
cpu_ctx->baseline_sample = cpu_ctx->scratch_sample;
cpu_ctx->scratch_sample = old_baseline;
}

static void
handle_pipe(struct perf_context *ctx)
{
Expand All @@ -396,6 +422,34 @@
}
#endif

static int
payload_cpu_data_insert_delta(struct payload_cpu_data *cpu_data, struct events_group *group, struct perf_group_cpu_context *cpu_ctx)
{
const struct perf_read_format *current = cpu_ctx->baseline_sample;
const struct perf_read_format *previous = cpu_ctx->scratch_sample;
struct event_config *event = NULL;
uint64_t delta_time_enabled = 0;
uint64_t delta_time_running = 0;
uint64_t delta_event_value = 0;
size_t event_i = 0;

delta_time_enabled = current->time_enabled - previous->time_enabled;
if (zhashx_insert(cpu_data->events, "time_enabled", &delta_time_enabled))
return -1;

delta_time_running = current->time_running - previous->time_running;
if (zhashx_insert(cpu_data->events, "time_running", &delta_time_running))
return -1;

for (event = (struct event_config *) zlistx_first(group->events), event_i = 0; event; event = (struct event_config *) zlistx_next(group->events), event_i++) {
delta_event_value = current->values[event_i].value - previous->values[event_i].value;
if (zhashx_insert(cpu_data->events, event->name, &delta_event_value))
return -1;
}

return 0;
}

static int
populate_payload(struct perf_context *ctx, struct payload *payload)
{
Expand All @@ -408,11 +462,7 @@
struct perf_group_cpu_context *cpu_ctx = NULL;
const char *cpu_id = NULL;
struct payload_cpu_data *cpu_data = NULL;
size_t perf_read_buffer_size;
struct perf_read_format *perf_read_buffer = NULL;
// double perf_multiplexing_ratio;
const struct event_config *event = NULL;
int event_i;

for (group_ctx = (struct perf_group_context *) zhashx_first(ctx->groups_ctx); group_ctx; group_ctx = (struct perf_group_context *) zhashx_next(ctx->groups_ctx)) {
group_name = (const char *) zhashx_cursor(ctx->groups_ctx);
Expand All @@ -422,15 +472,7 @@
goto error;
}

/* shared perf read buffer */
perf_read_buffer_size = offsetof(struct perf_read_format, values) + sizeof(struct perf_counter_value[zlistx_size(group_ctx->config->events)]);
perf_read_buffer = (struct perf_read_format *) malloc(perf_read_buffer_size);
if (!perf_read_buffer) {
zsys_error("perf<%s>: failed to allocate perf read buffer for group=%s", ctx->target_name, group_name);
goto error;
}

for (pkg_ctx = (struct perf_group_pkg_context *) zhashx_first(group_ctx->pkgs_ctx); pkg_ctx; pkg_ctx = (struct perf_group_pkg_context *) zhashx_next(group_ctx->pkgs_ctx)) {

Check warning on line 475 in src/perf.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Reduce the number of nested "goto" statements from 2 to 1 authorized.

See more on https://sonarcloud.io/project/issues?id=powerapi-ng_hwpc-sensor&issues=AZ8D4ni6J3i3wkBq6esq&open=AZ8D4ni6J3i3wkBq6esq&pullRequest=184
pkg_id = (const char *) zhashx_cursor(group_ctx->pkgs_ctx);
pkg_data = payload_pkg_data_create();
if (!pkg_data) {
Expand All @@ -446,42 +488,53 @@
goto error;
}

/* read counters value for the cpu */
if (perf_events_group_read_cpu(cpu_ctx, perf_read_buffer, perf_read_buffer_size)) {
if (perf_events_group_read_cpu(cpu_ctx)) {

Check failure on line 491 in src/perf.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=powerapi-ng_hwpc-sensor&issues=AZ8D4ni6J3i3wkBq6esn&open=AZ8D4ni6J3i3wkBq6esn&pullRequest=184
zsys_error("perf<%s>: cannot read perf values for group=%s pkg=%s cpu=%s", ctx->target_name, group_name, pkg_id, cpu_id);
goto error;
}

perf_group_cpu_context_advance_baseline(cpu_ctx);

#if 0
/* warn if PMU multiplexing is happening */
perf_multiplexing_ratio = compute_perf_multiplexing_ratio(perf_read_buffer);
perf_multiplexing_ratio = compute_perf_multiplexing_ratio(cpu_ctx->baseline_sample);
if (perf_multiplexing_ratio < 1.0) {
zsys_warning("perf<%s>: perf multiplexing for group=%s pkg=%s cpu=%s ratio=%f", ctx->target_name, group_name, pkg_id, cpu_id, perf_multiplexing_ratio);
}
#endif

/* store events value */
zhashx_insert(cpu_data->events, "time_enabled", &perf_read_buffer->time_enabled);
zhashx_insert(cpu_data->events, "time_running", &perf_read_buffer->time_running);
for (event = (struct event_config *) zlistx_first(group_ctx->config->events), event_i = 0; event; event = (struct event_config *) zlistx_next(group_ctx->config->events), event_i++) {
zhashx_insert(cpu_data->events, event->name, &perf_read_buffer->values[event_i].value);
if (payload_cpu_data_insert_delta(cpu_data, group_ctx->config, cpu_ctx)) {

Check failure on line 506 in src/perf.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=powerapi-ng_hwpc-sensor&issues=AZ8D4ni6J3i3wkBq6eso&open=AZ8D4ni6J3i3wkBq6eso&pullRequest=184
zsys_error("perf<%s>: failed to store perf values for group=%s pkg=%s cpu=%s", ctx->target_name, group_name, pkg_id, cpu_id);
goto error;
}

zhashx_insert(pkg_data->cpus, cpu_id, cpu_data);
if (zhashx_insert(pkg_data->cpus, cpu_id, cpu_data)) {

Check failure on line 511 in src/perf.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=powerapi-ng_hwpc-sensor&issues=AZ8D4ni6J3i3wkBq6esp&open=AZ8D4ni6J3i3wkBq6esp&pullRequest=184
zsys_error("perf<%s>: failed to store cpu data for group=%s pkg=%s cpu=%s", ctx->target_name, group_name, pkg_id, cpu_id);
goto error;
}

cpu_data = NULL;
}

if (zhashx_insert(group_data->pkgs, pkg_id, pkg_data)) {
zsys_error("perf<%s>: failed to store pkg data for group=%s pkg=%s", ctx->target_name, group_name, pkg_id);
goto error;
}

zhashx_insert(group_data->pkgs, pkg_id, pkg_data);
pkg_data = NULL;
}

free(perf_read_buffer);
perf_read_buffer = NULL;
zhashx_insert(payload->groups, group_name, group_data);
if (zhashx_insert(payload->groups, group_name, group_data)) {
zsys_error("perf<%s>: failed to store group data for group=%s", ctx->target_name, group_name);
goto error;
}

group_data = NULL;
}

return 0;

error:
free(perf_read_buffer);
payload_cpu_data_destroy(&cpu_data);
payload_pkg_data_destroy(&pkg_data);
payload_group_data_destroy(&group_data);
Expand Down Expand Up @@ -593,4 +646,3 @@
close(fd);
return 0;
}

38 changes: 20 additions & 18 deletions src/perf.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,32 @@ struct perf_config
struct target *target;
};

/*
* perf_counter_value stores the counter value.
*/
struct perf_counter_value {
uint64_t value;
};

/*
* perf_cpu_report stores the events counter value.
*/
struct perf_read_format {
uint64_t nr;
uint64_t time_enabled; /* PERF_FORMAT_TOTAL_TIME_ENABLED flag */
uint64_t time_running; /* PERF_FORMAT_TOTAL_TIME_RUNNING flag */
struct perf_counter_value values[];
};

/*
* perf_group_cpu_context stores the context of an events group for a specific cpu.
*/
struct perf_group_cpu_context
{
zlistx_t *perf_fds; /* int *fd */
size_t sample_size;
struct perf_read_format *baseline_sample;
struct perf_read_format *scratch_sample;
};

/*
Expand Down Expand Up @@ -87,23 +107,6 @@ struct perf_context
zhashx_t *groups_ctx; /* char *group_name -> struct perf_group_context *group_ctx */
};

/*
* perf_counter_value stores the counter value.
*/
struct perf_counter_value {
uint64_t value;
};

/*
* perf_cpu_report stores the events counter value.
*/
struct perf_read_format {
uint64_t nr;
uint64_t time_enabled; /* PERF_FORMAT_TOTAL_TIME_ENABLED flag */
uint64_t time_running; /* PERF_FORMAT_TOTAL_TIME_RUNNING flag */
struct perf_counter_value values[];
};

/*
* perf_config_create allocate and configure a perf configuration structure.
*/
Expand All @@ -126,4 +129,3 @@ void perf_monitoring_actor(zsock_t *pipe, void *args);
int perf_try_global_counting_event_open(void);

#endif /* PERF_H */

Loading