opd_ibs.c revision 7a33c86eb98056ef0570c99e713214f8dc56b6ef
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@amd.com> 9 * @author Paul Drongowski <paul.drongowski@amd.com> 10 * @author Suravee Suthikulpanit <suravee.suthikulpanit@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 37extern op_cpu cpu_type; 38extern int no_event_ok; 39extern int sfile_equal(struct sfile const * sf, struct sfile const * sf2); 40extern void sfile_dup(struct sfile * to, struct sfile * from); 41extern char * session_dir; 42 43/* IBS Select Counters */ 44static unsigned int ibs_selected_size; 45 46/* These flags store the IBS-derived events selection. */ 47static unsigned int ibs_fetch_selected_flag; 48static unsigned int ibs_op_selected_flag; 49static unsigned int ibs_op_ls_selected_flag; 50static unsigned int ibs_op_nb_selected_flag; 51 52/* IBS Statistics */ 53static unsigned long ibs_fetch_sample_stats; 54static unsigned long ibs_fetch_incomplete_stats; 55static unsigned long ibs_op_sample_stats; 56static unsigned long ibs_op_incomplete_stats; 57static unsigned long ibs_derived_event_stats; 58 59/* 60 * IBS Virtual Counter 61 */ 62struct opd_event ibs_vc[OP_MAX_IBS_COUNTERS]; 63 64/* IBS Virtual Counter Index(VCI) Map*/ 65unsigned int ibs_vci_map[OP_MAX_IBS_COUNTERS]; 66 67/* CPUID information */ 68unsigned int ibs_family; 69unsigned int ibs_model; 70unsigned int ibs_stepping; 71 72/* IBS Extended MSRs */ 73static unsigned long ibs_bta_enabled; 74 75/* IBS log files */ 76FILE * memaccess_log; 77FILE * 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 */ 84static 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 */ 98static 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 117static 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); 163out: 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 172static 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 192void 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 242static 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 266void 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 */ 326static 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 343void 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 352void 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 362static 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 374static 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 439static 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 458static int ibs_parse_and_set_um_fetch(char const * str) 459{ 460 if (!str) 461 return -1; 462 return 0; 463} 464 465 466static 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 481static 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 asm ("cpuid" : "=a" (v.eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "0" (1)); 500 501 ibs_family = v.family + v.ext_family; 502 ibs_model = v.model + v.ext_model; 503 ibs_stepping = v.stepping; 504#else 505 ibs_family = 0; 506 ibs_model = 0; 507 ibs_stepping = 0; 508#endif 509} 510 511 512static int ibs_init(char const * argv) 513{ 514 char * tmp, * ptr, * tok1, * tok2 = NULL; 515 unsigned int i = 0; 516 unsigned long int ibs_fetch_count = 0; 517 unsigned long int ibs_op_count = 0; 518 unsigned long int ibs_op_um = 0; 519 520 if (!argv) 521 return -1; 522 523 if (empty_line(argv) != 0) 524 return -1; 525 526 tmp = op_xstrndup(argv, strlen(argv)); 527 ptr = (char *) skip_ws(tmp); 528 529 // "fetch:event1,event2,....:count:um|op:event1,event2,.....:count:um" 530 tok1 = strtok_r(ptr, "|", &tok2); 531 532 while (tok1 != NULL) { 533 534 if (!strncmp("fetch:", tok1, strlen("fetch:"))) { 535 // Get to event section 536 tok1 = tok1 + strlen("fetch:"); 537 if (ibs_parse_and_set_events(tok1) == -1) 538 return -1; 539 540 // Get to count section 541 while (tok1) { 542 if (*tok1 == '\0') 543 return -1; 544 if (*tok1 != ':') { 545 tok1++; 546 } else { 547 tok1++; 548 break; 549 } 550 } 551 552 if (ibs_parse_counts(tok1, &ibs_fetch_count) == -1) 553 return -1; 554 555 // Get to um section 556 while (tok1) { 557 if (*tok1 == '\0') 558 return -1; 559 if (*tok1 != ':') { 560 tok1++; 561 } else { 562 tok1++; 563 break; 564 } 565 } 566 567 if (ibs_parse_and_set_um_fetch(tok1) == -1) 568 return -1; 569 570 } else if (!strncmp("op:", tok1, strlen("op:"))) { 571 // Get to event section 572 tok1 = tok1 + strlen("op:"); 573 if (ibs_parse_and_set_events(tok1) == -1) 574 return -1; 575 576 // Get to count section 577 while (tok1) { 578 if (*tok1 == '\0') 579 return -1; 580 if (*tok1 != ':') { 581 tok1++; 582 } else { 583 tok1++; 584 break; 585 } 586 } 587 588 if (ibs_parse_counts(tok1, &ibs_op_count) == -1) 589 return -1; 590 591 // Get to um section 592 while (tok1) { 593 if (*tok1 == '\0') 594 return -1; 595 if (*tok1 != ':') { 596 tok1++; 597 } else { 598 tok1++; 599 break; 600 } 601 } 602 603 if (ibs_parse_and_set_um_op(tok1, &ibs_op_um)) 604 return -1; 605 606 } else 607 return -1; 608 609 tok1 = strtok_r(NULL, "|", &tok2); 610 } 611 612 /* Initialize ibs_vc */ 613 for (i = 0 ; i < ibs_selected_size ; i++) 614 { 615 if (IS_IBS_FETCH(ibs_vc[i].value)) { 616 ibs_vc[i].count = ibs_fetch_count; 617 ibs_vc[i].um = 0; 618 } else { 619 ibs_vc[i].count = ibs_op_count; 620 ibs_vc[i].um = ibs_op_um; 621 } 622 } 623 624 // Allow no event 625 no_event_ok = 1; 626 627 check_cpuid_family_model_stepping(); 628 629 get_ibs_bta_status(); 630 631 /* Create IBS memory access log */ 632 memaccess_log = NULL; 633 if (ibs_op_um & 0x2) { 634 char filename[1024]; 635 strncpy(filename, session_dir, 1023); 636 strncat(filename, "/samples/ibs_memaccess.log", 1024); 637 if ((memaccess_log = fopen(filename, "w")) == NULL) { 638 verbprintf(vext, "Warning: Cannot create file %s\n", filename); 639 640 } else { 641 fprintf (memaccess_log, "# IBS Memory Access Log\n\n"); 642 fprintf (memaccess_log, "# Format: app_cookie,cookie,cpu,tgid,tid,pc,branch-target-address,\n"); 643 fprintf (memaccess_log, "# phy-hi:phy-low,lin-hi:lin-low,accese-type,latency\n\n"); 644 } 645 } 646 647 // Create IBS Branch Target Address (BTA) log 648 bta_log = NULL; 649 if (ibs_bta_enabled) { 650 char filename[1024]; 651 strncpy(filename, session_dir, 1023); 652 strncat(filename, "/samples/ibs_bta.log", 1024); 653 if ((bta_log = fopen(filename, "w")) == NULL) { 654 verbprintf(vext, "Warning: Cannot create file %s\n", filename); 655 } else { 656 fprintf (bta_log, "# IBS Memory Access Log\n\n"); 657 fprintf (bta_log, "# Format: app_cookie,cookie,cpu,tgid,tid,pc,branch-target-address\n\n"); 658 } 659 } 660 661 return 0; 662} 663 664 665static int ibs_deinit() 666{ 667 if (memaccess_log) { 668 fclose (memaccess_log); 669 memaccess_log = NULL; 670 } 671 672 if (bta_log) { 673 fclose (bta_log); 674 bta_log = NULL; 675 } 676 return 0; 677} 678 679 680static int ibs_print_stats() 681{ 682 printf("Nr. IBS Fetch samples : %lu (%lu entries)\n", 683 ibs_fetch_sample_stats, (ibs_fetch_sample_stats * 7)); 684 printf("Nr. IBS Fetch incompletes : %lu\n", ibs_fetch_incomplete_stats); 685 printf("Nr. IBS Op samples : %lu (%lu entries)\n", 686 ibs_op_sample_stats, (ibs_op_sample_stats * 13)); 687 printf("Nr. IBS Op incompletes : %lu\n", ibs_op_incomplete_stats); 688 printf("Nr. IBS derived events : %lu\n", ibs_derived_event_stats); 689 return 0; 690} 691 692 693static int ibs_sfile_create(struct sfile * sf) 694{ 695 unsigned int i; 696 sf->ext_files = xmalloc(ibs_selected_size * sizeof(odb_t)); 697 for (i = 0 ; i < ibs_selected_size ; ++i) 698 odb_init(&sf->ext_files[i]); 699 700 return 0; 701} 702 703 704static int ibs_sfile_dup (struct sfile * to, struct sfile * from) 705{ 706 unsigned int i; 707 if (from->ext_files != NULL) { 708 to->ext_files = xmalloc(ibs_selected_size * sizeof(odb_t)); 709 for (i = 0 ; i < ibs_selected_size ; ++i) 710 odb_init(&to->ext_files[i]); 711 } else { 712 to->ext_files = NULL; 713 } 714 return 0; 715} 716 717static int ibs_sfile_close(struct sfile * sf) 718{ 719 unsigned int i; 720 if (sf->ext_files != NULL) { 721 for (i = 0; i < ibs_selected_size ; ++i) 722 odb_close(&sf->ext_files[i]); 723 724 free(sf->ext_files); 725 sf->ext_files= NULL; 726 } 727 return 0; 728} 729 730static int ibs_sfile_sync(struct sfile * sf) 731{ 732 unsigned int i; 733 if (sf->ext_files != NULL) { 734 for (i = 0; i < ibs_selected_size ; ++i) 735 odb_sync(&sf->ext_files[i]); 736 } 737 return 0; 738} 739 740static odb_t * ibs_sfile_get(struct transient const * trans, int is_cg) 741{ 742 struct sfile * sf = trans->current; 743 struct sfile * last = trans->last; 744 struct cg_entry * cg; 745 struct list_head * pos; 746 unsigned long hash; 747 odb_t * file; 748 unsigned long counter, ibs_vci, key; 749 750 /* Note: "trans->event" for IBS is not the same as traditional 751 * events. Here, it has the actual event (0xfxxx), while the 752 * traditional event has the event index. 753 */ 754 key = get_ibs_vci_key(trans->event); 755 if (key == ~0UL) { 756 fprintf(stderr, "%s: Invalid IBS event %lu\n", __func__, trans->event); 757 abort(); 758 } 759 ibs_vci = ibs_vci_map[key]; 760 counter = ibs_vci + OP_MAX_COUNTERS; 761 762 /* Creating IBS sfile if it not already exists */ 763 if (sf->ext_files == NULL) 764 ibs_sfile_create(sf); 765 766 file = &(sf->ext_files[ibs_vci]); 767 if (!is_cg) 768 goto open; 769 770 hash = last->hashval & (CG_HASH_SIZE - 1); 771 772 /* Need to look for the right 'to'. Since we're looking for 773 * 'last', we use its hash. 774 */ 775 list_for_each(pos, &sf->cg_hash[hash]) { 776 cg = list_entry(pos, struct cg_entry, hash); 777 if (sfile_equal(last, &cg->to)) { 778 file = &(cg->to.ext_files[ibs_vci]); 779 goto open; 780 } 781 } 782 783 cg = xmalloc(sizeof(struct cg_entry)); 784 sfile_dup(&cg->to, last); 785 list_add(&cg->hash, &sf->cg_hash[hash]); 786 file = &(cg->to.ext_files[ibs_vci]); 787 788open: 789 if (!odb_open_count(file)) 790 opd_open_sample_file(file, last, sf, counter, is_cg); 791 792 /* Error is logged by opd_open_sample_file */ 793 if (!odb_open_count(file)) 794 return NULL; 795 796 return file; 797} 798 799 800/** Filled opd_event structure with IBS derived event information 801 * from the given counter value. 802 */ 803static struct opd_event * ibs_sfile_find_counter_event(unsigned long counter) 804{ 805 unsigned long ibs_vci; 806 807 if (counter >= OP_MAX_COUNTERS + OP_MAX_IBS_COUNTERS 808 || counter < OP_MAX_COUNTERS) { 809 fprintf(stderr,"Error: find_ibs_counter_event : " 810 "invalid counter value %lu.\n", counter); 811 abort(); 812 } 813 814 ibs_vci = counter - OP_MAX_COUNTERS; 815 return &ibs_vc[ibs_vci]; 816} 817 818 819struct opd_ext_sfile_handlers ibs_sfile_handlers = 820{ 821 .create = &ibs_sfile_create, 822 .dup = &ibs_sfile_dup, 823 .close = &ibs_sfile_close, 824 .sync = &ibs_sfile_sync, 825 .get = &ibs_sfile_get, 826 .find_counter_event = &ibs_sfile_find_counter_event 827}; 828 829 830struct opd_ext_handlers ibs_handlers = 831{ 832 .ext_init = &ibs_init, 833 .ext_deinit = &ibs_deinit, 834 .ext_print_stats = &ibs_print_stats, 835 .ext_sfile = &ibs_sfile_handlers 836}; 837