Home | History | Annotate | Download | only in daemon
      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