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 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 
     36 extern op_cpu cpu_type;
     37 extern int no_event_ok;
     38 extern int sfile_equal(struct sfile const * sf, struct sfile const * sf2);
     39 extern void sfile_dup(struct sfile * to, struct sfile * from);
     40 
     41 /* IBS Select Arrays/Counters */
     42 static unsigned int ibs_selected_size;
     43 static unsigned int ibs_fetch_selected_flag;
     44 static unsigned int ibs_fetch_selected_size;
     45 static unsigned int ibs_op_selected_flag;
     46 static unsigned int ibs_op_selected_size;
     47 static unsigned int ibs_op_ls_selected_flag;
     48 static unsigned int ibs_op_ls_selected_size;
     49 static unsigned int ibs_op_nb_selected_flag;
     50 static unsigned int ibs_op_nb_selected_size;
     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 /**
     68  * This function converts IBS fetch event flags and values into
     69  * derived events. If the tagged (sampled) fetched caused a derived
     70  * event, the derived event is tallied.
     71  */
     72 static void opd_log_ibs_fetch(struct transient * trans)
     73 {
     74 	struct ibs_fetch_sample * trans_fetch = ((struct ibs_sample*)(trans->ext))->fetch;
     75 	if (!trans_fetch)
     76 		return;
     77 
     78 	trans_ibs_fetch(trans, ibs_fetch_selected_flag, ibs_fetch_selected_size);
     79 }
     80 
     81 
     82 /**
     83  * This function translates the IBS op event flags and values into
     84  * IBS op derived events. If an op derived event occured, it's tallied.
     85  */
     86 static void opd_log_ibs_op(struct transient * trans)
     87 {
     88 	struct ibs_op_sample * trans_op = ((struct ibs_sample*)(trans->ext))->op;
     89 	if (!trans_op)
     90 		return;
     91 
     92 	trans_ibs_op(trans, ibs_op_selected_flag, ibs_op_selected_size);
     93 	trans_ibs_op_ls(trans, ibs_op_ls_selected_flag, ibs_op_ls_selected_size);
     94 	trans_ibs_op_nb(trans, ibs_op_nb_selected_flag, ibs_op_nb_selected_size);
     95 }
     96 
     97 
     98 static void opd_put_ibs_sample(struct transient * trans)
     99 {
    100 	unsigned long long event = 0;
    101 	struct kernel_image * k_image = NULL;
    102 	struct ibs_fetch_sample * trans_fetch = ((struct ibs_sample*)(trans->ext))->fetch;
    103 
    104 	if (!enough_remaining(trans, 1)) {
    105 		trans->remaining = 0;
    106 		return;
    107 	}
    108 
    109 	/* IBS can generate samples with invalid dcookie and
    110 	 * in kernel address range. Map such samples to vmlinux
    111 	 * only if the user either specifies a range, or vmlinux.
    112 	 */
    113 	if (trans->cookie == INVALID_COOKIE
    114 	    && (k_image = find_kernel_image(trans)) != NULL
    115 	    && (k_image->start != 0 && k_image->end != 0)
    116 	    && trans->in_kernel == 0)
    117 		trans->in_kernel = 1;
    118 
    119 	if (trans->tracing != TRACING_ON)
    120 		trans->event = event;
    121 
    122 	/* sfile can change at each sample for kernel */
    123 	if (trans->in_kernel != 0)
    124 		clear_trans_current(trans);
    125 
    126 	if (!trans->in_kernel && trans->cookie == NO_COOKIE)
    127 		trans->anon = find_anon_mapping(trans);
    128 
    129 	/* get the current sfile if needed */
    130 	if (!trans->current)
    131 		trans->current = sfile_find(trans);
    132 
    133 	/*
    134 	 * can happen if kernel sample falls through the cracks, or if
    135 	 * it's a sample from an anon region we couldn't find
    136 	 */
    137 	if (!trans->current)
    138 		goto out;
    139 
    140 	if (trans_fetch)
    141 		opd_log_ibs_fetch(trans);
    142 	else
    143 		opd_log_ibs_op(trans);
    144 out:
    145 	/* switch to trace mode */
    146 	if (trans->tracing == TRACING_START)
    147 		trans->tracing = TRACING_ON;
    148 
    149 	update_trans_last(trans);
    150 }
    151 
    152 
    153 void code_ibs_fetch_sample(struct transient * trans)
    154 {
    155 	struct ibs_fetch_sample * trans_fetch = NULL;
    156 
    157 	if (!enough_remaining(trans, 7)) {
    158 		verbprintf(vext, "not enough remaining\n");
    159 		trans->remaining = 0;
    160 		ibs_fetch_incomplete_stats++;
    161 		return;
    162 	}
    163 
    164 	ibs_fetch_sample_stats++;
    165 
    166 	trans->ext = xmalloc(sizeof(struct ibs_sample));
    167 	((struct ibs_sample*)(trans->ext))->fetch = xmalloc(sizeof(struct ibs_fetch_sample));
    168 	trans_fetch = ((struct ibs_sample*)(trans->ext))->fetch;
    169 
    170 	trans_fetch->rip = pop_buffer_value(trans);
    171 
    172 	trans_fetch->ibs_fetch_lin_addr_low = pop_buffer_value(trans);
    173 	trans_fetch->ibs_fetch_lin_addr_high = pop_buffer_value(trans);
    174 
    175 	trans_fetch->ibs_fetch_ctl_low = pop_buffer_value(trans);
    176 	trans_fetch->ibs_fetch_ctl_high = pop_buffer_value(trans);
    177 	trans_fetch->ibs_fetch_phys_addr_low = pop_buffer_value(trans);
    178 	trans_fetch->ibs_fetch_phys_addr_high = pop_buffer_value(trans);
    179 
    180 	verbprintf(vsamples,
    181 		"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",
    182 		trans->cpu,
    183 		(long)trans->tgid,
    184 		trans_fetch->rip,
    185 		(trans_fetch->ibs_fetch_ctl_high >> 16) & 0x3ff,
    186 		(trans_fetch->ibs_fetch_ctl_high) & 0xffff,
    187 		trans_fetch->ibs_fetch_phys_addr_high,
    188 		trans_fetch->ibs_fetch_phys_addr_low,
    189 		trans_fetch->ibs_fetch_lin_addr_high,
    190 		trans_fetch->ibs_fetch_lin_addr_low) ;
    191 
    192 	/* Overwrite the trans->pc with the more accurate trans_fetch->rip */
    193 	trans->pc = trans_fetch->rip;
    194 
    195 	opd_put_ibs_sample(trans);
    196 
    197 	free(trans_fetch);
    198 	free(trans->ext);
    199 	trans->ext = NULL;
    200 }
    201 
    202 
    203 void code_ibs_op_sample(struct transient * trans)
    204 {
    205 	struct ibs_op_sample * trans_op= NULL;
    206 
    207 	if (!enough_remaining(trans, 13)) {
    208 		verbprintf(vext, "not enough remaining\n");
    209 		trans->remaining = 0;
    210 		ibs_op_incomplete_stats++;
    211 		return;
    212 	}
    213 
    214 	ibs_op_sample_stats++;
    215 
    216 	trans->ext = xmalloc(sizeof(struct ibs_sample));
    217 	((struct ibs_sample*)(trans->ext))->op = xmalloc(sizeof(struct ibs_op_sample));
    218 	trans_op = ((struct ibs_sample*)(trans->ext))->op;
    219 
    220 	trans_op->rip = pop_buffer_value(trans);
    221 
    222 	trans_op->ibs_op_lin_addr_low = pop_buffer_value(trans);
    223 	trans_op->ibs_op_lin_addr_high = pop_buffer_value(trans);
    224 
    225 	trans_op->ibs_op_data1_low         = pop_buffer_value(trans);
    226 	trans_op->ibs_op_data1_high        = pop_buffer_value(trans);
    227 	trans_op->ibs_op_data2_low         = pop_buffer_value(trans);
    228 	trans_op->ibs_op_data2_high        = pop_buffer_value(trans);
    229 	trans_op->ibs_op_data3_low         = pop_buffer_value(trans);
    230 	trans_op->ibs_op_data3_high        = pop_buffer_value(trans);
    231 	trans_op->ibs_op_ldst_linaddr_low  = pop_buffer_value(trans);
    232 	trans_op->ibs_op_ldst_linaddr_high = pop_buffer_value(trans);
    233 	trans_op->ibs_op_phys_addr_low     = pop_buffer_value(trans);
    234 	trans_op->ibs_op_phys_addr_high    = pop_buffer_value(trans);
    235 
    236 	verbprintf(vsamples,
    237 		   "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",
    238 		   trans->cpu,
    239 		   trans->tgid,
    240 		   trans_op->rip,
    241 		   trans_op->ibs_op_data1_high,
    242 		   trans_op->ibs_op_data1_low,
    243 		   trans_op->ibs_op_data2_low,
    244 		   trans_op->ibs_op_data3_high,
    245 		   trans_op->ibs_op_data3_low,
    246 		   trans_op->ibs_op_ldst_linaddr_low,
    247 		   trans_op->ibs_op_phys_addr_low);
    248 
    249 	/* Overwrite the trans->pc with the more accurate trans_op->rip */
    250 	trans->pc = trans_op->rip;
    251 
    252 	opd_put_ibs_sample(trans);
    253 
    254 	free(trans_op);
    255 	free(trans->ext);
    256 	trans->ext = NULL;
    257 }
    258 
    259 
    260 /** Convert IBS event to value used for data structure indexing */
    261 static unsigned long ibs_event_to_counter(unsigned long x)
    262 {
    263 	unsigned long ret = ~0UL;
    264 
    265 	if (IS_IBS_FETCH(x))
    266 		ret = (x - IBS_FETCH_BASE);
    267 	else if (IS_IBS_OP(x))
    268 		ret = (x - IBS_OP_BASE + IBS_FETCH_MAX);
    269 	else if (IS_IBS_OP_LS(x))
    270 		ret = (x - IBS_OP_LS_BASE + IBS_OP_MAX + IBS_FETCH_MAX);
    271 	else if (IS_IBS_OP_NB(x))
    272 		ret = (x - IBS_OP_NB_BASE + IBS_OP_LS_MAX + IBS_OP_MAX + IBS_FETCH_MAX);
    273 
    274 	return (ret != ~0UL) ? ret + OP_MAX_COUNTERS : ret;
    275 }
    276 
    277 
    278 void opd_log_ibs_event(unsigned int event,
    279 	struct transient * trans)
    280 {
    281 	ibs_derived_event_stats++;
    282 	trans->event = event;
    283 	sfile_log_sample_count(trans, 1);
    284 }
    285 
    286 
    287 void opd_log_ibs_count(unsigned int event,
    288 			struct transient * trans,
    289 			unsigned int count)
    290 {
    291 	ibs_derived_event_stats++;
    292 	trans->event = event;
    293 	sfile_log_sample_count(trans, count);
    294 }
    295 
    296 
    297 static unsigned long get_ibs_vci_key(unsigned int event)
    298 {
    299 	unsigned long key = ibs_event_to_counter(event);
    300 	if (key == ~0UL || key < OP_MAX_COUNTERS)
    301 		return ~0UL;
    302 
    303 	key = key - OP_MAX_COUNTERS;
    304 
    305 	return key;
    306 }
    307 
    308 
    309 static int ibs_parse_and_set_events(char * str)
    310 {
    311 	char * tmp, * ptr, * tok1, * tok2 = NULL;
    312 	int is_done = 0;
    313 	struct op_event * event = NULL;
    314 	op_cpu cpu_type = CPU_NO_GOOD;
    315 	unsigned long key;
    316 
    317 	if (!str)
    318 		return -1;
    319 
    320 	cpu_type = op_get_cpu_type();
    321 	op_events(cpu_type);
    322 
    323 	tmp = op_xstrndup(str, strlen(str));
    324 	ptr = tmp;
    325 
    326 	while (is_done != 1
    327 		&& (tok1 = strtok_r(ptr, ",", &tok2)) != NULL) {
    328 
    329 		if ((ptr = strstr(tok1, ":")) != NULL) {
    330 			*ptr = '\0';
    331 			is_done = 1;
    332 		}
    333 
    334 		// Resove event number
    335 		event = find_event_by_name(tok1, 0, 0);
    336 		if (!event)
    337 			return -1;
    338 
    339 		// Grouping
    340 		if (IS_IBS_FETCH(event->val)) {
    341 			ibs_fetch_selected_flag |= 1 << IBS_FETCH_OFFSET(event->val);
    342 			ibs_fetch_selected_size++;
    343 		} else if (IS_IBS_OP(event->val)) {
    344 			ibs_op_selected_flag |= 1 << IBS_OP_OFFSET(event->val);
    345 			ibs_op_selected_size++;
    346 		} else if (IS_IBS_OP_LS(event->val)) {
    347 			ibs_op_ls_selected_flag |= 1 << IBS_OP_LS_OFFSET(event->val);
    348 			ibs_op_ls_selected_size++;
    349 		} else if (IS_IBS_OP_NB(event->val)) {
    350 			ibs_op_nb_selected_flag |= 1 << IBS_OP_NB_OFFSET(event->val);
    351 			ibs_op_nb_selected_size++;
    352 		} else {
    353 			return -1;
    354 		}
    355 
    356 		key = get_ibs_vci_key(event->val);
    357 		if (key == ~0UL)
    358 			return -1;
    359 
    360 		ibs_vci_map[key] = ibs_selected_size;
    361 
    362 		/* Initialize part of ibs_vc */
    363 		ibs_vc[ibs_selected_size].name    = tok1;
    364 		ibs_vc[ibs_selected_size].value   = event->val;
    365 		ibs_vc[ibs_selected_size].counter = ibs_selected_size + OP_MAX_COUNTERS;
    366 		ibs_vc[ibs_selected_size].kernel  = 1;
    367 		ibs_vc[ibs_selected_size].user    = 1;
    368 
    369 		ibs_selected_size++;
    370 
    371 		ptr = NULL;
    372 	}
    373 
    374 	return 0;
    375 }
    376 
    377 
    378 static int ibs_parse_counts(char * str, unsigned long int * count)
    379 {
    380 	char * tmp, * tok1, * tok2 = NULL, *end = NULL;
    381 	if (!str)
    382 		return -1;
    383 
    384 	tmp = op_xstrndup(str, strlen(str));
    385 	tok1 = strtok_r(tmp, ":", &tok2);
    386 	*count = strtoul(tok1, &end, 10);
    387 	if ((end && *end) || *count == 0
    388 	    || errno == EINVAL || errno == ERANGE) {
    389 		fprintf(stderr,"Invalid count (%s)\n", str);
    390 		return -1;
    391 	}
    392 
    393 	return 0;
    394 }
    395 
    396 
    397 static int ibs_parse_and_set_um_fetch(char const * str)
    398 {
    399 	if (!str)
    400 		return -1;
    401 	return 0;
    402 }
    403 
    404 
    405 
    406 static int ibs_parse_and_set_um_op(char const * str, unsigned long int * ibs_op_um)
    407 {
    408 	char * end = NULL;
    409 	if (!str)
    410 		return -1;
    411 
    412 	*ibs_op_um = strtoul(str, &end, 16);
    413 	if ((end && *end) || errno == EINVAL || errno == ERANGE) {
    414 		fprintf(stderr,"Invalid unitmaks (%s)\n", str);
    415 		return -1;
    416 	}
    417 	return 0;
    418 }
    419 
    420 
    421 static int ibs_init(char const * argv)
    422 {
    423 	char * tmp, * ptr, * tok1, * tok2 = NULL;
    424 	unsigned int i = 0;
    425 	unsigned long int ibs_fetch_count = 0;
    426 	unsigned long int ibs_op_count = 0;
    427 	unsigned long int ibs_op_um = 0;
    428 
    429 	if (!argv)
    430 		return -1;
    431 
    432 	if (empty_line(argv) != 0)
    433 		return -1;
    434 
    435 	tmp = op_xstrndup(argv, strlen(argv));
    436 	ptr = (char *) skip_ws(tmp);
    437 
    438 	// "fetch:event1,event2,....:count:um|op:event1,event2,.....:count:um"
    439 	tok1 = strtok_r(ptr, "|", &tok2);
    440 
    441 	while (tok1 != NULL) {
    442 
    443 		if (!strncmp("fetch:", tok1, strlen("fetch:"))) {
    444 			// Get to event section
    445 			tok1 = tok1 + strlen("fetch:");
    446 			if (ibs_parse_and_set_events(tok1) == -1)
    447 				return -1;
    448 
    449 			// Get to count section
    450 			while (tok1) {
    451 				if (*tok1 == '\0')
    452 					return -1;
    453 				if (*tok1 != ':') {
    454 					tok1++;
    455 				} else {
    456 					tok1++;
    457 					break;
    458 				}
    459 			}
    460 
    461 			if (ibs_parse_counts(tok1, &ibs_fetch_count) == -1)
    462 				return -1;
    463 
    464 			// Get to um section
    465 			while (tok1) {
    466 				if (*tok1 == '\0')
    467 					return -1;
    468 				if (*tok1 != ':') {
    469 					tok1++;
    470 				} else {
    471 					tok1++;
    472 					break;
    473 				}
    474 			}
    475 
    476 			if (ibs_parse_and_set_um_fetch(tok1) == -1)
    477 				return -1;
    478 
    479 		} else if (!strncmp("op:", tok1, strlen("op:"))) {
    480 			// Get to event section
    481 			tok1 = tok1 + strlen("op:");
    482 			if (ibs_parse_and_set_events(tok1) == -1)
    483 				return -1;
    484 
    485 			// Get to count section
    486 			while (tok1) {
    487 				if (*tok1 == '\0')
    488 					return -1;
    489 				if (*tok1 != ':') {
    490 					tok1++;
    491 				} else {
    492 					tok1++;
    493 					break;
    494 				}
    495 			}
    496 
    497 			if (ibs_parse_counts(tok1, &ibs_op_count) == -1)
    498 				return -1;
    499 
    500 			// Get to um section
    501 			while (tok1) {
    502 				if (*tok1 == '\0')
    503 					return -1;
    504 				if (*tok1 != ':') {
    505 					tok1++;
    506 				} else {
    507 					tok1++;
    508 					break;
    509 				}
    510 			}
    511 
    512 			if (ibs_parse_and_set_um_op(tok1, &ibs_op_um))
    513 				return -1;
    514 
    515 		} else
    516 			return -1;
    517 
    518 		tok1 = strtok_r(NULL, "|", &tok2);
    519 	}
    520 
    521 	/* Initialize ibs_vc */
    522 	for (i = 0 ; i < ibs_selected_size ; i++)
    523 	{
    524 		if (IS_IBS_FETCH(ibs_vc[i].value)) {
    525 			ibs_vc[i].count   = ibs_fetch_count;
    526 			ibs_vc[i].um      = 0;
    527 		} else {
    528 			ibs_vc[i].count   = ibs_op_count;
    529 			ibs_vc[i].um      = ibs_op_um;
    530 		}
    531 	}
    532 
    533 	// Allow no event
    534 	no_event_ok = 1;
    535 	return 0;
    536 }
    537 
    538 
    539 static int ibs_print_stats()
    540 {
    541 	printf("Nr. IBS Fetch samples     : %lu (%lu entries)\n", ibs_fetch_sample_stats, (ibs_fetch_sample_stats * 7));
    542 	printf("Nr. IBS Fetch incompletes : %lu\n", ibs_fetch_incomplete_stats);
    543 	printf("Nr. IBS Op samples        : %lu (%lu entries)\n", ibs_op_sample_stats, (ibs_op_sample_stats * 13));
    544 	printf("Nr. IBS Op incompletes    : %lu\n", ibs_op_incomplete_stats);
    545 	printf("Nr. IBS derived events    : %lu\n", ibs_derived_event_stats);
    546 	return 0;
    547 }
    548 
    549 
    550 static int ibs_sfile_create(struct sfile * sf)
    551 {
    552 	unsigned int i;
    553 	sf->ext_files = xmalloc(ibs_selected_size * sizeof(odb_t));
    554 	for (i = 0 ; i < ibs_selected_size ; ++i)
    555 		odb_init(&sf->ext_files[i]);
    556 
    557 	return 0;
    558 }
    559 
    560 
    561 static int ibs_sfile_dup (struct sfile * to, struct sfile * from)
    562 {
    563 	unsigned int i;
    564 	if (from->ext_files != NULL) {
    565 		to->ext_files = xmalloc(ibs_selected_size * sizeof(odb_t));
    566 		for (i = 0 ; i < ibs_selected_size ; ++i)
    567 			odb_init(&to->ext_files[i]);
    568 	} else {
    569 		to->ext_files = NULL;
    570 	}
    571 	return 0;
    572 }
    573 
    574 static int ibs_sfile_close(struct sfile * sf)
    575 {
    576 	unsigned int i;
    577 	if (sf->ext_files != NULL) {
    578 		for (i = 0; i < ibs_selected_size ; ++i)
    579 			odb_close(&sf->ext_files[i]);
    580 
    581 		free(sf->ext_files);
    582 		sf->ext_files= NULL;
    583 	}
    584 	return 0;
    585 }
    586 
    587 static int ibs_sfile_sync(struct sfile * sf)
    588 {
    589 	unsigned int i;
    590 	if (sf->ext_files != NULL) {
    591 		for (i = 0; i < ibs_selected_size ; ++i)
    592 			odb_sync(&sf->ext_files[i]);
    593 	}
    594 	return 0;
    595 }
    596 
    597 static odb_t * ibs_sfile_get(struct transient const * trans, int is_cg)
    598 {
    599 	struct sfile * sf = trans->current;
    600 	struct sfile * last = trans->last;
    601 	struct cg_entry * cg;
    602 	struct list_head * pos;
    603 	unsigned long hash;
    604 	odb_t * file;
    605 	unsigned long counter, ibs_vci, key;
    606 
    607 	/* Note: "trans->event" for IBS is not the same as traditional
    608  	 * events.  Here, it has the actual event (0xfxxx), while the
    609  	 * traditional event has the event index.
    610  	 */
    611 	key = get_ibs_vci_key(trans->event);
    612 	if (key == ~0UL) {
    613 		fprintf(stderr, "%s: Invalid IBS event %lu\n", __func__, trans->event);
    614 		abort();
    615 	}
    616 	ibs_vci = ibs_vci_map[key];
    617 	counter = ibs_vci + OP_MAX_COUNTERS;
    618 
    619 	/* Creating IBS sfile if it not already exists */
    620 	if (sf->ext_files == NULL)
    621 		ibs_sfile_create(sf);
    622 
    623 	file = &(sf->ext_files[ibs_vci]);
    624 	if (!is_cg)
    625 		goto open;
    626 
    627 	hash = last->hashval & (CG_HASH_SIZE - 1);
    628 
    629 	/* Need to look for the right 'to'. Since we're looking for
    630 	 * 'last', we use its hash.
    631 	 */
    632 	list_for_each(pos, &sf->cg_hash[hash]) {
    633 		cg = list_entry(pos, struct cg_entry, hash);
    634 		if (sfile_equal(last, &cg->to)) {
    635 			file = &(cg->to.ext_files[ibs_vci]);
    636 			goto open;
    637 		}
    638 	}
    639 
    640 	cg = xmalloc(sizeof(struct cg_entry));
    641 	sfile_dup(&cg->to, last);
    642 	list_add(&cg->hash, &sf->cg_hash[hash]);
    643 	file = &(cg->to.ext_files[ibs_vci]);
    644 
    645 open:
    646 	if (!odb_open_count(file))
    647 		opd_open_sample_file(file, last, sf, counter, is_cg);
    648 
    649 	/* Error is logged by opd_open_sample_file */
    650 	if (!odb_open_count(file))
    651 		return NULL;
    652 
    653 	return file;
    654 }
    655 
    656 
    657 /** Filled opd_event structure with IBS derived event information
    658  *  from the given counter value.
    659  */
    660 static struct opd_event * ibs_sfile_find_counter_event(unsigned long counter)
    661 {
    662 	unsigned long ibs_vci;
    663 
    664 	if (counter >= OP_MAX_COUNTERS + OP_MAX_IBS_COUNTERS
    665 	    || counter < OP_MAX_COUNTERS) {
    666 		fprintf(stderr,"Error: find_ibs_counter_event : "
    667 				"invalid counter value %lu.\n", counter);
    668 		abort();
    669 	}
    670 
    671 	ibs_vci = counter - OP_MAX_COUNTERS;
    672 	return &ibs_vc[ibs_vci];
    673 }
    674 
    675 
    676 struct opd_ext_sfile_handlers ibs_sfile_handlers =
    677 {
    678 	.create = &ibs_sfile_create,
    679 	.dup    = &ibs_sfile_dup,
    680 	.close  = &ibs_sfile_close,
    681 	.sync   = &ibs_sfile_sync,
    682 	.get    = &ibs_sfile_get,
    683 	.find_counter_event = &ibs_sfile_find_counter_event
    684 };
    685 
    686 
    687 struct opd_ext_handlers ibs_handlers =
    688 {
    689 	.ext_init  = &ibs_init,
    690 	.ext_print_stats = &ibs_print_stats,
    691 	.ext_sfile = &ibs_sfile_handlers
    692 };
    693