/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.vm.x86.performance; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.jnode.vm.performance.PerformanceCounterEvent; import org.jnode.vm.performance.PresetEvent; import org.jnode.vm.x86.MSR; import org.jnode.vm.x86.VmX86Processor; import org.jnode.vm.x86.VmX86Thread; abstract class P4FamilyPerformanceCounters extends X86PerformanceCounters { private final CounterMSRInfo[] counters; private final P4Event[] events; private final Set<PerformanceCounterEvent> eventSet; // ------------------------------------------ // ESCR MSR indexes // ------------------------------------------ public static final int BPU_ESCR0 = 0x3B2; public static final int BPU_ESCR1 = 0x3B3; public static final int BSU_ESCR0 = 0x3A0; public static final int BSU_ESCR1 = 0x3A1; public static final int CR_ESCR0 = 0; public static final int CR_ESCR1 = 0; public static final int CRU_ESCR0 = 0x3B8; public static final int CRU_ESCR1 = 0x3B9; public static final int CRU_ESCR2 = 0x3CC; public static final int CRU_ESCR3 = 0x3CD; public static final int CRU_ESCR4 = 0x3E0; public static final int CRU_ESCR5 = 0x3E1; public static final int FSB_ESCR0 = 0x3A2; public static final int FSB_ESCR1 = 0x3A3; public static final int IS_ESCR0 = 0x3B4; public static final int IS_ESCR1 = 0x3B5; public static final int ITLB_ESCR0 = 0x3B6; public static final int ITLB_ESCR1 = 0x3B7; public static final int IX_ESCR0 = 0x3C8; public static final int IX_ESCR1 = 0x3C9; public static final int MOP_ESCR0 = 0x3AA; public static final int MOP_ESCR1 = 0x3AB; public static final int MS_ESCR0 = 0x3C0; public static final int MS_ESCR1 = 0x3C1; public static final int PMH_ESCR1 = 0x3AD; public static final int PMH_ESCR0 = 0x3AC; public static final int TBPU_ESCR0 = 0x3C2; public static final int TBPU_ESCR1 = 0x3C3; public static final int TC_ESCR0 = 0x3C4; public static final int TC_ESCR1 = 0x3C5; /** * @param cpu * @param maxCounters */ public P4FamilyPerformanceCounters(VmX86Processor cpu, CounterMSRInfo[] counters, P4Event[] events) { super(cpu, counters.length); this.counters = counters; this.events = events; this.eventSet = Collections .unmodifiableSet(new TreeSet<PerformanceCounterEvent>(Arrays .asList(events))); } /** * Class holding MSR information for a single performance counter. * * @author Ewout Prangsma (epr@users.sourceforge.net) */ public static class CounterMSRInfo { final char counterMSRIndex; final char cccrMSRIndex; /** * @param counterMSRIndex * @param cccrMSRIndex * @param escrNrs * @param escrMSRIndexes */ public CounterMSRInfo(int counterMSRIndex, int cccrMSRIndex) { this.counterMSRIndex = (char) counterMSRIndex; this.cccrMSRIndex = (char) cccrMSRIndex; } } /** * ESCR restriction. * * @author Ewout Prangsma (epr@users.sourceforge.net) */ public static final class ESCR_RES { /** * The ESCR MSR index */ final char escr; /** * The Counters number (0..17) to which this event is restricted */ final byte[] counters; /** * @param escr * @param counters */ public ESCR_RES(int escr, byte[] counters) { this.escr = (char) escr; this.counters = counters; } /** * @param escr * @param cnt0 */ public ESCR_RES(int escr, int cnt0) { this(escr, new byte[]{(byte) cnt0}); } /** * @param escr * @param cnt0 * @param cnt1 */ public ESCR_RES(int escr, int cnt0, int cnt1) { this(escr, new byte[]{(byte) cnt0, (byte) cnt1}); } /** * @param escr * @param cnt0 * @param cnt1 * @param cnt2 */ public ESCR_RES(int escr, int cnt0, int cnt1, int cnt2) { this(escr, new byte[]{(byte) cnt0, (byte) cnt1, (byte) cnt2}); } } /** * Event class for P4 familiy events. * * @author Ewout Prangsma (epr@users.sourceforge.net) */ public static final class P4Event extends PerformanceCounterEvent { /** * ESCR bits 30-25 */ private final byte escrEventSelect; /** * ESCR bits 24-9 */ private final char escrEventMask; /** * ESCR restrictions */ private final ESCR_RES[] escrRestr; /** * CCCR select value */ private final byte cccrSelect; /** * @param preset */ public P4Event(PresetEvent preset, int escrEventSelect, int escrEventMask, int cccrSelect, ESCR_RES res0) { this(preset, escrEventSelect, escrEventMask, cccrSelect, new ESCR_RES[]{res0}); } /** * @param preset */ public P4Event(PresetEvent preset, int escrEventSelect, int escrEventMask, int cccrSelect, ESCR_RES res0, ESCR_RES res1) { this(preset, escrEventSelect, escrEventMask, cccrSelect, new ESCR_RES[]{res0, res1}); } /** * @param preset */ public P4Event(PresetEvent preset, int escrEventSelect, int escrEventMask, int cccrSelect, ESCR_RES[] ress) { super(preset); this.escrEventSelect = (byte) escrEventSelect; this.escrEventMask = (char) escrEventMask; this.cccrSelect = (byte) cccrSelect; this.escrRestr = ress; } /** * @param id * @param description */ public P4Event(String id, String description, int escrEventSelect, int escrEventMask, int cccrSelect, ESCR_RES[] ress) { super(id, description); this.escrEventSelect = (byte) escrEventSelect; this.escrEventMask = (char) escrEventMask; this.cccrSelect = (byte) cccrSelect; this.escrRestr = ress; } /** * Creates the value for the ESCR MSR. * * @return */ final long createESCRValue() { // USR | eventMask | eventSelect return (1 << 2) | (escrEventMask << 9) | (escrEventSelect << 25); } /** * Creates the value for the CCCR MSR. * * @return */ final long createCCCRValue() { // EN | ESCR select | Rsvd return (1 << 12) | (cccrSelect << 13) | (3 << 16); } } /** * @see org.jnode.vm.x86.performance.X86PerformanceCounters#getAvailableEvent(java.lang.String) */ public final PerformanceCounterEvent getAvailableEvent(String id) { for (PerformanceCounterEvent e : events) { if (e.getId().equals(id)) { return e; } } return null; } /** * @see org.jnode.vm.x86.performance.X86PerformanceCounters#getAvailableEvents() */ public final Set<PerformanceCounterEvent> getAvailableEvents() { return eventSet; } /** * @see org.jnode.vm.x86.performance.X86PerformanceCounters#getCounterValues(long[], * org.jnode.vm.x86.VmX86Thread) */ protected void getCounterValues(long[] counters, VmX86Thread thread) { final MSR[] countMSRs = thread.getReadWriteMSRs(); if (countMSRs == null) { throw new IllegalArgumentException("No active counters"); } final int cnt = counters.length; if (cnt > countMSRs.length) { throw new IllegalArgumentException("counters array is too long"); } // Get the counters for (int i = 0; i < cnt; i++) { counters[i] = countMSRs[i].getValue(); } } /** * @see org.jnode.vm.x86.performance.X86PerformanceCounters# * startCounters(org.jnode.vm.performance.PerformanceCounterEvent[], * org.jnode.vm.x86.VmX86Thread) */ protected void startCounters(PerformanceCounterEvent[] events, VmX86Thread thread) throws IllegalArgumentException { final Map<Integer, P4Event> escrState = new HashMap<Integer, P4Event>(); final P4Event[] counterState = new P4Event[counters.length]; final int eventCnt = events.length; final MSR[] selectMSRs = new MSR[eventCnt * 2]; final MSR[] counterMSRs = new MSR[eventCnt]; int i = 0; for (PerformanceCounterEvent e : events) { final P4Event evt = (P4Event) e; // Find a free ESCR final ESCR_RES escr = findFreeESCR(escrState, counterState, evt); final CounterMSRInfo cntInfo = counters[indexOf(counterState, evt)]; // Create the MSRs selectMSRs[i * 2 + 0] = new MSR(escr.escr, evt.createESCRValue()); selectMSRs[i * 2 + 1] = new MSR(cntInfo.cccrMSRIndex, evt.createCCCRValue()); counterMSRs[i] = new MSR(cntInfo.counterMSRIndex); i++; } thread.setMSRs(counterMSRs, selectMSRs); } /** * Gets the index of the given object in the given array. * * @param <T> * @param arr * @param obj * @return */ private final <T> int indexOf(T[] arr, T obj) { final int max = arr.length; for (int i = 0; i < max; i++) { if (arr[i] == obj) { return i; } } return -1; } /** * Find a free ESCR that can be used for the given event. * * @param escrState * @param evt * @return */ private final ESCR_RES findFreeESCR(Map<Integer, P4Event> escrState, P4Event[] counters, P4Event evt) throws IllegalArgumentException { for (ESCR_RES res : evt.escrRestr) { final int escrIndex = res.escr; if (!escrState.containsKey(escrIndex)) { final int cnt; if ((cnt = findFreeCounter(counters, res)) >= 0) { escrState.put(escrIndex, evt); counters[cnt] = evt; return res; } } } throw new IllegalArgumentException("No free ESCR for event " + evt); } /** * Find a free counter for the given ESCR. * * @param counters * @param escr * @return -1 If not found */ private final int findFreeCounter(P4Event[] counters, ESCR_RES escr) { for (byte cnt : escr.counters) { if (counters[cnt] == null) { return cnt; } } return -1; } /** * @see org.jnode.vm.x86.performance.X86PerformanceCounters#stopCounters(org.jnode.vm.x86.VmX86Thread) */ protected void stopCounters(VmX86Thread thread) throws IllegalArgumentException { final MSR[] selectMSRs = thread.getWriteOnlyMSRs(); if (selectMSRs != null) { final int cnt = selectMSRs.length; // Reset the counter selectors for (int i = 0; i < cnt; i++) { selectMSRs[i].setValue(0); } } } }