/*
* $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.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;
import org.vmmagic.pragma.UninterruptiblePragma;
/**
* Implementation of PerformanceCounters for models that implement performance
* monitoring counter using 2 MSR's per counter: a select MSR and a counter MSR.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
class DualMSRPerformanceCounters extends X86PerformanceCounters {
/**
* Event implementation.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public static class DualMSREvent extends PerformanceCounterEvent {
/**
* Value for the select MSR used to select this event
*/
private final long selectValue;
/**
* @param id
*/
public DualMSREvent(PresetEvent preset, long selectValue) {
super(preset);
this.selectValue = selectValue;
}
/**
* @param id
* @param selectValue
*/
public DualMSREvent(PresetEvent preset, int eventMask, int unitMask) {
this(preset, createSelectValue(eventMask, unitMask));
}
private static long createSelectValue(int eventMask, int unitMask) {
long v = 0;
v |= eventMask & 0xFF;
v |= (unitMask & 0xFF) << 8;
v |= 1 << 16; // USR
v |= 1 << 22; // EN
return v;
}
/**
* @return Returns the selectValue.
*/
public final long getSelectValue() {
return selectValue;
}
}
private final int[] countMSRIndexes;
private final DualMSREvent[] events;
private final Set<PerformanceCounterEvent> eventSet;
private final int[] selectMSRIndexes;
/**
* @param id
*/
public DualMSRPerformanceCounters(VmX86Processor cpu,
int[] selectMSRIndexes, int[] countMSRIndexes, DualMSREvent[] events) {
super(cpu, selectMSRIndexes.length);
if (selectMSRIndexes.length != countMSRIndexes.length) {
throw new IllegalArgumentException(
"selectMSRs and countMSRs have diffent length");
}
this.selectMSRIndexes = selectMSRIndexes;
this.countMSRIndexes = countMSRIndexes;
this.events = events;
this.eventSet = Collections
.unmodifiableSet(new TreeSet<PerformanceCounterEvent>(Arrays
.asList(events)));
}
/**
* @see org.jnode.vm.x86.performance.X86PerformanceCounters#getAvailableEvents()
*/
public final Set<PerformanceCounterEvent> getAvailableEvents() {
return eventSet;
}
/**
* @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#getCounterValues(long[])
*/
protected final void getCounterValues(long[] counters, VmX86Thread thread)
throws UninterruptiblePragma {
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[])
*/
protected final void startCounters(PerformanceCounterEvent[] events,
VmX86Thread thread) throws IllegalArgumentException {
final int cnt = events.length;
final MSR[] countMSRs = new MSR[cnt];
final MSR[] selectMSRs = new MSR[cnt];
for (int i = 0; i < cnt; i++) {
final DualMSREvent e = (DualMSREvent) events[i];
countMSRs[i] = new MSR(this.countMSRIndexes[i]);
selectMSRs[i] = new MSR(this.selectMSRIndexes[i], e.getSelectValue());
}
// Install MSR's
thread.setMSRs(countMSRs, selectMSRs);
}
/**
* @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);
}
}
}
}