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