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-2011, 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
34static EventGroup* eventGroup[MAX_EVENTGROUP_COUNT];
35static EventSet* eventSetTable[MAX_EVENTSET_COUNT];
36static Bool eventSets_initialized = 0;
37
38static
39void 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
54static
55EventGroup* 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(Char*));
66    eg->size = n;
67    eventGroup[id] = eg;
68    return eg;
69}
70
71EventGroup* CLG_(register_event_group) (int id, Char* n1)
72{
73    EventGroup* eg = new_event_group(id, 1);
74    eg->name[0] = n1;
75
76    return eg;
77}
78
79EventGroup* CLG_(register_event_group2)(int id, Char* n1, Char* n2)
80{
81    EventGroup* eg = new_event_group(id, 2);
82    eg->name[0] = n1;
83    eg->name[1] = n2;
84
85    return eg;
86}
87
88EventGroup* CLG_(register_event_group3)(int id, Char* n1, Char* n2, Char* n3)
89{
90    EventGroup* eg = new_event_group(id, 3);
91    eg->name[0] = n1;
92    eg->name[1] = n2;
93    eg->name[2] = n3;
94
95    return eg;
96}
97
98EventGroup* CLG_(register_event_group4)(int id,
99					Char* n1, Char* n2, Char* n3, Char* n4)
100{
101    EventGroup* eg = new_event_group(id, 4);
102    eg->name[0] = n1;
103    eg->name[1] = n2;
104    eg->name[2] = n3;
105    eg->name[3] = n4;
106
107    return eg;
108}
109
110EventGroup* CLG_(get_event_group)(int id)
111{
112    CLG_ASSERT(id>=0 && id<MAX_EVENTGROUP_COUNT);
113
114    return eventGroup[id];
115}
116
117
118static
119EventSet* eventset_from_mask(UInt mask)
120{
121    EventSet* es;
122    Int i, count, offset;
123
124    if (mask >= MAX_EVENTSET_COUNT) return 0;
125
126    initialize_event_sets();
127    if (eventSetTable[mask]) return eventSetTable[mask];
128
129    es = (EventSet*) CLG_MALLOC("cl.events.eventset.1", sizeof(EventSet));
130    es->mask = mask;
131
132    offset = 0;
133    count = 0;
134    for(i=0;i<MAX_EVENTGROUP_COUNT;i++) {
135	es->offset[i] = offset;
136	if ( ((mask & (1u<<i))==0) || (eventGroup[i]==0))
137	    continue;
138
139	offset += eventGroup[i]->size;
140	count++;
141    }
142    es->size = offset;
143    es->count = count;
144
145    eventSetTable[mask] = es;
146    return es;
147}
148
149EventSet* CLG_(get_event_set)(Int id)
150{
151    CLG_ASSERT(id>=0 && id<MAX_EVENTGROUP_COUNT);
152    return eventset_from_mask(1u << id);
153}
154
155EventSet* CLG_(get_event_set2)(Int id1, Int id2)
156{
157    CLG_ASSERT(id1>=0 && id1<MAX_EVENTGROUP_COUNT);
158    CLG_ASSERT(id2>=0 && id2<MAX_EVENTGROUP_COUNT);
159    return eventset_from_mask((1u << id1) | (1u << id2));
160}
161
162EventSet* CLG_(get_event_set3)(Int id1, Int id2, Int id3)
163{
164    CLG_ASSERT(id1>=0 && id1<MAX_EVENTGROUP_COUNT);
165    CLG_ASSERT(id2>=0 && id2<MAX_EVENTGROUP_COUNT);
166    CLG_ASSERT(id3>=0 && id3<MAX_EVENTGROUP_COUNT);
167    return eventset_from_mask((1u << id1) | (1u << id2) | (1u << id3));
168}
169
170EventSet* CLG_(add_event_group)(EventSet* es, Int id)
171{
172    CLG_ASSERT(id>=0 && id<MAX_EVENTGROUP_COUNT);
173    if (!es) es = eventset_from_mask(0);
174    return eventset_from_mask(es->mask | (1u << id));
175}
176
177EventSet* CLG_(add_event_group2)(EventSet* es, Int id1, Int id2)
178{
179    CLG_ASSERT(id1>=0 && id1<MAX_EVENTGROUP_COUNT);
180    CLG_ASSERT(id2>=0 && id2<MAX_EVENTGROUP_COUNT);
181    if (!es) es = eventset_from_mask(0);
182    return eventset_from_mask(es->mask | (1u << id1) | (1u << id2));
183}
184
185EventSet* CLG_(add_event_set)(EventSet* es1, EventSet* es2)
186{
187    if (!es1) es1 = eventset_from_mask(0);
188    if (!es2) es2 = eventset_from_mask(0);
189    return eventset_from_mask(es1->mask | es2->mask);
190}
191
192Int CLG_(sprint_eventset)(Char* buf, EventSet* es)
193{
194    Int i, j, pos;
195    UInt mask;
196    EventGroup* eg;
197
198
199    CLG_ASSERT(es->size >0);
200    pos = 0;
201    for(i=0, mask=1; i<MAX_EVENTGROUP_COUNT; i++, mask=mask<<1) {
202	if ((es->mask & mask)==0) continue;
203	if (eventGroup[i] ==0) continue;
204
205	eg = eventGroup[i];
206	for(j=0; j<eg->size; j++) {
207	    if (pos>0) buf[pos++] = ' ';
208	    pos += VG_(sprintf)(buf + pos, "%s", eg->name[j]);
209	}
210    }
211    buf[pos] = 0;
212
213    return pos;
214}
215
216
217/* Get cost array for an event set */
218ULong* CLG_(get_eventset_cost)(EventSet* es)
219{
220    return CLG_(get_costarray)(es->size);
221}
222
223/* Set all costs of an event set to zero */
224void CLG_(init_cost)(EventSet* es, ULong* cost)
225{
226    Int i;
227
228    if (!cost) return;
229
230    for(i=0; i<es->size; i++)
231	cost[i] = 0;
232}
233
234/* Set all costs of an event set to zero */
235void CLG_(init_cost_lz)(EventSet* es, ULong** cost)
236{
237    Int i;
238
239    CLG_ASSERT(cost != 0);
240    if (!(*cost))
241	*cost = CLG_(get_eventset_cost)(es);
242
243    for(i=0; i<es->size; i++)
244	(*cost)[i] = 0;
245}
246
247void CLG_(zero_cost)(EventSet* es, ULong* cost)
248{
249    Int i;
250
251    if (!cost) return;
252
253    for(i=0;i<es->size;i++)
254	cost[i] = 0;
255}
256
257Bool CLG_(is_zero_cost)(EventSet* es, ULong* cost)
258{
259    Int i;
260
261    if (!cost) return True;
262
263    for(i=0; i<es->size; i++)
264	if (cost[i] != 0) return False;
265
266    return True;
267}
268
269Bool CLG_(is_equal_cost)(EventSet* es, ULong* c1, ULong* c2)
270{
271    Int i;
272
273    if (!c1) return CLG_(is_zero_cost)(es, c2);
274    if (!c2) return CLG_(is_zero_cost)(es, c1);
275
276    for(i=0; i<es->size; i++)
277	if (c1[i] != c2[i]) return False;
278
279    return True;
280}
281
282void CLG_(copy_cost)(EventSet* es, ULong* dst, ULong* src)
283{
284    Int i;
285
286    if (!src) {
287	CLG_(zero_cost)(es, dst);
288	return;
289    }
290    CLG_ASSERT(dst != 0);
291
292    for(i=0;i<es->size;i++)
293	dst[i] = src[i];
294}
295
296void CLG_(copy_cost_lz)(EventSet* es, ULong** pdst, ULong* src)
297{
298    Int i;
299    ULong* dst;
300
301    CLG_ASSERT(pdst != 0);
302
303    if (!src) {
304	CLG_(zero_cost)(es, *pdst);
305	return;
306    }
307    dst = *pdst;
308    if (!dst)
309	dst = *pdst = CLG_(get_eventset_cost)(es);
310
311    for(i=0;i<es->size;i++)
312	dst[i] = src[i];
313}
314
315void CLG_(add_cost)(EventSet* es, ULong* dst, ULong* src)
316{
317    Int i;
318
319    if (!src) return;
320    CLG_ASSERT(dst != 0);
321
322    for(i=0; i<es->size; i++)
323	dst[i] += src[i];
324}
325
326void CLG_(add_cost_lz)(EventSet* es, ULong** pdst, ULong* src)
327{
328    Int i;
329    ULong* dst;
330
331    if (!src) return;
332    CLG_ASSERT(pdst != 0);
333
334    dst = *pdst;
335    if (!dst) {
336	dst = *pdst = CLG_(get_eventset_cost)(es);
337	CLG_(copy_cost)(es, dst, src);
338	return;
339    }
340
341    for(i=0; i<es->size; i++)
342	dst[i] += src[i];
343}
344
345/* Adds src to dst and zeros src. Returns false if nothing changed */
346Bool CLG_(add_and_zero_cost)(EventSet* es, ULong* dst, ULong* src)
347{
348    Int i;
349    Bool is_nonzero = False;
350
351    CLG_ASSERT((es != 0) && (dst != 0));
352    if (!src) return False;
353
354    for(i=0; i<es->size; i++) {
355	if (src[i]==0) continue;
356	dst[i] += src[i];
357	src[i] = 0;
358	is_nonzero = True;
359    }
360
361    return is_nonzero;
362}
363
364/* Adds src to dst and zeros src. Returns false if nothing changed */
365Bool CLG_(add_and_zero_cost2)(EventSet* esDst, ULong* dst,
366			      EventSet* esSrc, ULong* src)
367{
368    Int i,j;
369    Bool is_nonzero = False;
370    UInt mask;
371    EventGroup *eg;
372    ULong *egDst, *egSrc;
373
374    CLG_ASSERT((esDst != 0) && (dst != 0) && (esSrc != 0));
375    if (!src) return False;
376
377    for(i=0, mask=1; i<MAX_EVENTGROUP_COUNT; i++, mask=mask<<1) {
378	if ((esSrc->mask & mask)==0) continue;
379	if (eventGroup[i] ==0) continue;
380
381	/* if src has a subset, dst must have, too */
382	CLG_ASSERT((esDst->mask & mask)>0);
383	eg = eventGroup[i];
384	egSrc = src + esSrc->offset[i];
385	egDst = dst + esDst->offset[i];
386	for(j=0; j<eg->size; j++) {
387	    if (egSrc[j]==0) continue;
388	    egDst[j] += egSrc[j];
389	    egSrc[j] = 0;
390	    is_nonzero = True;
391	}
392    }
393
394    return is_nonzero;
395}
396
397
398
399/* Adds difference of new and old to dst, and set old to new.
400 * Returns false if nothing changed */
401Bool CLG_(add_diff_cost)(EventSet* es, ULong* dst, ULong* old, ULong* new_cost)
402{
403    Int i;
404    Bool is_nonzero = False;
405
406    CLG_ASSERT((es != 0) && (dst != 0));
407    CLG_ASSERT(old && new_cost);
408
409    for(i=0; i<es->size; i++) {
410	if (new_cost[i] == old[i]) continue;
411	dst[i] += new_cost[i] - old[i];
412	old[i] = new_cost[i];
413	is_nonzero = True;
414    }
415
416    return is_nonzero;
417}
418
419Bool CLG_(add_diff_cost_lz)(EventSet* es, ULong** pdst, ULong* old, ULong* new_cost)
420{
421    Int i;
422    ULong* dst;
423    Bool is_nonzero = False;
424
425    CLG_ASSERT((es != 0) && (pdst != 0));
426    CLG_ASSERT(old && new_cost);
427
428    dst = *pdst;
429    if (!dst) {
430	dst = *pdst = CLG_(get_eventset_cost)(es);
431	CLG_(zero_cost)(es, dst);
432    }
433
434    for(i=0; i<es->size; i++) {
435	if (new_cost[i] == old[i]) continue;
436	dst[i] += new_cost[i] - old[i];
437	old[i] = new_cost[i];
438	is_nonzero = True;
439    }
440
441    return is_nonzero;
442}
443
444
445/* Returns number of characters written */
446Int CLG_(sprint_cost)(Char* buf, EventSet* es, ULong* c)
447{
448    Int i, pos, skipped = 0;
449
450    if (!c || es->size==0) return 0;
451
452    /* At least one entry */
453    pos = VG_(sprintf)(buf, "%llu", c[0]);
454    for(i=1; i<es->size; i++) {
455	if (c[i] == 0) {
456	    skipped++;
457	    continue;
458	}
459	while(skipped>0) {
460	    buf[pos++] = ' ';
461	    buf[pos++] = '0';
462	    skipped--;
463	}
464	buf[pos++] = ' ';
465	pos += VG_(sprintf)(buf+pos, "%llu", c[i]);
466    }
467
468    return pos;
469}
470
471
472/* Allocate space for an event mapping */
473EventMapping* CLG_(get_eventmapping)(EventSet* es)
474{
475    EventMapping* em;
476
477    CLG_ASSERT(es != 0);
478
479    em = (EventMapping*) CLG_MALLOC("cl.events.geMapping.1",
480				    sizeof(EventMapping) +
481				    sizeof(struct EventMappingEntry) *
482				    es->size);
483    em->capacity = es->size;
484    em->size = 0;
485    em->es = es;
486
487    return em;
488}
489
490void CLG_(append_event)(EventMapping* em, Char* n)
491{
492    Int i, j, offset = 0;
493    UInt mask;
494    EventGroup* eg;
495
496    CLG_ASSERT(em != 0);
497    for(i=0, mask=1; i<MAX_EVENTGROUP_COUNT; i++, mask=mask<<1) {
498	if ((em->es->mask & mask)==0) continue;
499	if (eventGroup[i] ==0) continue;
500
501	eg = eventGroup[i];
502	for(j=0; j<eg->size; j++, offset++) {
503	    if (VG_(strcmp)(n, eg->name[j])!=0)
504		    continue;
505
506	    CLG_ASSERT(em->capacity > em->size);
507	    em->entry[em->size].group = i;
508	    em->entry[em->size].index = j;
509	    em->entry[em->size].offset = offset;
510	    em->size++;
511	    return;
512	}
513    }
514}
515
516
517/* Returns number of characters written */
518Int CLG_(sprint_eventmapping)(Char* buf, EventMapping* em)
519{
520    Int i, pos = 0;
521    EventGroup* eg;
522
523    CLG_ASSERT(em != 0);
524
525    for(i=0; i< em->size; i++) {
526	if (pos>0) buf[pos++] = ' ';
527	eg = eventGroup[em->entry[i].group];
528	CLG_ASSERT(eg != 0);
529	pos += VG_(sprintf)(buf + pos, "%s", eg->name[em->entry[i].index]);
530    }
531    buf[pos] = 0;
532
533    return pos;
534}
535
536/* Returns number of characters written */
537Int CLG_(sprint_mappingcost)(Char* buf, EventMapping* em, ULong* c)
538{
539    Int i, pos, skipped = 0;
540
541    if (!c || em->size==0) return 0;
542
543    /* At least one entry */
544    pos = VG_(sprintf)(buf, "%llu", c[em->entry[0].offset]);
545
546    for(i=1; i<em->size; i++) {
547	if (c[em->entry[i].offset] == 0) {
548	    skipped++;
549	    continue;
550	}
551	while(skipped>0) {
552	    buf[pos++] = ' ';
553	    buf[pos++] = '0';
554	    skipped--;
555	}
556	buf[pos++] = ' ';
557	pos += VG_(sprintf)(buf+pos, "%llu", c[em->entry[i].offset]);
558    }
559
560    return pos;
561}
562