xref: /linux/tools/perf/util/stat.c (revision c0e297dc61f8d4453e07afbea1fa8d0e67cd4a34)
1 #include <math.h>
2 #include "stat.h"
3 #include "evlist.h"
4 #include "evsel.h"
5 #include "thread_map.h"
6 
7 void update_stats(struct stats *stats, u64 val)
8 {
9 	double delta;
10 
11 	stats->n++;
12 	delta = val - stats->mean;
13 	stats->mean += delta / stats->n;
14 	stats->M2 += delta*(val - stats->mean);
15 
16 	if (val > stats->max)
17 		stats->max = val;
18 
19 	if (val < stats->min)
20 		stats->min = val;
21 }
22 
23 double avg_stats(struct stats *stats)
24 {
25 	return stats->mean;
26 }
27 
28 /*
29  * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
30  *
31  *       (\Sum n_i^2) - ((\Sum n_i)^2)/n
32  * s^2 = -------------------------------
33  *                  n - 1
34  *
35  * http://en.wikipedia.org/wiki/Stddev
36  *
37  * The std dev of the mean is related to the std dev by:
38  *
39  *             s
40  * s_mean = -------
41  *          sqrt(n)
42  *
43  */
44 double stddev_stats(struct stats *stats)
45 {
46 	double variance, variance_mean;
47 
48 	if (stats->n < 2)
49 		return 0.0;
50 
51 	variance = stats->M2 / (stats->n - 1);
52 	variance_mean = variance / stats->n;
53 
54 	return sqrt(variance_mean);
55 }
56 
57 double rel_stddev_stats(double stddev, double avg)
58 {
59 	double pct = 0.0;
60 
61 	if (avg)
62 		pct = 100.0 * stddev/avg;
63 
64 	return pct;
65 }
66 
67 bool __perf_evsel_stat__is(struct perf_evsel *evsel,
68 			   enum perf_stat_evsel_id id)
69 {
70 	struct perf_stat *ps = evsel->priv;
71 
72 	return ps->id == id;
73 }
74 
75 #define ID(id, name) [PERF_STAT_EVSEL_ID__##id] = #name
76 static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = {
77 	ID(NONE,		x),
78 	ID(CYCLES_IN_TX,	cpu/cycles-t/),
79 	ID(TRANSACTION_START,	cpu/tx-start/),
80 	ID(ELISION_START,	cpu/el-start/),
81 	ID(CYCLES_IN_TX_CP,	cpu/cycles-ct/),
82 };
83 #undef ID
84 
85 void perf_stat_evsel_id_init(struct perf_evsel *evsel)
86 {
87 	struct perf_stat *ps = evsel->priv;
88 	int i;
89 
90 	/* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
91 
92 	for (i = 0; i < PERF_STAT_EVSEL_ID__MAX; i++) {
93 		if (!strcmp(perf_evsel__name(evsel), id_str[i])) {
94 			ps->id = i;
95 			break;
96 		}
97 	}
98 }
99 
100 struct perf_counts *perf_counts__new(int ncpus, int nthreads)
101 {
102 	struct perf_counts *counts = zalloc(sizeof(*counts));
103 
104 	if (counts) {
105 		struct xyarray *values;
106 
107 		values = xyarray__new(ncpus, nthreads, sizeof(struct perf_counts_values));
108 		if (!values) {
109 			free(counts);
110 			return NULL;
111 		}
112 
113 		counts->values = values;
114 	}
115 
116 	return counts;
117 }
118 
119 void perf_counts__delete(struct perf_counts *counts)
120 {
121 	if (counts) {
122 		xyarray__delete(counts->values);
123 		free(counts);
124 	}
125 }
126 
127 static void perf_counts__reset(struct perf_counts *counts)
128 {
129 	xyarray__reset(counts->values);
130 }
131 
132 void perf_evsel__reset_counts(struct perf_evsel *evsel)
133 {
134 	perf_counts__reset(evsel->counts);
135 }
136 
137 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads)
138 {
139 	evsel->counts = perf_counts__new(ncpus, nthreads);
140 	return evsel->counts != NULL ? 0 : -ENOMEM;
141 }
142 
143 void perf_evsel__free_counts(struct perf_evsel *evsel)
144 {
145 	perf_counts__delete(evsel->counts);
146 	evsel->counts = NULL;
147 }
148 
149 void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
150 {
151 	int i;
152 	struct perf_stat *ps = evsel->priv;
153 
154 	for (i = 0; i < 3; i++)
155 		init_stats(&ps->res_stats[i]);
156 
157 	perf_stat_evsel_id_init(evsel);
158 }
159 
160 int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
161 {
162 	evsel->priv = zalloc(sizeof(struct perf_stat));
163 	if (evsel->priv == NULL)
164 		return -ENOMEM;
165 	perf_evsel__reset_stat_priv(evsel);
166 	return 0;
167 }
168 
169 void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
170 {
171 	zfree(&evsel->priv);
172 }
173 
174 int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
175 				      int ncpus, int nthreads)
176 {
177 	struct perf_counts *counts;
178 
179 	counts = perf_counts__new(ncpus, nthreads);
180 	if (counts)
181 		evsel->prev_raw_counts = counts;
182 
183 	return counts ? 0 : -ENOMEM;
184 }
185 
186 void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
187 {
188 	perf_counts__delete(evsel->prev_raw_counts);
189 	evsel->prev_raw_counts = NULL;
190 }
191 
192 int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw)
193 {
194 	int ncpus = perf_evsel__nr_cpus(evsel);
195 	int nthreads = thread_map__nr(evsel->threads);
196 
197 	if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
198 	    perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 ||
199 	    (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel, ncpus, nthreads) < 0))
200 		return -ENOMEM;
201 
202 	return 0;
203 }
204 
205 int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
206 {
207 	struct perf_evsel *evsel;
208 
209 	evlist__for_each(evlist, evsel) {
210 		if (perf_evsel__alloc_stats(evsel, alloc_raw))
211 			goto out_free;
212 	}
213 
214 	return 0;
215 
216 out_free:
217 	perf_evlist__free_stats(evlist);
218 	return -1;
219 }
220 
221 void perf_evlist__free_stats(struct perf_evlist *evlist)
222 {
223 	struct perf_evsel *evsel;
224 
225 	evlist__for_each(evlist, evsel) {
226 		perf_evsel__free_stat_priv(evsel);
227 		perf_evsel__free_counts(evsel);
228 		perf_evsel__free_prev_raw_counts(evsel);
229 	}
230 }
231 
232 void perf_evlist__reset_stats(struct perf_evlist *evlist)
233 {
234 	struct perf_evsel *evsel;
235 
236 	evlist__for_each(evlist, evsel) {
237 		perf_evsel__reset_stat_priv(evsel);
238 		perf_evsel__reset_counts(evsel);
239 	}
240 }
241