Deleted Added
full compact
hwpmc_x86.c (184205) hwpmc_x86.c (184802)
1/*-
2 * Copyright (c) 2005,2008 Joseph Koshy
3 * Copyright (c) 2007 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * Portions of this software were developed by A. Joseph Koshy under
7 * sponsorship from the FreeBSD Foundation and Google, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2005,2008 Joseph Koshy
3 * Copyright (c) 2007 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * Portions of this software were developed by A. Joseph Koshy under
7 * sponsorship from the FreeBSD Foundation and Google, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_x86.c 184205 2008-10-23 15:53:51Z des $");
32__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_x86.c 184802 2008-11-09 17:37:54Z jkoshy $");
33
34#include <sys/param.h>
35#include <sys/bus.h>
36#include <sys/pmc.h>
37#include <sys/proc.h>
38#include <sys/systm.h>
39
40#include <machine/cpu.h>
41#include <machine/apicreg.h>
42#include <machine/pmc_mdep.h>
43#include <machine/md_var.h>
44
45#include <vm/vm.h>
46#include <vm/vm_param.h>
47#include <vm/pmap.h>
48
49extern volatile lapic_t *lapic;
50
51void
52pmc_x86_lapic_enable_pmc_interrupt(void)
53{
54 uint32_t value;
55
56 value = lapic->lvt_pcint;
57 value &= ~APIC_LVT_M;
58 lapic->lvt_pcint = value;
59}
60
61/*
62 * Attempt to walk a user call stack using a too-simple algorithm.
63 * In the general case we need unwind information associated with
64 * the executable to be able to walk the user stack.
65 *
66 * We are handed a trap frame laid down at the time the PMC interrupt
67 * was taken. If the application is using frame pointers, the saved
68 * PC value could be:
69 * a. at the beginning of a function before the stack frame is laid
70 * down,
71 * b. just before a 'ret', after the stack frame has been taken off,
72 * c. somewhere else in the function with a valid stack frame being
73 * present,
74 *
75 * If the application is not using frame pointers, this algorithm will
76 * fail to yield an interesting call chain.
77 *
78 * TODO: figure out a way to use unwind information.
79 */
80
81int
82pmc_save_user_callchain(uintptr_t *cc, int nframes, struct trapframe *tf)
83{
84 int n;
85 uint32_t instr;
86 uintptr_t fp, oldfp, pc, r, sp;
87
88 KASSERT(TRAPF_USERMODE(tf), ("[x86,%d] Not a user trap frame tf=%p",
89 __LINE__, (void *) tf));
90
91 pc = PMC_TRAPFRAME_TO_PC(tf);
92 oldfp = fp = PMC_TRAPFRAME_TO_FP(tf);
93 sp = PMC_TRAPFRAME_TO_USER_SP(tf);
94
95 *cc++ = pc; n = 1;
96
97 r = fp + sizeof(uintptr_t); /* points to return address */
98
99 if (!PMC_IN_USERSPACE(pc))
100 return (n);
101
102 if (copyin((void *) pc, &instr, sizeof(instr)) != 0)
103 return (n);
104
105 if (PMC_AT_FUNCTION_PROLOGUE_PUSH_BP(instr) ||
106 PMC_AT_FUNCTION_EPILOGUE_RET(instr)) { /* ret */
107 if (copyin((void *) sp, &pc, sizeof(pc)) != 0)
108 return (n);
109 } else if (PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP(instr)) {
110 sp += sizeof(uintptr_t);
111 if (copyin((void *) sp, &pc, sizeof(pc)) != 0)
112 return (n);
113 } else if (copyin((void *) r, &pc, sizeof(pc)) != 0 ||
114 copyin((void *) fp, &fp, sizeof(fp) != 0))
115 return (n);
116
117 for (; n < nframes;) {
118 if (pc == 0 || !PMC_IN_USERSPACE(pc))
119 break;
120
121 *cc++ = pc; n++;
122
123 if (fp < oldfp)
124 break;
125
126 r = fp + sizeof(uintptr_t); /* address of return address */
127 oldfp = fp;
128
129 if (copyin((void *) r, &pc, sizeof(pc)) != 0 ||
130 copyin((void *) fp, &fp, sizeof(fp)) != 0)
131 break;
132 }
133
134 return (n);
135}
136
137/*
138 * Walking the kernel call stack.
139 *
140 * We are handed the trap frame laid down at the time the PMC
141 * interrupt was taken. The saved PC could be:
142 * a. in the lowlevel trap handler, meaning that there isn't a C stack
143 * to traverse,
144 * b. at the beginning of a function before the stack frame is laid
145 * down,
146 * c. just before a 'ret', after the stack frame has been taken off,
147 * d. somewhere else in a function with a valid stack frame being
148 * present.
149 *
150 * In case (d), the previous frame pointer is at [%ebp]/[%rbp] and
151 * the return address is at [%ebp+4]/[%rbp+8].
152 *
153 * For cases (b) and (c), the return address is at [%esp]/[%rsp] and
154 * the frame pointer doesn't need to be changed when going up one
155 * level in the stack.
156 *
157 * For case (a), we check if the PC lies in low-level trap handling
158 * code, and if so we terminate our trace.
159 */
160
161int
162pmc_save_kernel_callchain(uintptr_t *cc, int nframes, struct trapframe *tf)
163{
164 int n;
165 uint32_t instr;
166 uintptr_t fp, pc, r, sp, stackstart, stackend;
167 struct thread *td;
168
169 KASSERT(TRAPF_USERMODE(tf) == 0,("[x86,%d] not a kernel backtrace",
170 __LINE__));
171
172 pc = PMC_TRAPFRAME_TO_PC(tf);
173 fp = PMC_TRAPFRAME_TO_FP(tf);
174 sp = PMC_TRAPFRAME_TO_KERNEL_SP(tf);
175
176 *cc++ = pc;
177 r = fp + sizeof(uintptr_t); /* points to return address */
178
179 if ((td = curthread) == NULL)
180 return (1);
181
182 if (nframes <= 1)
183 return (1);
184
185 stackstart = (uintptr_t) td->td_kstack;
186 stackend = (uintptr_t) td->td_kstack + td->td_kstack_pages * PAGE_SIZE;
187
188 if (PMC_IN_TRAP_HANDLER(pc) ||
189 !PMC_IN_KERNEL(pc) || !PMC_IN_KERNEL(r) ||
190 !PMC_IN_KERNEL_STACK(sp, stackstart, stackend) ||
191 !PMC_IN_KERNEL_STACK(fp, stackstart, stackend))
192 return (1);
193
194 instr = *(uint32_t *) pc;
195
196 /*
197 * Determine whether the interrupted function was in the
198 * processing of either laying down its stack frame or taking
199 * it off.
200 *
201 * If we haven't started laying down a stack frame, or are
202 * just about to return, then our caller's address is at
203 * *sp, and we don't have a frame to unwind.
204 */
205 if (PMC_AT_FUNCTION_PROLOGUE_PUSH_BP(instr) ||
206 PMC_AT_FUNCTION_EPILOGUE_RET(instr))
207 pc = *(uintptr_t *) sp;
208 else if (PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP(instr)) {
209 /*
210 * The code was midway through laying down a frame.
211 * At this point sp[0] has a frame back pointer,
212 * and the caller's address is therefore at sp[1].
213 */
214 sp += sizeof(uintptr_t);
215 if (!PMC_IN_KERNEL_STACK(sp, stackstart, stackend))
216 return (1);
217 pc = *(uintptr_t *) sp;
218 } else {
219 /*
220 * Not in the function prologue or epilogue.
221 */
222 pc = *(uintptr_t *) r;
223 fp = *(uintptr_t *) fp;
224 }
225
226 for (n = 1; n < nframes; n++) {
227 *cc++ = pc;
228
229 if (PMC_IN_TRAP_HANDLER(pc))
230 break;
231
232 r = fp + sizeof(uintptr_t);
233 if (!PMC_IN_KERNEL_STACK(fp, stackstart, stackend) ||
234 !PMC_IN_KERNEL(r))
235 break;
236 pc = *(uintptr_t *) r;
237 fp = *(uintptr_t *) fp;
238 }
239
240 return (n);
241}
242
33
34#include <sys/param.h>
35#include <sys/bus.h>
36#include <sys/pmc.h>
37#include <sys/proc.h>
38#include <sys/systm.h>
39
40#include <machine/cpu.h>
41#include <machine/apicreg.h>
42#include <machine/pmc_mdep.h>
43#include <machine/md_var.h>
44
45#include <vm/vm.h>
46#include <vm/vm_param.h>
47#include <vm/pmap.h>
48
49extern volatile lapic_t *lapic;
50
51void
52pmc_x86_lapic_enable_pmc_interrupt(void)
53{
54 uint32_t value;
55
56 value = lapic->lvt_pcint;
57 value &= ~APIC_LVT_M;
58 lapic->lvt_pcint = value;
59}
60
61/*
62 * Attempt to walk a user call stack using a too-simple algorithm.
63 * In the general case we need unwind information associated with
64 * the executable to be able to walk the user stack.
65 *
66 * We are handed a trap frame laid down at the time the PMC interrupt
67 * was taken. If the application is using frame pointers, the saved
68 * PC value could be:
69 * a. at the beginning of a function before the stack frame is laid
70 * down,
71 * b. just before a 'ret', after the stack frame has been taken off,
72 * c. somewhere else in the function with a valid stack frame being
73 * present,
74 *
75 * If the application is not using frame pointers, this algorithm will
76 * fail to yield an interesting call chain.
77 *
78 * TODO: figure out a way to use unwind information.
79 */
80
81int
82pmc_save_user_callchain(uintptr_t *cc, int nframes, struct trapframe *tf)
83{
84 int n;
85 uint32_t instr;
86 uintptr_t fp, oldfp, pc, r, sp;
87
88 KASSERT(TRAPF_USERMODE(tf), ("[x86,%d] Not a user trap frame tf=%p",
89 __LINE__, (void *) tf));
90
91 pc = PMC_TRAPFRAME_TO_PC(tf);
92 oldfp = fp = PMC_TRAPFRAME_TO_FP(tf);
93 sp = PMC_TRAPFRAME_TO_USER_SP(tf);
94
95 *cc++ = pc; n = 1;
96
97 r = fp + sizeof(uintptr_t); /* points to return address */
98
99 if (!PMC_IN_USERSPACE(pc))
100 return (n);
101
102 if (copyin((void *) pc, &instr, sizeof(instr)) != 0)
103 return (n);
104
105 if (PMC_AT_FUNCTION_PROLOGUE_PUSH_BP(instr) ||
106 PMC_AT_FUNCTION_EPILOGUE_RET(instr)) { /* ret */
107 if (copyin((void *) sp, &pc, sizeof(pc)) != 0)
108 return (n);
109 } else if (PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP(instr)) {
110 sp += sizeof(uintptr_t);
111 if (copyin((void *) sp, &pc, sizeof(pc)) != 0)
112 return (n);
113 } else if (copyin((void *) r, &pc, sizeof(pc)) != 0 ||
114 copyin((void *) fp, &fp, sizeof(fp) != 0))
115 return (n);
116
117 for (; n < nframes;) {
118 if (pc == 0 || !PMC_IN_USERSPACE(pc))
119 break;
120
121 *cc++ = pc; n++;
122
123 if (fp < oldfp)
124 break;
125
126 r = fp + sizeof(uintptr_t); /* address of return address */
127 oldfp = fp;
128
129 if (copyin((void *) r, &pc, sizeof(pc)) != 0 ||
130 copyin((void *) fp, &fp, sizeof(fp)) != 0)
131 break;
132 }
133
134 return (n);
135}
136
137/*
138 * Walking the kernel call stack.
139 *
140 * We are handed the trap frame laid down at the time the PMC
141 * interrupt was taken. The saved PC could be:
142 * a. in the lowlevel trap handler, meaning that there isn't a C stack
143 * to traverse,
144 * b. at the beginning of a function before the stack frame is laid
145 * down,
146 * c. just before a 'ret', after the stack frame has been taken off,
147 * d. somewhere else in a function with a valid stack frame being
148 * present.
149 *
150 * In case (d), the previous frame pointer is at [%ebp]/[%rbp] and
151 * the return address is at [%ebp+4]/[%rbp+8].
152 *
153 * For cases (b) and (c), the return address is at [%esp]/[%rsp] and
154 * the frame pointer doesn't need to be changed when going up one
155 * level in the stack.
156 *
157 * For case (a), we check if the PC lies in low-level trap handling
158 * code, and if so we terminate our trace.
159 */
160
161int
162pmc_save_kernel_callchain(uintptr_t *cc, int nframes, struct trapframe *tf)
163{
164 int n;
165 uint32_t instr;
166 uintptr_t fp, pc, r, sp, stackstart, stackend;
167 struct thread *td;
168
169 KASSERT(TRAPF_USERMODE(tf) == 0,("[x86,%d] not a kernel backtrace",
170 __LINE__));
171
172 pc = PMC_TRAPFRAME_TO_PC(tf);
173 fp = PMC_TRAPFRAME_TO_FP(tf);
174 sp = PMC_TRAPFRAME_TO_KERNEL_SP(tf);
175
176 *cc++ = pc;
177 r = fp + sizeof(uintptr_t); /* points to return address */
178
179 if ((td = curthread) == NULL)
180 return (1);
181
182 if (nframes <= 1)
183 return (1);
184
185 stackstart = (uintptr_t) td->td_kstack;
186 stackend = (uintptr_t) td->td_kstack + td->td_kstack_pages * PAGE_SIZE;
187
188 if (PMC_IN_TRAP_HANDLER(pc) ||
189 !PMC_IN_KERNEL(pc) || !PMC_IN_KERNEL(r) ||
190 !PMC_IN_KERNEL_STACK(sp, stackstart, stackend) ||
191 !PMC_IN_KERNEL_STACK(fp, stackstart, stackend))
192 return (1);
193
194 instr = *(uint32_t *) pc;
195
196 /*
197 * Determine whether the interrupted function was in the
198 * processing of either laying down its stack frame or taking
199 * it off.
200 *
201 * If we haven't started laying down a stack frame, or are
202 * just about to return, then our caller's address is at
203 * *sp, and we don't have a frame to unwind.
204 */
205 if (PMC_AT_FUNCTION_PROLOGUE_PUSH_BP(instr) ||
206 PMC_AT_FUNCTION_EPILOGUE_RET(instr))
207 pc = *(uintptr_t *) sp;
208 else if (PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP(instr)) {
209 /*
210 * The code was midway through laying down a frame.
211 * At this point sp[0] has a frame back pointer,
212 * and the caller's address is therefore at sp[1].
213 */
214 sp += sizeof(uintptr_t);
215 if (!PMC_IN_KERNEL_STACK(sp, stackstart, stackend))
216 return (1);
217 pc = *(uintptr_t *) sp;
218 } else {
219 /*
220 * Not in the function prologue or epilogue.
221 */
222 pc = *(uintptr_t *) r;
223 fp = *(uintptr_t *) fp;
224 }
225
226 for (n = 1; n < nframes; n++) {
227 *cc++ = pc;
228
229 if (PMC_IN_TRAP_HANDLER(pc))
230 break;
231
232 r = fp + sizeof(uintptr_t);
233 if (!PMC_IN_KERNEL_STACK(fp, stackstart, stackend) ||
234 !PMC_IN_KERNEL(r))
235 break;
236 pc = *(uintptr_t *) r;
237 fp = *(uintptr_t *) fp;
238 }
239
240 return (n);
241}
242
243static struct pmc_mdep *
244pmc_intel_initialize(void)
245{
246 struct pmc_mdep *pmc_mdep;
247 enum pmc_cputype cputype;
248 int error, model;
249
250 KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0,
251 ("[intel,%d] Initializing non-intel processor", __LINE__));
252
253 PMCDBG(MDP,INI,0, "intel-initialize cpuid=0x%x", cpu_id);
254
255 cputype = -1;
256
257 switch (cpu_id & 0xF00) {
258#if defined(__i386__)
259 case 0x500: /* Pentium family processors */
260 cputype = PMC_CPU_INTEL_P5;
261 break;
262 case 0x600: /* Pentium Pro, Celeron, Pentium II & III */
263 switch ((cpu_id & 0xF0) >> 4) { /* model number field */
264 case 0x1:
265 cputype = PMC_CPU_INTEL_P6;
266 break;
267 case 0x3: case 0x5:
268 cputype = PMC_CPU_INTEL_PII;
269 break;
270 case 0x6:
271 cputype = PMC_CPU_INTEL_CL;
272 break;
273 case 0x7: case 0x8: case 0xA: case 0xB:
274 cputype = PMC_CPU_INTEL_PIII;
275 break;
276 case 0x9: case 0xD:
277 cputype = PMC_CPU_INTEL_PM;
278 break;
279 }
280 break;
281#endif
282#if defined(__i386__) || defined(__amd64__)
283 case 0xF00: /* P4 */
284 model = ((cpu_id & 0xF0000) >> 12) | ((cpu_id & 0xF0) >> 4);
285 if (model >= 0 && model <= 6) /* known models */
286 cputype = PMC_CPU_INTEL_PIV;
287 break;
288 }
289#endif
290
291 if ((int) cputype == -1) {
292 printf("pmc: Unknown Intel CPU.\n");
293 return NULL;
294 }
295
296 pmc_mdep = malloc(sizeof(struct pmc_mdep),
297 M_PMC, M_WAITOK|M_ZERO);
298
299 pmc_mdep->pmd_cputype = cputype;
300 pmc_mdep->pmd_nclass = 2;
301 pmc_mdep->pmd_classes[0].pm_class = PMC_CLASS_TSC;
302 pmc_mdep->pmd_classes[0].pm_caps = PMC_CAP_READ;
303 pmc_mdep->pmd_classes[0].pm_width = 64;
304 pmc_mdep->pmd_nclasspmcs[0] = 1;
305
306 error = 0;
307
308 switch (cputype) {
309
310#if defined(__i386__) || defined(__amd64__)
311
312 /*
313 * Intel Pentium 4 Processors, and P4/EMT64 processors.
314 */
315
316 case PMC_CPU_INTEL_PIV:
317 error = pmc_initialize_p4(pmc_mdep);
318 break;
319#endif
320
321#if defined(__i386__)
322 /*
323 * P6 Family Processors
324 */
325
326 case PMC_CPU_INTEL_P6:
327 case PMC_CPU_INTEL_CL:
328 case PMC_CPU_INTEL_PII:
329 case PMC_CPU_INTEL_PIII:
330 case PMC_CPU_INTEL_PM:
331
332 error = pmc_initialize_p6(pmc_mdep);
333 break;
334
335 /*
336 * Intel Pentium PMCs.
337 */
338
339 case PMC_CPU_INTEL_P5:
340 error = pmc_initialize_p5(pmc_mdep);
341 break;
342#endif
343
344 default:
345 KASSERT(0,("[intel,%d] Unknown CPU type", __LINE__));
346 }
347
348 if (error) {
349 free(pmc_mdep, M_PMC);
350 pmc_mdep = NULL;
351 }
352
353 return pmc_mdep;
354}
355
356
357/*
358 * Machine dependent initialization for x86 class platforms.
359 */
360
361struct pmc_mdep *
362pmc_md_initialize()
363{
364 int i;
365 struct pmc_mdep *md;
366
367 /* determine the CPU kind */
368 md = NULL;
369 if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
370 md = pmc_amd_initialize();
371 else if (strcmp(cpu_vendor, "GenuineIntel") == 0)
372 md = pmc_intel_initialize();
243/*
244 * Machine dependent initialization for x86 class platforms.
245 */
246
247struct pmc_mdep *
248pmc_md_initialize()
249{
250 int i;
251 struct pmc_mdep *md;
252
253 /* determine the CPU kind */
254 md = NULL;
255 if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
256 md = pmc_amd_initialize();
257 else if (strcmp(cpu_vendor, "GenuineIntel") == 0)
258 md = pmc_intel_initialize();
259 else
260 KASSERT(0, ("[x86,%d] Unknown vendor", __LINE__));
373
374 /* disallow sampling if we do not have an LAPIC */
375 if (md != NULL && lapic == NULL)
376 for (i = 1; i < md->pmd_nclass; i++)
261
262 /* disallow sampling if we do not have an LAPIC */
263 if (md != NULL && lapic == NULL)
264 for (i = 1; i < md->pmd_nclass; i++)
377 md->pmd_classes[i].pm_caps &= ~PMC_CAP_INTERRUPT;
265 md->pmd_classdep[i].pcd_caps &= ~PMC_CAP_INTERRUPT;
378
266
379 return md;
267 return (md);
380}
268}
269
270void
271pmc_md_finalize(struct pmc_mdep *md)
272{
273 if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
274 pmc_amd_finalize(md);
275 else if (strcmp(cpu_vendor, "GenuineIntel") == 0)
276 pmc_intel_finalize(md);
277 else
278 KASSERT(0, ("[x86,%d] Unknown vendor", __LINE__));
279}