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