1 /*--------------------------------------------------------------------*/
2 /*--- Callgrind                                                    ---*/
3 /*---                                                     events.c ---*/
4 /*--------------------------------------------------------------------*/
5 
6 /*
7    This file is part of Callgrind, a Valgrind tool for call tracing.
8 
9    Copyright (C) 2002-2017, Josef Weidendorfer (Josef.Weidendorfer@gmx.de)
10 
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License as
13    published by the Free Software Foundation; either version 2 of the
14    License, or (at your option) any later version.
15 
16    This program is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    General Public License for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24    02111-1307, USA.
25 
26    The GNU General Public License is contained in the file COPYING.
27 */
28 
29 #include "global.h"
30 
31 /* This should be 2**MAX_EVENTGROUP_COUNT */
32 #define MAX_EVENTSET_COUNT 1024
33 
34 static EventGroup* eventGroup[MAX_EVENTGROUP_COUNT];
35 static EventSet* eventSetTable[MAX_EVENTSET_COUNT];
36 static Bool eventSets_initialized = 0;
37 
38 static
initialize_event_sets(void)39 void initialize_event_sets(void)
40 {
41     Int i;
42 
43     if (eventSets_initialized) return;
44 
45     for(i=0; i< MAX_EVENTGROUP_COUNT; i++)
46 	eventGroup[i] = 0;
47 
48     for(i=0; i< MAX_EVENTSET_COUNT; i++)
49 	eventSetTable[i] = 0;
50 
51     eventSets_initialized = 1;
52  }
53 
54 static
new_event_group(int id,int n)55 EventGroup* new_event_group(int id, int n)
56 {
57     EventGroup* eg;
58 
59     initialize_event_sets();
60 
61     CLG_ASSERT(id>=0 && id<MAX_EVENTGROUP_COUNT);
62     CLG_ASSERT(eventGroup[id]==0);
63 
64     eg = (EventGroup*) CLG_MALLOC("cl.events.group.1",
65 				  sizeof(EventGroup) + n * sizeof(HChar*));
66     eg->size = n;
67     eventGroup[id] = eg;
68     return eg;
69 }
70 
CLG_(register_event_group)71 EventGroup* CLG_(register_event_group) (int id, const HChar* n1)
72 {
73     EventGroup* eg = new_event_group(id, 1);
74     eg->name[0] = n1;
75 
76     return eg;
77 }
78 
CLG_(register_event_group2)79 EventGroup* CLG_(register_event_group2)(int id, const HChar* n1,
80                                         const HChar* n2)
81 {
82     EventGroup* eg = new_event_group(id, 2);
83     eg->name[0] = n1;
84     eg->name[1] = n2;
85 
86     return eg;
87 }
88 
CLG_(register_event_group3)89 EventGroup* CLG_(register_event_group3)(int id, const HChar* n1,
90                                         const HChar* n2, const HChar* n3)
91 {
92     EventGroup* eg = new_event_group(id, 3);
93     eg->name[0] = n1;
94     eg->name[1] = n2;
95     eg->name[2] = n3;
96 
97     return eg;
98 }
99 
CLG_(register_event_group4)100 EventGroup* CLG_(register_event_group4)(int id, const HChar* n1,
101                                         const HChar* n2, const HChar* n3,
102                                         const HChar* n4)
103 {
104     EventGroup* eg = new_event_group(id, 4);
105     eg->name[0] = n1;
106     eg->name[1] = n2;
107     eg->name[2] = n3;
108     eg->name[3] = n4;
109 
110     return eg;
111 }
112 
CLG_(get_event_group)113 EventGroup* CLG_(get_event_group)(int id)
114 {
115     CLG_ASSERT(id>=0 && id<MAX_EVENTGROUP_COUNT);
116 
117     return eventGroup[id];
118 }
119 
120 
121 static
eventset_from_mask(UInt mask)122 EventSet* eventset_from_mask(UInt mask)
123 {
124     EventSet* es;
125     Int i, count, offset;
126 
127     if (mask >= MAX_EVENTSET_COUNT) return 0;
128 
129     initialize_event_sets();
130     if (eventSetTable[mask]) return eventSetTable[mask];
131 
132     es = (EventSet*) CLG_MALLOC("cl.events.eventset.1", sizeof(EventSet));
133     es->mask = mask;
134 
135     offset = 0;
136     count = 0;
137     for(i=0;i<MAX_EVENTGROUP_COUNT;i++) {
138 	es->offset[i] = offset;
139 	if ( ((mask & (1u<<i))==0) || (eventGroup[i]==0))
140 	    continue;
141 
142 	offset += eventGroup[i]->size;
143 	count++;
144     }
145     es->size = offset;
146     es->count = count;
147 
148     eventSetTable[mask] = es;
149     return es;
150 }
151 
CLG_(get_event_set)152 EventSet* CLG_(get_event_set)(Int id)
153 {
154     CLG_ASSERT(id>=0 && id<MAX_EVENTGROUP_COUNT);
155     return eventset_from_mask(1u << id);
156 }
157 
CLG_(get_event_set2)158 EventSet* CLG_(get_event_set2)(Int id1, Int id2)
159 {
160     CLG_ASSERT(id1>=0 && id1<MAX_EVENTGROUP_COUNT);
161     CLG_ASSERT(id2>=0 && id2<MAX_EVENTGROUP_COUNT);
162     return eventset_from_mask((1u << id1) | (1u << id2));
163 }
164 
CLG_(add_event_group)165 EventSet* CLG_(add_event_group)(EventSet* es, Int id)
166 {
167     CLG_ASSERT(id>=0 && id<MAX_EVENTGROUP_COUNT);
168     if (!es) es = eventset_from_mask(0);
169     return eventset_from_mask(es->mask | (1u << id));
170 }
171 
CLG_(add_event_group2)172 EventSet* CLG_(add_event_group2)(EventSet* es, Int id1, Int id2)
173 {
174     CLG_ASSERT(id1>=0 && id1<MAX_EVENTGROUP_COUNT);
175     CLG_ASSERT(id2>=0 && id2<MAX_EVENTGROUP_COUNT);
176     if (!es) es = eventset_from_mask(0);
177     return eventset_from_mask(es->mask | (1u << id1) | (1u << id2));
178 }
179 
CLG_(add_event_set)180 EventSet* CLG_(add_event_set)(EventSet* es1, EventSet* es2)
181 {
182     if (!es1) es1 = eventset_from_mask(0);
183     if (!es2) es2 = eventset_from_mask(0);
184     return eventset_from_mask(es1->mask | es2->mask);
185 }
186 
187 
188 /* Get cost array for an event set */
CLG_(get_eventset_cost)189 ULong* CLG_(get_eventset_cost)(EventSet* es)
190 {
191     return CLG_(get_costarray)(es->size);
192 }
193 
194 /* Set all costs of an event set to zero */
CLG_(init_cost)195 void CLG_(init_cost)(EventSet* es, ULong* cost)
196 {
197     Int i;
198 
199     if (!cost) return;
200 
201     for(i=0; i<es->size; i++)
202 	cost[i] = 0;
203 }
204 
205 /* Set all costs of an event set to zero */
CLG_(init_cost_lz)206 void CLG_(init_cost_lz)(EventSet* es, ULong** cost)
207 {
208     Int i;
209 
210     CLG_ASSERT(cost != 0);
211     if (!(*cost))
212 	*cost = CLG_(get_eventset_cost)(es);
213 
214     for(i=0; i<es->size; i++)
215 	(*cost)[i] = 0;
216 }
217 
CLG_(zero_cost)218 void CLG_(zero_cost)(EventSet* es, ULong* cost)
219 {
220     Int i;
221 
222     if (!cost) return;
223 
224     for(i=0;i<es->size;i++)
225 	cost[i] = 0;
226 }
227 
CLG_(is_zero_cost)228 Bool CLG_(is_zero_cost)(EventSet* es, ULong* cost)
229 {
230     Int i;
231 
232     if (!cost) return True;
233 
234     for(i=0; i<es->size; i++)
235 	if (cost[i] != 0) return False;
236 
237     return True;
238 }
239 
CLG_(copy_cost)240 void CLG_(copy_cost)(EventSet* es, ULong* dst, ULong* src)
241 {
242     Int i;
243 
244     if (!src) {
245 	CLG_(zero_cost)(es, dst);
246 	return;
247     }
248     CLG_ASSERT(dst != 0);
249 
250     for(i=0;i<es->size;i++)
251 	dst[i] = src[i];
252 }
253 
CLG_(copy_cost_lz)254 void CLG_(copy_cost_lz)(EventSet* es, ULong** pdst, ULong* src)
255 {
256     Int i;
257     ULong* dst;
258 
259     CLG_ASSERT(pdst != 0);
260 
261     if (!src) {
262 	CLG_(zero_cost)(es, *pdst);
263 	return;
264     }
265     dst = *pdst;
266     if (!dst)
267 	dst = *pdst = CLG_(get_eventset_cost)(es);
268 
269     for(i=0;i<es->size;i++)
270 	dst[i] = src[i];
271 }
272 
CLG_(add_cost)273 void CLG_(add_cost)(EventSet* es, ULong* dst, ULong* src)
274 {
275     Int i;
276 
277     if (!src) return;
278     CLG_ASSERT(dst != 0);
279 
280     for(i=0; i<es->size; i++)
281 	dst[i] += src[i];
282 }
283 
CLG_(add_cost_lz)284 void CLG_(add_cost_lz)(EventSet* es, ULong** pdst, ULong* src)
285 {
286     Int i;
287     ULong* dst;
288 
289     if (!src) return;
290     CLG_ASSERT(pdst != 0);
291 
292     dst = *pdst;
293     if (!dst) {
294 	dst = *pdst = CLG_(get_eventset_cost)(es);
295 	CLG_(copy_cost)(es, dst, src);
296 	return;
297     }
298 
299     for(i=0; i<es->size; i++)
300 	dst[i] += src[i];
301 }
302 
303 /* Adds src to dst and zeros src. Returns false if nothing changed */
CLG_(add_and_zero_cost)304 Bool CLG_(add_and_zero_cost)(EventSet* es, ULong* dst, ULong* src)
305 {
306     Int i;
307     Bool is_nonzero = False;
308 
309     CLG_ASSERT((es != 0) && (dst != 0));
310     if (!src) return False;
311 
312     for(i=0; i<es->size; i++) {
313 	if (src[i]==0) continue;
314 	dst[i] += src[i];
315 	src[i] = 0;
316 	is_nonzero = True;
317     }
318 
319     return is_nonzero;
320 }
321 
322 /* Adds src to dst and zeros src. Returns false if nothing changed */
CLG_(add_and_zero_cost2)323 Bool CLG_(add_and_zero_cost2)(EventSet* esDst, ULong* dst,
324 			      EventSet* esSrc, ULong* src)
325 {
326     Int i,j;
327     Bool is_nonzero = False;
328     UInt mask;
329     EventGroup *eg;
330     ULong *egDst, *egSrc;
331 
332     CLG_ASSERT((esDst != 0) && (dst != 0) && (esSrc != 0));
333     if (!src) return False;
334 
335     for(i=0, mask=1; i<MAX_EVENTGROUP_COUNT; i++, mask=mask<<1) {
336 	if ((esSrc->mask & mask)==0) continue;
337 	if (eventGroup[i] ==0) continue;
338 
339 	/* if src has a subset, dst must have, too */
340 	CLG_ASSERT((esDst->mask & mask)>0);
341 	eg = eventGroup[i];
342 	egSrc = src + esSrc->offset[i];
343 	egDst = dst + esDst->offset[i];
344 	for(j=0; j<eg->size; j++) {
345 	    if (egSrc[j]==0) continue;
346 	    egDst[j] += egSrc[j];
347 	    egSrc[j] = 0;
348 	    is_nonzero = True;
349 	}
350     }
351 
352     return is_nonzero;
353 }
354 
355 
356 
357 /* Adds difference of new and old to dst, and set old to new.
358  * Returns false if nothing changed */
CLG_(add_diff_cost)359 Bool CLG_(add_diff_cost)(EventSet* es, ULong* dst, ULong* old, ULong* new_cost)
360 {
361     Int i;
362     Bool is_nonzero = False;
363 
364     CLG_ASSERT((es != 0) && (dst != 0));
365     CLG_ASSERT(old && new_cost);
366 
367     for(i=0; i<es->size; i++) {
368 	if (new_cost[i] == old[i]) continue;
369 	dst[i] += new_cost[i] - old[i];
370 	old[i] = new_cost[i];
371 	is_nonzero = True;
372     }
373 
374     return is_nonzero;
375 }
376 
CLG_(add_diff_cost_lz)377 Bool CLG_(add_diff_cost_lz)(EventSet* es, ULong** pdst, ULong* old, ULong* new_cost)
378 {
379     Int i;
380     ULong* dst;
381     Bool is_nonzero = False;
382 
383     CLG_ASSERT((es != 0) && (pdst != 0));
384     CLG_ASSERT(old && new_cost);
385 
386     dst = *pdst;
387     if (!dst) {
388 	dst = *pdst = CLG_(get_eventset_cost)(es);
389 	CLG_(zero_cost)(es, dst);
390     }
391 
392     for(i=0; i<es->size; i++) {
393 	if (new_cost[i] == old[i]) continue;
394 	dst[i] += new_cost[i] - old[i];
395 	old[i] = new_cost[i];
396 	is_nonzero = True;
397     }
398 
399     return is_nonzero;
400 }
401 
402 
403 /* Allocate space for an event mapping */
CLG_(get_eventmapping)404 EventMapping* CLG_(get_eventmapping)(EventSet* es)
405 {
406     EventMapping* em;
407 
408     CLG_ASSERT(es != 0);
409 
410     em = (EventMapping*) CLG_MALLOC("cl.events.geMapping.1",
411 				    sizeof(EventMapping) +
412 				    sizeof(struct EventMappingEntry) *
413 				    es->size);
414     em->capacity = es->size;
415     em->size = 0;
416     em->es = es;
417 
418     return em;
419 }
420 
CLG_(append_event)421 void CLG_(append_event)(EventMapping* em, const HChar* n)
422 {
423     Int i, j, offset = 0;
424     UInt mask;
425     EventGroup* eg;
426 
427     CLG_ASSERT(em != 0);
428     for(i=0, mask=1; i<MAX_EVENTGROUP_COUNT; i++, mask=mask<<1) {
429 	if ((em->es->mask & mask)==0) continue;
430 	if (eventGroup[i] ==0) continue;
431 
432 	eg = eventGroup[i];
433 	for(j=0; j<eg->size; j++, offset++) {
434 	    if (VG_(strcmp)(n, eg->name[j])!=0)
435 		    continue;
436 
437 	    CLG_ASSERT(em->capacity > em->size);
438 	    em->entry[em->size].group = i;
439 	    em->entry[em->size].index = j;
440 	    em->entry[em->size].offset = offset;
441 	    em->size++;
442 	    return;
443 	}
444     }
445 }
446 
447 
448 /* Returns pointer to dynamically string. The string will be overwritten
449    with each invocation. */
CLG_(eventmapping_as_string)450 HChar *CLG_(eventmapping_as_string)(const EventMapping* em)
451 {
452     Int i;
453     EventGroup* eg;
454 
455     CLG_ASSERT(em != 0);
456 
457     XArray *xa = VG_(newXA)(VG_(malloc), "cl.events.emas", VG_(free),
458                             sizeof(HChar));
459 
460     for(i=0; i< em->size; i++) {
461 	if (i > 0) {
462            VG_(xaprintf)(xa, "%c", ' ');
463         }
464 	eg = eventGroup[em->entry[i].group];
465 	CLG_ASSERT(eg != 0);
466         VG_(xaprintf)(xa, "%s", eg->name[em->entry[i].index]);
467     }
468     VG_(xaprintf)(xa, "%c", '\0');   // zero terminate the string
469 
470     HChar *buf = VG_(strdup)("cl.events.emas", VG_(indexXA)(xa, 0));
471     VG_(deleteXA)(xa);
472 
473     return buf;
474 }
475 
476 /* Returns pointer to dynamically allocated string. Caller needs to
477    VG_(free) it. */
CLG_(mappingcost_as_string)478 HChar *CLG_(mappingcost_as_string)(const EventMapping* em, const ULong* c)
479 {
480     Int i, skipped = 0;
481 
482     if (!c || em->size==0) return VG_(strdup)("cl.events.mcas", "");
483 
484     XArray *xa = VG_(newXA)(VG_(malloc), "cl.events.mcas", VG_(free),
485                             sizeof(HChar));
486 
487     /* At least one entry */
488     VG_(xaprintf)(xa, "%llu", c[em->entry[0].offset]);
489 
490     for(i=1; i<em->size; i++) {
491 	if (c[em->entry[i].offset] == 0) {
492 	    skipped++;
493 	    continue;
494 	}
495 	while(skipped>0) {
496             VG_(xaprintf)(xa, " 0");
497 	    skipped--;
498 	}
499 	VG_(xaprintf)(xa, " %llu", c[em->entry[i].offset]);
500     }
501     VG_(xaprintf)(xa, "%c", '\0');   // zero terminate the string
502 
503     HChar *buf = VG_(strdup)("cl.events.mas", VG_(indexXA)(xa, 0));
504     VG_(deleteXA)(xa);
505 
506     return buf;
507 }
508