1 /** 2 * @file daemon/opd_ibs.c 3 * AMD Family10h Instruction Based Sampling (IBS) handling. 4 * 5 * @remark Copyright 2007-2010 OProfile authors 6 * @remark Read the file COPYING 7 * 8 * @author Jason Yeh <jason.yeh (at) amd.com> 9 * @author Paul Drongowski <paul.drongowski (at) amd.com> 10 * @author Suravee Suthikulpanit <suravee.suthikulpanit (at) amd.com> 11 * Copyright (c) 2008 Advanced Micro Devices, Inc. 12 */ 13 14 #include "op_hw_config.h" 15 #include "op_events.h" 16 #include "op_string.h" 17 #include "op_libiberty.h" 18 #include "opd_printf.h" 19 #include "opd_trans.h" 20 #include "opd_events.h" 21 #include "opd_kernel.h" 22 #include "opd_anon.h" 23 #include "opd_sfile.h" 24 #include "opd_interface.h" 25 #include "opd_mangling.h" 26 #include "opd_extended.h" 27 #include "opd_ibs.h" 28 #include "opd_ibs_trans.h" 29 #include "opd_ibs_macro.h" 30 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <errno.h> 34 #include <string.h> 35 #include <limits.h> 36 37 extern op_cpu cpu_type; 38 extern int no_event_ok; 39 extern int sfile_equal(struct sfile const * sf, struct sfile const * sf2); 40 extern void sfile_dup(struct sfile * to, struct sfile * from); 41 extern char * session_dir; 42 43 /* IBS Select Counters */ 44 static unsigned int ibs_selected_size; 45 46 /* These flags store the IBS-derived events selection. */ 47 static unsigned int ibs_fetch_selected_flag; 48 static unsigned int ibs_op_selected_flag; 49 static unsigned int ibs_op_ls_selected_flag; 50 static unsigned int ibs_op_nb_selected_flag; 51 52 /* IBS Statistics */ 53 static unsigned long ibs_fetch_sample_stats; 54 static unsigned long ibs_fetch_incomplete_stats; 55 static unsigned long ibs_op_sample_stats; 56 static unsigned long ibs_op_incomplete_stats; 57 static unsigned long ibs_derived_event_stats; 58 59 /* 60 * IBS Virtual Counter 61 */ 62 struct opd_event ibs_vc[OP_MAX_IBS_COUNTERS]; 63 64 /* IBS Virtual Counter Index(VCI) Map*/ 65 unsigned int ibs_vci_map[OP_MAX_IBS_COUNTERS]; 66 67 /* CPUID information */ 68 unsigned int ibs_family; 69 unsigned int ibs_model; 70 unsigned int ibs_stepping; 71 72 /* IBS Extended MSRs */ 73 static unsigned long ibs_bta_enabled; 74 75 /* IBS log files */ 76 FILE * memaccess_log; 77 FILE * bta_log; 78 79 /** 80 * This function converts IBS fetch event flags and values into 81 * derived events. If the tagged (sampled) fetched caused a derived 82 * event, the derived event is tallied. 83 */ 84 static void opd_log_ibs_fetch(struct transient * trans) 85 { 86 struct ibs_fetch_sample * trans_fetch = ((struct ibs_sample*)(trans->ext))->fetch; 87 if (!trans_fetch) 88 return; 89 90 trans_ibs_fetch(trans, ibs_fetch_selected_flag); 91 } 92 93 94 /** 95 * This function translates the IBS op event flags and values into 96 * IBS op derived events. If an op derived event occured, it's tallied. 97 */ 98 static void opd_log_ibs_op(struct transient * trans) 99 { 100 struct ibs_op_sample * trans_op = ((struct ibs_sample*)(trans->ext))->op; 101 if (!trans_op) 102 return; 103 104 trans_ibs_op_mask_reserved(ibs_family, trans); 105 106 if (trans_ibs_op_rip_invalid(trans) != 0) 107 return; 108 109 trans_ibs_op(trans, ibs_op_selected_flag); 110 trans_ibs_op_ls(trans, ibs_op_ls_selected_flag); 111 trans_ibs_op_nb(trans, ibs_op_nb_selected_flag); 112 trans_ibs_op_ls_memaccess(trans); 113 trans_ibs_op_bta(trans); 114 } 115 116 117 static void opd_put_ibs_sample(struct transient * trans) 118 { 119 unsigned long long event = 0; 120 struct kernel_image * k_image = NULL; 121 struct ibs_fetch_sample * trans_fetch = ((struct ibs_sample*)(trans->ext))->fetch; 122 123 if (!enough_remaining(trans, 1)) { 124 trans->remaining = 0; 125 return; 126 } 127 128 /* IBS can generate samples with invalid dcookie and 129 * in kernel address range. Map such samples to vmlinux 130 * only if the user either specifies a range, or vmlinux. 131 */ 132 if (trans->cookie == INVALID_COOKIE 133 && (k_image = find_kernel_image(trans)) != NULL 134 && (k_image->start != 0 && k_image->end != 0) 135 && trans->in_kernel == 0) 136 trans->in_kernel = 1; 137 138 if (trans->tracing != TRACING_ON) 139 trans->event = event; 140 141 /* sfile can change at each sample for kernel */ 142 if (trans->in_kernel != 0) 143 clear_trans_current(trans); 144 145 if (!trans->in_kernel && trans->cookie == NO_COOKIE) 146 trans->anon = find_anon_mapping(trans); 147 148 /* get the current sfile if needed */ 149 if (!trans->current) 150 trans->current = sfile_find(trans); 151 152 /* 153 * can happen if kernel sample falls through the cracks, or if 154 * it's a sample from an anon region we couldn't find 155 */ 156 if (!trans->current) 157 goto out; 158 159 if (trans_fetch) 160 opd_log_ibs_fetch(trans); 161 else 162 opd_log_ibs_op(trans); 163 out: 164 /* switch to trace mode */ 165 if (trans->tracing == TRACING_START) 166 trans->tracing = TRACING_ON; 167 168 update_trans_last(trans); 169 } 170 171 172 static void get_ibs_bta_status() 173 { 174 FILE * fp = NULL; 175 char buf[PATH_MAX]; 176 177 /* Default to disable */ 178 ibs_bta_enabled = 0; 179 180 snprintf(buf, PATH_MAX, "/dev/oprofile/ibs_op/branch_target"); 181 fp = fopen(buf, "r"); 182 if (!fp) 183 return; 184 185 while (fgets(buf, PATH_MAX, fp) != NULL) 186 ibs_bta_enabled = strtoul(buf, NULL, 10); 187 188 fclose(fp); 189 } 190 191 192 void code_ibs_fetch_sample(struct transient * trans) 193 { 194 struct ibs_fetch_sample * trans_fetch = NULL; 195 196 if (!enough_remaining(trans, 7)) { 197 verbprintf(vext, "not enough remaining\n"); 198 trans->remaining = 0; 199 ibs_fetch_incomplete_stats++; 200 return; 201 } 202 203 ibs_fetch_sample_stats++; 204 205 trans->ext = xmalloc(sizeof(struct ibs_sample)); 206 ((struct ibs_sample*)(trans->ext))->fetch = xmalloc(sizeof(struct ibs_fetch_sample)); 207 trans_fetch = ((struct ibs_sample*)(trans->ext))->fetch; 208 209 trans_fetch->rip = pop_buffer_value(trans); 210 211 trans_fetch->ibs_fetch_lin_addr_low = pop_buffer_value(trans); 212 trans_fetch->ibs_fetch_lin_addr_high = pop_buffer_value(trans); 213 214 trans_fetch->ibs_fetch_ctl_low = pop_buffer_value(trans); 215 trans_fetch->ibs_fetch_ctl_high = pop_buffer_value(trans); 216 trans_fetch->ibs_fetch_phys_addr_low = pop_buffer_value(trans); 217 trans_fetch->ibs_fetch_phys_addr_high = pop_buffer_value(trans); 218 219 verbprintf(vsamples, 220 "FETCH_X CPU:%ld PID:%ld RIP:%lx CTL_H:%x LAT:%d P_HI:%x P_LO:%x L_HI:%x L_LO:%x\n", 221 trans->cpu, 222 (long)trans->tgid, 223 trans_fetch->rip, 224 (trans_fetch->ibs_fetch_ctl_high >> 16) & 0x3ff, 225 (trans_fetch->ibs_fetch_ctl_high) & 0xffff, 226 trans_fetch->ibs_fetch_phys_addr_high, 227 trans_fetch->ibs_fetch_phys_addr_low, 228 trans_fetch->ibs_fetch_lin_addr_high, 229 trans_fetch->ibs_fetch_lin_addr_low) ; 230 231 /* Overwrite the trans->pc with the more accurate trans_fetch->rip */ 232 trans->pc = trans_fetch->rip; 233 234 opd_put_ibs_sample(trans); 235 236 free(trans_fetch); 237 free(trans->ext); 238 trans->ext = NULL; 239 } 240 241 242 static void get_ibs_op_bta_sample(struct transient * trans, 243 struct ibs_op_sample * trans_op) 244 { 245 // Check remaining 246 if (!enough_remaining(trans, 2)) { 247 verbprintf(vext, "not enough remaining\n"); 248 trans->remaining = 0; 249 ibs_op_incomplete_stats++; 250 return; 251 } 252 253 if (ibs_bta_enabled == 1) { 254 trans_op->ibs_op_brtgt_addr = pop_buffer_value(trans); 255 256 // Check if branch target address is valid (MSRC001_1035[37] == 1] 257 if ((trans_op->ibs_op_data1_high & (0x00000001 << 5)) == 0) { 258 trans_op->ibs_op_brtgt_addr = 0; 259 } 260 } else { 261 trans_op->ibs_op_brtgt_addr = 0; 262 } 263 } 264 265 266 void code_ibs_op_sample(struct transient * trans) 267 { 268 struct ibs_op_sample * trans_op= NULL; 269 270 if (!enough_remaining(trans, 13)) { 271 verbprintf(vext, "not enough remaining\n"); 272 trans->remaining = 0; 273 ibs_op_incomplete_stats++; 274 return; 275 } 276 277 ibs_op_sample_stats++; 278 279 trans->ext = xmalloc(sizeof(struct ibs_sample)); 280 ((struct ibs_sample*)(trans->ext))->op = xmalloc(sizeof(struct ibs_op_sample)); 281 trans_op = ((struct ibs_sample*)(trans->ext))->op; 282 283 trans_op->rip = pop_buffer_value(trans); 284 285 trans_op->ibs_op_lin_addr_low = pop_buffer_value(trans); 286 trans_op->ibs_op_lin_addr_high = pop_buffer_value(trans); 287 288 trans_op->ibs_op_data1_low = pop_buffer_value(trans); 289 trans_op->ibs_op_data1_high = pop_buffer_value(trans); 290 trans_op->ibs_op_data2_low = pop_buffer_value(trans); 291 trans_op->ibs_op_data2_high = pop_buffer_value(trans); 292 trans_op->ibs_op_data3_low = pop_buffer_value(trans); 293 trans_op->ibs_op_data3_high = pop_buffer_value(trans); 294 trans_op->ibs_op_ldst_linaddr_low = pop_buffer_value(trans); 295 trans_op->ibs_op_ldst_linaddr_high = pop_buffer_value(trans); 296 trans_op->ibs_op_phys_addr_low = pop_buffer_value(trans); 297 trans_op->ibs_op_phys_addr_high = pop_buffer_value(trans); 298 299 get_ibs_op_bta_sample(trans, trans_op); 300 301 verbprintf(vsamples, 302 "IBS_OP_X CPU:%ld PID:%d RIP:%lx D1HI:%x D1LO:%x D2LO:%x D3HI:%x D3LO:%x L_LO:%x P_LO:%x\n", 303 trans->cpu, 304 trans->tgid, 305 trans_op->rip, 306 trans_op->ibs_op_data1_high, 307 trans_op->ibs_op_data1_low, 308 trans_op->ibs_op_data2_low, 309 trans_op->ibs_op_data3_high, 310 trans_op->ibs_op_data3_low, 311 trans_op->ibs_op_ldst_linaddr_low, 312 trans_op->ibs_op_phys_addr_low); 313 314 /* Overwrite the trans->pc with the more accurate trans_op->rip */ 315 trans->pc = trans_op->rip; 316 317 opd_put_ibs_sample(trans); 318 319 free(trans_op); 320 free(trans->ext); 321 trans->ext = NULL; 322 } 323 324 325 /** Convert IBS event to value used for data structure indexing */ 326 static unsigned long ibs_event_to_counter(unsigned long x) 327 { 328 unsigned long ret = ~0UL; 329 330 if (IS_IBS_FETCH(x)) 331 ret = (x - IBS_FETCH_BASE); 332 else if (IS_IBS_OP(x)) 333 ret = (x - IBS_OP_BASE + IBS_FETCH_MAX); 334 else if (IS_IBS_OP_LS(x)) 335 ret = (x - IBS_OP_LS_BASE + IBS_OP_MAX + IBS_FETCH_MAX); 336 else if (IS_IBS_OP_NB(x)) 337 ret = (x - IBS_OP_NB_BASE + IBS_OP_LS_MAX + IBS_OP_MAX + IBS_FETCH_MAX); 338 339 return (ret != ~0UL) ? ret + OP_MAX_COUNTERS : ret; 340 } 341 342 343 void opd_log_ibs_event(unsigned int event, 344 struct transient * trans) 345 { 346 ibs_derived_event_stats++; 347 trans->event = event; 348 sfile_log_sample_count(trans, 1); 349 } 350 351 352 void opd_log_ibs_count(unsigned int event, 353 struct transient * trans, 354 unsigned int count) 355 { 356 ibs_derived_event_stats++; 357 trans->event = event; 358 sfile_log_sample_count(trans, count); 359 } 360 361 362 static unsigned long get_ibs_vci_key(unsigned int event) 363 { 364 unsigned long key = ibs_event_to_counter(event); 365 if (key == ~0UL || key < OP_MAX_COUNTERS) 366 return ~0UL; 367 368 key = key - OP_MAX_COUNTERS; 369 370 return key; 371 } 372 373 374 static int ibs_parse_and_set_events(char * str) 375 { 376 char * tmp, * ptr, * tok1, * tok2 = NULL; 377 int is_done = 0; 378 struct op_event * event = NULL; 379 op_cpu cpu_type = CPU_NO_GOOD; 380 unsigned long key; 381 382 if (!str) 383 return -1; 384 385 cpu_type = op_get_cpu_type(); 386 op_events(cpu_type); 387 388 tmp = op_xstrndup(str, strlen(str)); 389 ptr = tmp; 390 391 while (is_done != 1 392 && (tok1 = strtok_r(ptr, ",", &tok2)) != NULL) { 393 394 if ((ptr = strstr(tok1, ":")) != NULL) { 395 *ptr = '\0'; 396 is_done = 1; 397 } 398 399 // Resove event number 400 event = find_event_by_name(tok1, 0, 0); 401 if (!event) 402 return -1; 403 404 // Grouping 405 if (IS_IBS_FETCH(event->val)) { 406 ibs_fetch_selected_flag |= 1 << IBS_FETCH_OFFSET(event->val); 407 } else if (IS_IBS_OP(event->val)) { 408 ibs_op_selected_flag |= 1 << IBS_OP_OFFSET(event->val); 409 } else if (IS_IBS_OP_LS(event->val)) { 410 ibs_op_ls_selected_flag |= 1 << IBS_OP_LS_OFFSET(event->val); 411 } else if (IS_IBS_OP_NB(event->val)) { 412 ibs_op_nb_selected_flag |= 1 << IBS_OP_NB_OFFSET(event->val); 413 } else { 414 return -1; 415 } 416 417 key = get_ibs_vci_key(event->val); 418 if (key == ~0UL) 419 return -1; 420 421 ibs_vci_map[key] = ibs_selected_size; 422 423 /* Initialize part of ibs_vc */ 424 ibs_vc[ibs_selected_size].name = tok1; 425 ibs_vc[ibs_selected_size].value = event->val; 426 ibs_vc[ibs_selected_size].counter = ibs_selected_size + OP_MAX_COUNTERS; 427 ibs_vc[ibs_selected_size].kernel = 1; 428 ibs_vc[ibs_selected_size].user = 1; 429 430 ibs_selected_size++; 431 432 ptr = NULL; 433 } 434 435 return 0; 436 } 437 438 439 static int ibs_parse_counts(char * str, unsigned long int * count) 440 { 441 char * tmp, * tok1, * tok2 = NULL, *end = NULL; 442 if (!str) 443 return -1; 444 445 tmp = op_xstrndup(str, strlen(str)); 446 tok1 = strtok_r(tmp, ":", &tok2); 447 *count = strtoul(tok1, &end, 10); 448 if ((end && *end) || *count == 0 449 || errno == EINVAL || errno == ERANGE) { 450 fprintf(stderr,"Invalid count (%s)\n", str); 451 return -1; 452 } 453 454 return 0; 455 } 456 457 458 static int ibs_parse_and_set_um_fetch(char const * str) 459 { 460 if (!str) 461 return -1; 462 return 0; 463 } 464 465 466 static int ibs_parse_and_set_um_op(char const * str, unsigned long int * ibs_op_um) 467 { 468 char * end = NULL; 469 if (!str) 470 return -1; 471 472 *ibs_op_um = strtoul(str, &end, 16); 473 if ((end && *end) || errno == EINVAL || errno == ERANGE) { 474 fprintf(stderr,"Invalid unitmaks (%s)\n", str); 475 return -1; 476 } 477 return 0; 478 } 479 480 481 static void check_cpuid_family_model_stepping() 482 { 483 #if defined(__i386__) || defined(__x86_64__) 484 union { 485 unsigned eax; 486 struct { 487 unsigned stepping : 4; 488 unsigned model : 4; 489 unsigned family : 4; 490 unsigned res : 4; 491 unsigned ext_model : 4; 492 unsigned ext_family : 8; 493 unsigned res2 : 4; 494 }; 495 } v; 496 unsigned ebx, ecx, edx; 497 498 /* CPUID Fn0000_0001_EAX Family, Model, Stepping */ 499 #ifdef __PIC__ 500 __asm__ __volatile__ ( 501 "pushl %%ebx\n" 502 "cpuid\n" 503 "mov %%ebx, %1\n" 504 "popl %%ebx" 505 : "=a" (v.eax), "=r" (ebx), "=c" (ecx), "=d" (edx) : "0" (1) 506 ); 507 #else 508 asm ("cpuid" : "=a" (v.eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "0" (1)); 509 #endif 510 511 ibs_family = v.family + v.ext_family; 512 ibs_model = v.model + v.ext_model; 513 ibs_stepping = v.stepping; 514 #else 515 ibs_family = 0; 516 ibs_model = 0; 517 ibs_stepping = 0; 518 #endif 519 } 520 521 522 static int ibs_init(char const * argv) 523 { 524 char * tmp, * ptr, * tok1, * tok2 = NULL; 525 unsigned int i = 0; 526 unsigned long int ibs_fetch_count = 0; 527 unsigned long int ibs_op_count = 0; 528 unsigned long int ibs_op_um = 0; 529 530 if (!argv) 531 return -1; 532 533 if (empty_line(argv) != 0) 534 return -1; 535 536 tmp = op_xstrndup(argv, strlen(argv)); 537 ptr = (char *) skip_ws(tmp); 538 539 // "fetch:event1,event2,....:count:um|op:event1,event2,.....:count:um" 540 tok1 = strtok_r(ptr, "|", &tok2); 541 542 while (tok1 != NULL) { 543 544 if (!strncmp("fetch:", tok1, strlen("fetch:"))) { 545 // Get to event section 546 tok1 = tok1 + strlen("fetch:"); 547 if (ibs_parse_and_set_events(tok1) == -1) 548 return -1; 549 550 // Get to count section 551 while (tok1) { 552 if (*tok1 == '\0') 553 return -1; 554 if (*tok1 != ':') { 555 tok1++; 556 } else { 557 tok1++; 558 break; 559 } 560 } 561 562 if (ibs_parse_counts(tok1, &ibs_fetch_count) == -1) 563 return -1; 564 565 // Get to um section 566 while (tok1) { 567 if (*tok1 == '\0') 568 return -1; 569 if (*tok1 != ':') { 570 tok1++; 571 } else { 572 tok1++; 573 break; 574 } 575 } 576 577 if (ibs_parse_and_set_um_fetch(tok1) == -1) 578 return -1; 579 580 } else if (!strncmp("op:", tok1, strlen("op:"))) { 581 // Get to event section 582 tok1 = tok1 + strlen("op:"); 583 if (ibs_parse_and_set_events(tok1) == -1) 584 return -1; 585 586 // Get to count section 587 while (tok1) { 588 if (*tok1 == '\0') 589 return -1; 590 if (*tok1 != ':') { 591 tok1++; 592 } else { 593 tok1++; 594 break; 595 } 596 } 597 598 if (ibs_parse_counts(tok1, &ibs_op_count) == -1) 599 return -1; 600 601 // Get to um section 602 while (tok1) { 603 if (*tok1 == '\0') 604 return -1; 605 if (*tok1 != ':') { 606 tok1++; 607 } else { 608 tok1++; 609 break; 610 } 611 } 612 613 if (ibs_parse_and_set_um_op(tok1, &ibs_op_um)) 614 return -1; 615 616 } else 617 return -1; 618 619 tok1 = strtok_r(NULL, "|", &tok2); 620 } 621 622 /* Initialize ibs_vc */ 623 for (i = 0 ; i < ibs_selected_size ; i++) 624 { 625 if (IS_IBS_FETCH(ibs_vc[i].value)) { 626 ibs_vc[i].count = ibs_fetch_count; 627 ibs_vc[i].um = 0; 628 } else { 629 ibs_vc[i].count = ibs_op_count; 630 ibs_vc[i].um = ibs_op_um; 631 } 632 } 633 634 // Allow no event 635 no_event_ok = 1; 636 637 check_cpuid_family_model_stepping(); 638 639 get_ibs_bta_status(); 640 641 /* Create IBS memory access log */ 642 memaccess_log = NULL; 643 if (ibs_op_um & 0x2) { 644 char filename[1024]; 645 strncpy(filename, session_dir, 1023); 646 strncat(filename, "/samples/ibs_memaccess.log", 1024); 647 if ((memaccess_log = fopen(filename, "w")) == NULL) { 648 verbprintf(vext, "Warning: Cannot create file %s\n", filename); 649 650 } else { 651 fprintf (memaccess_log, "# IBS Memory Access Log\n\n"); 652 fprintf (memaccess_log, "# Format: app_cookie,cookie,cpu,tgid,tid,pc,branch-target-address,\n"); 653 fprintf (memaccess_log, "# phy-hi:phy-low,lin-hi:lin-low,accese-type,latency\n\n"); 654 } 655 } 656 657 // Create IBS Branch Target Address (BTA) log 658 bta_log = NULL; 659 if (ibs_bta_enabled) { 660 char filename[1024]; 661 strncpy(filename, session_dir, 1023); 662 strncat(filename, "/samples/ibs_bta.log", 1024); 663 if ((bta_log = fopen(filename, "w")) == NULL) { 664 verbprintf(vext, "Warning: Cannot create file %s\n", filename); 665 } else { 666 fprintf (bta_log, "# IBS Memory Access Log\n\n"); 667 fprintf (bta_log, "# Format: app_cookie,cookie,cpu,tgid,tid,pc,branch-target-address\n\n"); 668 } 669 } 670 671 return 0; 672 } 673 674 675 static int ibs_deinit() 676 { 677 if (memaccess_log) { 678 fclose (memaccess_log); 679 memaccess_log = NULL; 680 } 681 682 if (bta_log) { 683 fclose (bta_log); 684 bta_log = NULL; 685 } 686 return 0; 687 } 688 689 690 static int ibs_print_stats() 691 { 692 printf("Nr. IBS Fetch samples : %lu (%lu entries)\n", 693 ibs_fetch_sample_stats, (ibs_fetch_sample_stats * 7)); 694 printf("Nr. IBS Fetch incompletes : %lu\n", ibs_fetch_incomplete_stats); 695 printf("Nr. IBS Op samples : %lu (%lu entries)\n", 696 ibs_op_sample_stats, (ibs_op_sample_stats * 13)); 697 printf("Nr. IBS Op incompletes : %lu\n", ibs_op_incomplete_stats); 698 printf("Nr. IBS derived events : %lu\n", ibs_derived_event_stats); 699 return 0; 700 } 701 702 703 static int ibs_sfile_create(struct sfile * sf) 704 { 705 unsigned int i; 706 sf->ext_files = xmalloc(ibs_selected_size * sizeof(odb_t)); 707 for (i = 0 ; i < ibs_selected_size ; ++i) 708 odb_init(&sf->ext_files[i]); 709 710 return 0; 711 } 712 713 714 static int ibs_sfile_dup (struct sfile * to, struct sfile * from) 715 { 716 unsigned int i; 717 if (from->ext_files != NULL) { 718 to->ext_files = xmalloc(ibs_selected_size * sizeof(odb_t)); 719 for (i = 0 ; i < ibs_selected_size ; ++i) 720 odb_init(&to->ext_files[i]); 721 } else { 722 to->ext_files = NULL; 723 } 724 return 0; 725 } 726 727 static int ibs_sfile_close(struct sfile * sf) 728 { 729 unsigned int i; 730 if (sf->ext_files != NULL) { 731 for (i = 0; i < ibs_selected_size ; ++i) 732 odb_close(&sf->ext_files[i]); 733 734 free(sf->ext_files); 735 sf->ext_files= NULL; 736 } 737 return 0; 738 } 739 740 static int ibs_sfile_sync(struct sfile * sf) 741 { 742 unsigned int i; 743 if (sf->ext_files != NULL) { 744 for (i = 0; i < ibs_selected_size ; ++i) 745 odb_sync(&sf->ext_files[i]); 746 } 747 return 0; 748 } 749 750 static odb_t * ibs_sfile_get(struct transient const * trans, int is_cg) 751 { 752 struct sfile * sf = trans->current; 753 struct sfile * last = trans->last; 754 struct cg_entry * cg; 755 struct list_head * pos; 756 unsigned long hash; 757 odb_t * file; 758 unsigned long counter, ibs_vci, key; 759 760 /* Note: "trans->event" for IBS is not the same as traditional 761 * events. Here, it has the actual event (0xfxxx), while the 762 * traditional event has the event index. 763 */ 764 key = get_ibs_vci_key(trans->event); 765 if (key == ~0UL) { 766 fprintf(stderr, "%s: Invalid IBS event %lu\n", __func__, trans->event); 767 abort(); 768 } 769 ibs_vci = ibs_vci_map[key]; 770 counter = ibs_vci + OP_MAX_COUNTERS; 771 772 /* Creating IBS sfile if it not already exists */ 773 if (sf->ext_files == NULL) 774 ibs_sfile_create(sf); 775 776 file = &(sf->ext_files[ibs_vci]); 777 if (!is_cg) 778 goto open; 779 780 hash = last->hashval & (CG_HASH_SIZE - 1); 781 782 /* Need to look for the right 'to'. Since we're looking for 783 * 'last', we use its hash. 784 */ 785 list_for_each(pos, &sf->cg_hash[hash]) { 786 cg = list_entry(pos, struct cg_entry, hash); 787 if (sfile_equal(last, &cg->to)) { 788 file = &(cg->to.ext_files[ibs_vci]); 789 goto open; 790 } 791 } 792 793 cg = xmalloc(sizeof(struct cg_entry)); 794 sfile_dup(&cg->to, last); 795 list_add(&cg->hash, &sf->cg_hash[hash]); 796 file = &(cg->to.ext_files[ibs_vci]); 797 798 open: 799 if (!odb_open_count(file)) 800 opd_open_sample_file(file, last, sf, counter, is_cg); 801 802 /* Error is logged by opd_open_sample_file */ 803 if (!odb_open_count(file)) 804 return NULL; 805 806 return file; 807 } 808 809 810 /** Filled opd_event structure with IBS derived event information 811 * from the given counter value. 812 */ 813 static struct opd_event * ibs_sfile_find_counter_event(unsigned long counter) 814 { 815 unsigned long ibs_vci; 816 817 if (counter >= OP_MAX_COUNTERS + OP_MAX_IBS_COUNTERS 818 || counter < OP_MAX_COUNTERS) { 819 fprintf(stderr,"Error: find_ibs_counter_event : " 820 "invalid counter value %lu.\n", counter); 821 abort(); 822 } 823 824 ibs_vci = counter - OP_MAX_COUNTERS; 825 return &ibs_vc[ibs_vci]; 826 } 827 828 829 struct opd_ext_sfile_handlers ibs_sfile_handlers = 830 { 831 .create = &ibs_sfile_create, 832 .dup = &ibs_sfile_dup, 833 .close = &ibs_sfile_close, 834 .sync = &ibs_sfile_sync, 835 .get = &ibs_sfile_get, 836 .find_counter_event = &ibs_sfile_find_counter_event 837 }; 838 839 840 struct opd_ext_handlers ibs_handlers = 841 { 842 .ext_init = &ibs_init, 843 .ext_deinit = &ibs_deinit, 844 .ext_print_stats = &ibs_print_stats, 845 .ext_sfile = &ibs_sfile_handlers 846 }; 847