001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.mmtk.utility.statistics;
014
015 import org.mmtk.utility.Log;
016 import org.mmtk.vm.VM;
017 import org.vmmagic.pragma.Uninterruptible;
018
019 /**
020 * This class represents a perf event, such as cache misses, etc.
021 */
022 @Uninterruptible
023 public final class PerfEvent extends LongCounter {
024 /** {@code true} if the counter did not run due to contention for a physical counter */
025 private boolean contended;
026
027 /** {@code true} if the counter did not run all of the time and has been scaled appropriately */
028 private boolean scaled;
029
030 /** {@code true} if the counter overflowed */
031 private boolean overflowed;
032
033 /** The index of the counter in the native array */
034 private int index;
035
036 /** The previously read value of the counter (used to detect overflow) */
037 private long previousValue;
038
039 /** A buffer passed to the native code when reading values, returns the tuple RAW_COUNT, TIME_ENABLED, TIME_RUNNING */
040 private final long[] readBuffer = new long[3];
041 private static final int RAW_COUNT = 0;
042 private static final int TIME_ENABLED = 1;
043 private static final int TIME_RUNNING = 2;
044
045 /** {@code true} if any data was scaled */
046 public static boolean dataWasScaled = false;
047
048 public PerfEvent(int index, String name) {
049 super(name, true, false);
050 this.index = index;
051 }
052
053 /**
054 * Counters are 64 bit unsigned in the kernel but only 63 bits are available in Java
055 */
056 @Override
057 protected long getCurrentValue() {
058 VM.statistics.perfEventRead(index, readBuffer);
059 if (readBuffer[RAW_COUNT] < 0 || readBuffer[TIME_ENABLED] < 0 || readBuffer[TIME_RUNNING] < 0) {
060 // Negative implies they have exceeded 63 bits.
061 overflowed = true;
062 }
063 if (readBuffer[TIME_ENABLED] == 0) {
064 // Counter never run (assume contention)
065 contended = true;
066 }
067 // Was the counter scaled?
068 if (readBuffer[TIME_ENABLED] != readBuffer[TIME_RUNNING]) {
069 scaled = true;
070 dataWasScaled = true;
071 double scaleFactor;
072 if (readBuffer[TIME_RUNNING] == 0) {
073 scaleFactor = 0;
074 } else {
075 scaleFactor = readBuffer[TIME_ENABLED] / readBuffer[TIME_RUNNING];
076 }
077 readBuffer[RAW_COUNT] = (long) (readBuffer[RAW_COUNT] * scaleFactor);
078 }
079 if (readBuffer[RAW_COUNT] < previousValue) {
080 // value should monotonically increase
081 overflowed = true;
082 }
083 previousValue = readBuffer[RAW_COUNT];
084 return readBuffer[RAW_COUNT];
085 }
086
087 @Override
088 void printValue(long value) {
089 if (overflowed) {
090 Log.write("OVERFLOWED");
091 } else if (contended) {
092 Log.write("CONTENDED");
093 } else {
094 Log.write(value);
095 if (scaled) {
096 Log.write(" (SCALED)");
097 }
098 }
099 }
100
101 @Override
102 public String getColumnSuffix() {
103 return
104 overflowed ? "overflowed" :
105 contended ? "contended" :
106 scaled ? ".scaled" :
107 "";
108 }
109 }
110