<commit_before>/*
 * builtin-report.c
 *
 * Builtin report command: Analyze the perf.data input file,
 * look up and read DSOs and symbol information and display
 * a histogram of results, along various sorting keys.
 */
#include "builtin.h"

#include "util/util.h"

#include "util/color.h"
#include <linux/list.h>
#include "util/cache.h"
#include <linux/rbtree.h>
#include "util/symbol.h"
#include "util/callchain.h"
#include "util/strlist.h"
#include "util/values.h"

#include "perf.h"
#include "util/debug.h"
#include "util/header.h"
#include "util/session.h"

#include "util/parse-options.h"
#include "util/parse-events.h"

#include "util/thread.h"
#include "util/sort.h"
#include "util/hist.h"

static char		const *input_name = "perf.data";

static bool		force;
static bool		hide_unresolved;
static bool		dont_use_callchains;

static bool		show_threads;
static struct perf_read_values	show_threads_values;

static char		default_pretty_printing_style[] = "normal";
static char		*pretty_printing_style = default_pretty_printing_style;

static char		callchain_default_opt[] = "fractal,0.5";

static struct event_stat_id *get_stats(struct perf_session *self,
				       u64 event_stream, u32 type, u64 config)
{
	struct rb_node **p = &self->stats_by_id.rb_node;
	struct rb_node *parent = NULL;
	struct event_stat_id *iter, *new;

	while (*p != NULL) {
		parent = *p;
		iter = rb_entry(parent, struct event_stat_id, rb_node);
		if (iter->config == config)
			return iter;


		if (config > iter->config)
			p = &(*p)->rb_right;
		else
			p = &(*p)->rb_left;
	}

	new = malloc(sizeof(struct event_stat_id));
	if (new == NULL)
		return NULL;
	memset(new, 0, sizeof(struct event_stat_id));
	new->event_stream = event_stream;
	new->config = config;
	new->type = type;
	rb_link_node(&new->rb_node, parent, p);
	rb_insert_color(&new->rb_node, &self->stats_by_id);
	return new;
}

static int perf_session__add_hist_entry(struct perf_session *self,
					struct addr_location *al,
					struct sample_data *data)
{
	struct map_symbol *syms = NULL;
	struct symbol *parent = NULL;
	bool hit;
	int err;
	struct hist_entry *he;
	struct event_stat_id *stats;
	struct perf_event_attr *attr;

	if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) {
		syms = perf_session__resolve_callchain(self, al->thread,
						       data->callchain, &parent);
		if (syms == NULL)
			return -ENOMEM;
	}

	attr = perf_header__find_attr(data->id, &self->header);
	if (attr)
		stats = get_stats(self, data->id, attr->type, attr->config);
	else
		stats = get_stats(self, data->id, 0, 0);
	if (stats == NULL)
		return -ENOMEM;
	he = __perf_session__add_hist_entry(&stats->hists, al, parent,
					    data->period, &hit);
	if (he == NULL)
		return -ENOMEM;

	if (hit)
		__perf_session__add_count(he, al,  data->period);

	if (symbol_conf.use_callchain) {
		if (!hit)
			callchain_init(he->callchain);
		err = append_chain(he->callchain, data->callchain, syms);
		free(syms);

		if (err)
			return err;
	}

	return 0;
}

static int add_event_total(struct perf_session *session,
			   struct sample_data *data,
			   struct perf_event_attr *attr)
{
	struct event_stat_id *stats;

	if (attr)
		stats = get_stats(session, data->id, attr->type, attr->config);
	else
		stats = get_stats(session, data->id, 0, 0);

	if (!stats)
		return -ENOMEM;

	stats->stats.total += data->period;
	session->events_stats.total += data->period;
	return 0;
}

