• 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-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 
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  */
opd_log_ibs_fetch(struct transient * trans)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  */
opd_log_ibs_op(struct transient * trans)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 
opd_put_ibs_sample(struct transient * trans)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 
get_ibs_bta_status()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 
code_ibs_fetch_sample(struct transient * trans)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 
get_ibs_op_bta_sample(struct transient * trans,struct ibs_op_sample * trans_op)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 
code_ibs_op_sample(struct transient * trans)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 */
ibs_event_to_counter(unsigned long x)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 
opd_log_ibs_event(unsigned int event,struct transient * trans)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 
opd_log_ibs_count(unsigned int event,struct transient * trans,unsigned int count)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 
get_ibs_vci_key(unsigned int event)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 
ibs_parse_and_set_events(char * str)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 
ibs_parse_counts(char * str,unsigned long int * count)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 
ibs_parse_and_set_um_fetch(char const * str)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 
ibs_parse_and_set_um_op(char const * str,unsigned long int * ibs_op_um)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 
check_cpuid_family_model_stepping()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 
ibs_init(char const * argv)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 
ibs_deinit()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 
ibs_print_stats()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 
ibs_sfile_create(struct sfile * sf)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 
ibs_sfile_dup(struct sfile * to,struct sfile * from)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 
ibs_sfile_close(struct sfile * sf)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 
ibs_sfile_sync(struct sfile * sf)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 
ibs_sfile_get(struct transient const * trans,int is_cg)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  */
ibs_sfile_find_counter_event(unsigned long counter)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