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-2015, Josef Weidendorfer (Josef.Weidendorfer (at) 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 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 */ 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 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. */ 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. */ 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