static int process_sample_event(event_t *event, struct perf_session *session)
{
	struct sample_data data = { .period = 1, };
	struct addr_location al;
	struct perf_event_attr *attr;
<commit_msg>perf report: Fix leak of resolved callchains array on error path<commit_after>/*
 * builtin-report.c
 *
 * Builtin report command: Analyze the perf.data input file,
 * look up and read DSOs and symbol information and display
 * a histogram of results, along various sorting keys.
 */
#include "builtin.h"

#include "util/util.h"

#include "util/color.h"
#include <linux/list.h>
#include "util/cache.h"
#include <linux/rbtree.h>
#include "util/symbol.h"
#include "util/callchain.h"
#include "util/strlist.h"
#include "util/values.h"

#include "perf.h"
#include "util/debug.h"
#include "util/header.h"
#include "util/session.h"

#include "util/parse-options.h"
#include "util/parse-events.h"

#include "util/thread.h"
#include "util/sort.h"
#include "util/hist.h"

static char		const *input_name = "perf.data";

static bool		force;
static bool		hide_unresolved;
static bool		dont_use_callchains;

static bool		show_threads;
static struct perf_read_values	show_threads_values;

static char		default_pretty_printing_style[] = "normal";
static char		*pretty_printing_style = default_pretty_printing_style;

static char		callchain_default_opt[] = "fractal,0.5";

static struct event_stat_id *get_stats(struct perf_session *self,
				       u64 event_stream, u32 type, u64 config)
{
	struct rb_node **p = &self->stats_by_id.rb_node;
	struct rb_node *parent = NULL;
	struct event_stat_id *iter, *new;

	while (*p != NULL) {
		parent = *p;
		iter = rb_entry(parent, struct event_stat_id, rb_node);
		if (iter->config == config)
			return iter;


		if (config > iter->config)
			p = &(*p)->rb_right;
		else
			p = &(*p)->rb_left;
	}

	new = malloc(sizeof(struct event_stat_id));
	if (new == NULL)
		return NULL;
	memset(new, 0, sizeof(struct event_stat_id));
	new->event_stream = event_stream;
	new->config = config;
	new->type = type;
	rb_link_node(&new->rb_node, parent, p);
	rb_insert_color(&new->rb_node, &self->stats_by_id);
	return new;
}

static int perf_session__add_hist_entry(struct perf_session *self,
					struct addr_location *al,
					struct sample_data *data)
{
	struct map_symbol *syms = NULL;
	struct symbol *parent = NULL;
	bool hit;
	int err = -ENOMEM;
	struct hist_entry *he;
	struct event_stat_id *stats;
	struct perf_event_attr *attr;

	if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) {
		syms = perf_session__resolve_callchain(self, al->thread,
						       data->callchain, &parent);
		if (syms == NULL)
			return -ENOMEM;
	}

	attr = perf_header__find_attr(data->id, &self->header);
	if (attr)
		stats = get_stats(self, data->id, attr->type, attr->config);
	else
		stats = get_stats(self, data->id, 0, 0);
	if (stats == NULL)
		goto out_free_syms;
	he = __perf_session__add_hist_entry(&stats->hists, al, parent,
					    data->period, &hit);
	if (he == NULL)
		goto out_free_syms;

	if (hit)
		__perf_session__add_count(he, al,  data->period);

	err = 0;
	if (symbol_conf.use_callchain) {
		if (!hit)
			callchain_init(he->callchain);
		err = append_chain(he->callchain, data->callchain, syms);
	}
out_free_syms:
	free(syms);
	return err;
}

static int add_event_total(struct perf_session *session,
			   struct sample_data *data,
			   struct perf_event_attr *attr)
{
	struct event_stat_id *stats;

	if (attr)
		stats = get_stats(session, data->id, attr->type, attr->config);
	else
		stats = get_stats(session, data->id, 0, 0);

	if (!stats)
		return -ENOMEM;

	stats->stats.total += data->period;
	session->events_stats.total += data->period;
	return 0;
}

static int process_sample_event(event_t *event, struct perf_session *session)
{
	struct sample_data data = { .period = 1, };
	struct addr_location al;
	struct perf_event_attr *attr;

{'fraction_non_alphanumeric': 0.13314136843548607, 'fraction_numerical': 0.0043877690936514465, 'mean_word_length': 4.414996288047513, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1434828', 'n_tokens_mistral': 2842, 'n_tokens_neox': 2673, 'n_words': 660}