• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
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  */
opd_log_ibs_fetch(struct transient * trans)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  */
opd_log_ibs_op(struct transient * trans)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 
opd_put_ibs_sample(struct transient * trans)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 
code_ibs_fetch_sample(struct transient * trans)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 
code_ibs_op_sample(struct transient * trans)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 */
ibs_event_to_counter(unsigned long x)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 
opd_log_ibs_event(unsigned int event,struct transient * trans)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 
opd_log_ibs_count(unsigned int event,struct transient * trans,unsigned int count)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 
get_ibs_vci_key(unsigned int event)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 
ibs_parse_and_set_events(char * str)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 
ibs_parse_counts(char * str,unsigned long int * count)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 
ibs_parse_and_set_um_fetch(char const * str)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 
ibs_parse_and_set_um_op(char const * str,unsigned long int * ibs_op_um)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 
ibs_init(char const * argv)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 
ibs_print_stats()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 
ibs_sfile_create(struct sfile * sf)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 
ibs_sfile_dup(struct sfile * to,struct sfile * from)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 
ibs_sfile_close(struct sfile * sf)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 
ibs_sfile_sync(struct sfile * sf)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 
ibs_sfile_get(struct transient const * trans,int is_cg)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  */
ibs_sfile_find_counter_event(unsigned long counter)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