• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file daemon/opd_events.c
3  * Event details for each counter
4  *
5  * @remark Copyright 2002, 2003 OProfile authors
6  * @remark Read the file COPYING
7  *
8  * @author John Levon
9  * @author Philippe Elie
10  */
11 
12 #include "config.h"
13 
14 #include "opd_events.h"
15 #include "opd_printf.h"
16 #include "opd_extended.h"
17 #include "oprofiled.h"
18 
19 #include "op_string.h"
20 #include "op_config.h"
21 #include "op_cpufreq.h"
22 #include "op_cpu_type.h"
23 #include "op_libiberty.h"
24 #include "op_hw_config.h"
25 #include "op_sample_file.h"
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 
30 extern op_cpu cpu_type;
31 
32 struct opd_event opd_events[OP_MAX_COUNTERS];
33 
34 static double cpu_speed;
35 
malformed_events(void)36 static void malformed_events(void)
37 {
38 	fprintf(stderr, "oprofiled: malformed events passed "
39 		"on the command line\n");
40 	exit(EXIT_FAILURE);
41 }
42 
43 
copy_token(char ** c,char delim)44 static char * copy_token(char ** c, char delim)
45 {
46 	char * tmp = *c;
47 	char * tmp2 = *c;
48 	char * str;
49 
50 	if (!**c)
51 		return NULL;
52 
53 	while (*tmp2 && *tmp2 != delim)
54 		++tmp2;
55 
56 	if (tmp2 == tmp)
57 		return NULL;
58 
59 	str = op_xstrndup(tmp, tmp2 - tmp);
60 	*c = tmp2;
61 	if (**c)
62 		++*c;
63 	return str;
64 }
65 
66 
copy_ulong(char ** c,char delim)67 static unsigned long copy_ulong(char ** c, char delim)
68 {
69 	unsigned long val = 0;
70 	char * str = copy_token(c, delim);
71 	if (!str)
72 		malformed_events();
73 	val = strtoul(str, NULL, 0);
74 	free(str);
75 	return val;
76 }
77 
78 
opd_parse_events(char const * events)79 void opd_parse_events(char const * events)
80 {
81 	char * ev = xstrdup(events);
82 	char * c;
83 	size_t cur = 0;
84 
85 	if (cpu_type == CPU_TIMER_INT) {
86 		struct opd_event * event = &opd_events[0];
87 		event->name = xstrdup("TIMER");
88 		event->value = event->counter
89 			= event->count = event->um = 0;
90 		event->kernel = 1;
91 		event->user = 1;
92 		return;
93 	}
94 
95 	if (!ev || !strlen(ev)) {
96 		fprintf(stderr, "oprofiled: no events passed.\n");
97 		exit(EXIT_FAILURE);
98 	}
99 
100 	verbprintf(vmisc, "Events: %s\n", ev);
101 
102 	c = ev;
103 
104 	while (*c && cur < op_nr_counters) {
105 		struct opd_event * event = &opd_events[cur];
106 
107 		if (!(event->name = copy_token(&c, ':')))
108 			malformed_events();
109 		event->value = copy_ulong(&c, ':');
110 		event->counter = copy_ulong(&c, ':');
111 		event->count = copy_ulong(&c, ':');
112 		event->um = copy_ulong(&c, ':');
113 		event->kernel = copy_ulong(&c, ':');
114 		event->user = copy_ulong(&c, ',');
115 		++cur;
116 	}
117 
118 	if (*c) {
119 		fprintf(stderr, "oprofiled: too many events passed.\n");
120 		exit(EXIT_FAILURE);
121 	}
122 
123 	free(ev);
124 
125 	cpu_speed = op_cpu_frequency();
126 }
127 
128 
find_counter_event(unsigned long counter)129 struct opd_event * find_counter_event(unsigned long counter)
130 {
131 	size_t i;
132 	struct opd_event * ret = NULL;
133 
134 	if (counter >= OP_MAX_COUNTERS) {
135 		if((ret = opd_ext_find_counter_event(counter)) != NULL)
136 			return ret;
137 	}
138 
139 	for (i = 0; i < op_nr_counters && opd_events[i].name; ++i) {
140 		if (counter == opd_events[i].counter)
141 			return &opd_events[i];
142 	}
143 
144 	fprintf(stderr, "Unknown event for counter %lu\n", counter);
145         /*
146          * ANDROID FIXME - from time to time there seems to be 1 phantom event
147          * reported from counter 3 when only counter 0 is enabled. Instead of
148          * crashing the daemon and losing tons of useful samples, we just
149          * charge the erroneous single count to the first event.
150          */
151 #ifdef ANDROID
152         return &opd_events[0];
153 #else
154 	abort();
155 	return NULL;
156 
157 #endif
158 }
159 
160 
fill_header(struct opd_header * header,unsigned long counter,vma_t anon_start,vma_t cg_to_anon_start,int is_kernel,int cg_to_is_kernel,int spu_samples,uint64_t embed_offset,time_t mtime)161 void fill_header(struct opd_header * header, unsigned long counter,
162 		 vma_t anon_start, vma_t cg_to_anon_start,
163 		 int is_kernel, int cg_to_is_kernel,
164 		 int spu_samples, uint64_t embed_offset, time_t mtime)
165 {
166 	struct opd_event * event = find_counter_event(counter);
167 
168 	memset(header, '\0', sizeof(struct opd_header));
169 	header->version = OPD_VERSION;
170 	memcpy(header->magic, OPD_MAGIC, sizeof(header->magic));
171 	header->cpu_type = cpu_type;
172 	header->ctr_event = event->value;
173 	header->ctr_count = event->count;
174 	header->ctr_um = event->um;
175 	header->is_kernel = is_kernel;
176 	header->cg_to_is_kernel = cg_to_is_kernel;
177 	header->cpu_speed = cpu_speed;
178 	header->mtime = mtime;
179 	header->anon_start = anon_start;
180 	header->spu_profile = spu_samples;
181 	header->embedded_offset = embed_offset;
182 	header->cg_to_anon_start = cg_to_anon_start;
183 }
184