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 */ 013package org.mmtk.utility.statistics; 014 015import org.mmtk.utility.Log; 016import org.mmtk.vm.VM; 017import org.vmmagic.pragma.Uninterruptible; 018 019/** 020 * This class represents a perf event, such as cache misses, etc. 021 */ 022@Uninterruptible 023public 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 final 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