Loading core/java/com/android/internal/os/KernelCpuThreadReader.java +152 −12 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.os.Process; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.io.IOException; import java.nio.file.DirectoryStream; Loading @@ -33,6 +34,16 @@ import java.util.ArrayList; * Given a process, will iterate over the child threads of the process, and return the CPU usage * statistics for each child thread. The CPU usage statistics contain the amount of time spent in a * frequency band. * * <p>Frequencies are bucketed together to reduce the amount of data created. This means that we * return {@link #NUM_BUCKETS} frequencies instead of the full number. Frequencies are reported as * the lowest frequency in that range. Frequencies are spread as evenly as possible across the * buckets. The buckets do not cross over the little/big frequencies reported. * * <p>N.B.: In order to bucket across little/big frequencies correctly, we assume that the {@code * time_in_state} file contains every little core frequency in ascending order, followed by every * big core frequency in ascending order. This assumption might not hold for devices with different * kernel implementations of the {@code time_in_state} file generation. */ public class KernelCpuThreadReader { Loading Loading @@ -79,6 +90,11 @@ public class KernelCpuThreadReader { private static final Path DEFAULT_INITIAL_TIME_IN_STATE_PATH = DEFAULT_PROC_PATH.resolve("self/time_in_state"); /** * Number of frequency buckets */ private static final int NUM_BUCKETS = 8; /** * Where the proc filesystem is mounted */ Loading @@ -95,6 +111,11 @@ public class KernelCpuThreadReader { */ private final ProcTimeInStateReader mProcTimeInStateReader; /** * Used to sort frequencies and usage times into buckets */ private final FrequencyBucketCreator mFrequencyBucketCreator; private KernelCpuThreadReader() throws IOException { this(DEFAULT_PROC_PATH, DEFAULT_INITIAL_TIME_IN_STATE_PATH); } Loading @@ -111,12 +132,10 @@ public class KernelCpuThreadReader { mProcPath = procPath; mProcTimeInStateReader = new ProcTimeInStateReader(initialTimeInStatePath); // Copy mProcTimeInState's frequencies, casting the longs to ints long[] frequenciesKhz = mProcTimeInStateReader.getFrequenciesKhz(); mFrequenciesKhz = new int[frequenciesKhz.length]; for (int i = 0; i < frequenciesKhz.length; i++) { mFrequenciesKhz[i] = (int) frequenciesKhz[i]; } // Copy mProcTimeInState's frequencies and initialize bucketing final long[] frequenciesKhz = mProcTimeInStateReader.getFrequenciesKhz(); mFrequencyBucketCreator = new FrequencyBucketCreator(frequenciesKhz, NUM_BUCKETS); mFrequenciesKhz = mFrequencyBucketCreator.getBucketMinFrequencies(frequenciesKhz); } /** Loading Loading @@ -228,12 +247,7 @@ public class KernelCpuThreadReader { if (cpuUsagesLong == null) { return null; } // Convert long[] to int[] final int[] cpuUsages = new int[cpuUsagesLong.length]; for (int i = 0; i < cpuUsagesLong.length; i++) { cpuUsages[i] = (int) cpuUsagesLong[i]; } int[] cpuUsages = mFrequencyBucketCreator.getBucketedValues(cpuUsagesLong); return new ThreadCpuUsage(threadId, threadName, cpuUsages); } Loading Loading @@ -265,6 +279,132 @@ public class KernelCpuThreadReader { return threadName; } /** * Puts frequencies and usage times into buckets */ @VisibleForTesting public static class FrequencyBucketCreator { private final int mNumBuckets; private final int mNumFrequencies; private final int mBigFrequenciesStartIndex; private final int mLittleNumBuckets; private final int mBigNumBuckets; private final int mLittleBucketSize; private final int mBigBucketSize; /** * Buckets based of a list of frequencies * * @param frequencies the frequencies to base buckets off * @param numBuckets how many buckets to create */ @VisibleForTesting public FrequencyBucketCreator(long[] frequencies, int numBuckets) { Preconditions.checkArgument(numBuckets > 0); mNumFrequencies = frequencies.length; mBigFrequenciesStartIndex = getBigFrequenciesStartIndex(frequencies); final int littleNumBuckets; final int bigNumBuckets; if (mBigFrequenciesStartIndex < frequencies.length) { littleNumBuckets = numBuckets / 2; bigNumBuckets = numBuckets - littleNumBuckets; } else { // If we've got no big frequencies, set all buckets to little frequencies littleNumBuckets = numBuckets; bigNumBuckets = 0; } // Ensure that we don't have more buckets than frequencies mLittleNumBuckets = Math.min(littleNumBuckets, mBigFrequenciesStartIndex); mBigNumBuckets = Math.min( bigNumBuckets, frequencies.length - mBigFrequenciesStartIndex); mNumBuckets = mLittleNumBuckets + mBigNumBuckets; // Set the size of each little and big bucket. If they have no buckets, the size is zero mLittleBucketSize = mLittleNumBuckets == 0 ? 0 : mBigFrequenciesStartIndex / mLittleNumBuckets; mBigBucketSize = mBigNumBuckets == 0 ? 0 : (frequencies.length - mBigFrequenciesStartIndex) / mBigNumBuckets; } /** * Find the index where frequencies change from little core to big core */ @VisibleForTesting public static int getBigFrequenciesStartIndex(long[] frequenciesKhz) { for (int i = 0; i < frequenciesKhz.length - 1; i++) { if (frequenciesKhz[i] > frequenciesKhz[i + 1]) { return i + 1; } } return frequenciesKhz.length; } /** * Get the minimum frequency in each bucket */ @VisibleForTesting public int[] getBucketMinFrequencies(long[] frequenciesKhz) { Preconditions.checkArgument(frequenciesKhz.length == mNumFrequencies); // If there's only one bucket, we bucket everything together so the first bucket is the // min frequency if (mNumBuckets == 1) { return new int[]{(int) frequenciesKhz[0]}; } final int[] bucketMinFrequencies = new int[mNumBuckets]; // Initialize little buckets min frequencies for (int i = 0; i < mLittleNumBuckets; i++) { bucketMinFrequencies[i] = (int) frequenciesKhz[i * mLittleBucketSize]; } // Initialize big buckets min frequencies for (int i = 0; i < mBigNumBuckets; i++) { final int frequencyIndex = mBigFrequenciesStartIndex + i * mBigBucketSize; bucketMinFrequencies[mLittleNumBuckets + i] = (int) frequenciesKhz[frequencyIndex]; } return bucketMinFrequencies; } /** * Put an array of values into buckets. This takes a {@code long[]} and returns {@code * int[]} as everywhere this method is used will have to do the conversion anyway, so we * save time by doing it here instead * * @param values the values to bucket * @return the bucketed usage times */ @VisibleForTesting public int[] getBucketedValues(long[] values) { Preconditions.checkArgument(values.length == mNumFrequencies); final int[] bucketed = new int[mNumBuckets]; // If there's only one bucket, add all frequencies in if (mNumBuckets == 1) { for (int i = 0; i < values.length; i++) { bucketed[0] += values[i]; } return bucketed; } // Initialize the little buckets for (int i = 0; i < mBigFrequenciesStartIndex; i++) { final int bucketIndex = Math.min(i / mLittleBucketSize, mLittleNumBuckets - 1); bucketed[bucketIndex] += values[i]; } // Initialize the big buckets for (int i = mBigFrequenciesStartIndex; i < values.length; i++) { final int bucketIndex = Math.min( mLittleNumBuckets + (i - mBigFrequenciesStartIndex) / mBigBucketSize, mNumBuckets - 1); bucketed[bucketIndex] += values[i]; } return bucketed; } } /** * CPU usage of a process */ Loading core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java +130 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.os; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; Loading Loading @@ -139,4 +140,133 @@ public class KernelCpuThreadReaderTest { assertEquals(threadCount, THREAD_IDS.length); } @Test public void testBucketSetup_simple() { long[] frequencies = {1, 2, 3, 4, 1, 2, 3, 4}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 4); assertArrayEquals( new int[]{1, 3, 1, 3}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{2, 2, 2, 2}, frequencyBucketCreator.getBucketedValues(new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_noBig() { long[] frequencies = {1, 2, 3, 4, 5, 6, 7, 8}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 4); assertArrayEquals( new int[]{1, 3, 5, 7}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{2, 2, 2, 2}, frequencyBucketCreator.getBucketedValues(new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_moreLittle() { long[] frequencies = {1, 2, 3, 4, 5, 1, 2, 3}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 4); assertArrayEquals( new int[]{1, 3, 1, 2}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{2, 3, 1, 2}, frequencyBucketCreator.getBucketedValues(new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_moreBig() { long[] frequencies = {1, 2, 3, 1, 2, 3, 4, 5}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 4); assertArrayEquals( new int[]{1, 2, 1, 3}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{1, 2, 2, 3}, frequencyBucketCreator.getBucketedValues(new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_equalBuckets() { long[] frequencies = {1, 2, 3, 4, 1, 2, 3, 4}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 8); assertArrayEquals( new int[]{1, 2, 3, 4, 1, 2, 3, 4}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{1, 1, 1, 1, 1, 1, 1, 1}, frequencyBucketCreator.getBucketedValues(new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_moreBigBucketsThanFrequencies() { long[] frequencies = {1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 8); assertArrayEquals( new int[]{1, 3, 5, 7, 1, 2, 3}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{2, 2, 2, 3, 1, 1, 1}, frequencyBucketCreator.getBucketedValues( new long[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_oneBucket() { long[] frequencies = {1, 2, 3, 4, 2, 3, 4, 5}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 1); assertArrayEquals( new int[]{1}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{8}, frequencyBucketCreator.getBucketedValues( new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testGetBigFrequenciesStartIndex_simple() { assertEquals( 3, KernelCpuThreadReader.FrequencyBucketCreator.getBigFrequenciesStartIndex( new long[]{1, 2, 3, 1, 2, 3})); } @Test public void testGetBigFrequenciesStartIndex_moreLittle() { assertEquals( 4, KernelCpuThreadReader.FrequencyBucketCreator.getBigFrequenciesStartIndex( new long[]{1, 2, 3, 4, 1, 2})); } @Test public void testGetBigFrequenciesStartIndex_moreBig() { assertEquals( 2, KernelCpuThreadReader.FrequencyBucketCreator.getBigFrequenciesStartIndex( new long[]{1, 2, 1, 2, 3, 4})); } @Test public void testGetBigFrequenciesStartIndex_noBig() { assertEquals( 4, KernelCpuThreadReader.FrequencyBucketCreator.getBigFrequenciesStartIndex( new long[]{1, 2, 3, 4})); } } Loading
core/java/com/android/internal/os/KernelCpuThreadReader.java +152 −12 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.os.Process; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.io.IOException; import java.nio.file.DirectoryStream; Loading @@ -33,6 +34,16 @@ import java.util.ArrayList; * Given a process, will iterate over the child threads of the process, and return the CPU usage * statistics for each child thread. The CPU usage statistics contain the amount of time spent in a * frequency band. * * <p>Frequencies are bucketed together to reduce the amount of data created. This means that we * return {@link #NUM_BUCKETS} frequencies instead of the full number. Frequencies are reported as * the lowest frequency in that range. Frequencies are spread as evenly as possible across the * buckets. The buckets do not cross over the little/big frequencies reported. * * <p>N.B.: In order to bucket across little/big frequencies correctly, we assume that the {@code * time_in_state} file contains every little core frequency in ascending order, followed by every * big core frequency in ascending order. This assumption might not hold for devices with different * kernel implementations of the {@code time_in_state} file generation. */ public class KernelCpuThreadReader { Loading Loading @@ -79,6 +90,11 @@ public class KernelCpuThreadReader { private static final Path DEFAULT_INITIAL_TIME_IN_STATE_PATH = DEFAULT_PROC_PATH.resolve("self/time_in_state"); /** * Number of frequency buckets */ private static final int NUM_BUCKETS = 8; /** * Where the proc filesystem is mounted */ Loading @@ -95,6 +111,11 @@ public class KernelCpuThreadReader { */ private final ProcTimeInStateReader mProcTimeInStateReader; /** * Used to sort frequencies and usage times into buckets */ private final FrequencyBucketCreator mFrequencyBucketCreator; private KernelCpuThreadReader() throws IOException { this(DEFAULT_PROC_PATH, DEFAULT_INITIAL_TIME_IN_STATE_PATH); } Loading @@ -111,12 +132,10 @@ public class KernelCpuThreadReader { mProcPath = procPath; mProcTimeInStateReader = new ProcTimeInStateReader(initialTimeInStatePath); // Copy mProcTimeInState's frequencies, casting the longs to ints long[] frequenciesKhz = mProcTimeInStateReader.getFrequenciesKhz(); mFrequenciesKhz = new int[frequenciesKhz.length]; for (int i = 0; i < frequenciesKhz.length; i++) { mFrequenciesKhz[i] = (int) frequenciesKhz[i]; } // Copy mProcTimeInState's frequencies and initialize bucketing final long[] frequenciesKhz = mProcTimeInStateReader.getFrequenciesKhz(); mFrequencyBucketCreator = new FrequencyBucketCreator(frequenciesKhz, NUM_BUCKETS); mFrequenciesKhz = mFrequencyBucketCreator.getBucketMinFrequencies(frequenciesKhz); } /** Loading Loading @@ -228,12 +247,7 @@ public class KernelCpuThreadReader { if (cpuUsagesLong == null) { return null; } // Convert long[] to int[] final int[] cpuUsages = new int[cpuUsagesLong.length]; for (int i = 0; i < cpuUsagesLong.length; i++) { cpuUsages[i] = (int) cpuUsagesLong[i]; } int[] cpuUsages = mFrequencyBucketCreator.getBucketedValues(cpuUsagesLong); return new ThreadCpuUsage(threadId, threadName, cpuUsages); } Loading Loading @@ -265,6 +279,132 @@ public class KernelCpuThreadReader { return threadName; } /** * Puts frequencies and usage times into buckets */ @VisibleForTesting public static class FrequencyBucketCreator { private final int mNumBuckets; private final int mNumFrequencies; private final int mBigFrequenciesStartIndex; private final int mLittleNumBuckets; private final int mBigNumBuckets; private final int mLittleBucketSize; private final int mBigBucketSize; /** * Buckets based of a list of frequencies * * @param frequencies the frequencies to base buckets off * @param numBuckets how many buckets to create */ @VisibleForTesting public FrequencyBucketCreator(long[] frequencies, int numBuckets) { Preconditions.checkArgument(numBuckets > 0); mNumFrequencies = frequencies.length; mBigFrequenciesStartIndex = getBigFrequenciesStartIndex(frequencies); final int littleNumBuckets; final int bigNumBuckets; if (mBigFrequenciesStartIndex < frequencies.length) { littleNumBuckets = numBuckets / 2; bigNumBuckets = numBuckets - littleNumBuckets; } else { // If we've got no big frequencies, set all buckets to little frequencies littleNumBuckets = numBuckets; bigNumBuckets = 0; } // Ensure that we don't have more buckets than frequencies mLittleNumBuckets = Math.min(littleNumBuckets, mBigFrequenciesStartIndex); mBigNumBuckets = Math.min( bigNumBuckets, frequencies.length - mBigFrequenciesStartIndex); mNumBuckets = mLittleNumBuckets + mBigNumBuckets; // Set the size of each little and big bucket. If they have no buckets, the size is zero mLittleBucketSize = mLittleNumBuckets == 0 ? 0 : mBigFrequenciesStartIndex / mLittleNumBuckets; mBigBucketSize = mBigNumBuckets == 0 ? 0 : (frequencies.length - mBigFrequenciesStartIndex) / mBigNumBuckets; } /** * Find the index where frequencies change from little core to big core */ @VisibleForTesting public static int getBigFrequenciesStartIndex(long[] frequenciesKhz) { for (int i = 0; i < frequenciesKhz.length - 1; i++) { if (frequenciesKhz[i] > frequenciesKhz[i + 1]) { return i + 1; } } return frequenciesKhz.length; } /** * Get the minimum frequency in each bucket */ @VisibleForTesting public int[] getBucketMinFrequencies(long[] frequenciesKhz) { Preconditions.checkArgument(frequenciesKhz.length == mNumFrequencies); // If there's only one bucket, we bucket everything together so the first bucket is the // min frequency if (mNumBuckets == 1) { return new int[]{(int) frequenciesKhz[0]}; } final int[] bucketMinFrequencies = new int[mNumBuckets]; // Initialize little buckets min frequencies for (int i = 0; i < mLittleNumBuckets; i++) { bucketMinFrequencies[i] = (int) frequenciesKhz[i * mLittleBucketSize]; } // Initialize big buckets min frequencies for (int i = 0; i < mBigNumBuckets; i++) { final int frequencyIndex = mBigFrequenciesStartIndex + i * mBigBucketSize; bucketMinFrequencies[mLittleNumBuckets + i] = (int) frequenciesKhz[frequencyIndex]; } return bucketMinFrequencies; } /** * Put an array of values into buckets. This takes a {@code long[]} and returns {@code * int[]} as everywhere this method is used will have to do the conversion anyway, so we * save time by doing it here instead * * @param values the values to bucket * @return the bucketed usage times */ @VisibleForTesting public int[] getBucketedValues(long[] values) { Preconditions.checkArgument(values.length == mNumFrequencies); final int[] bucketed = new int[mNumBuckets]; // If there's only one bucket, add all frequencies in if (mNumBuckets == 1) { for (int i = 0; i < values.length; i++) { bucketed[0] += values[i]; } return bucketed; } // Initialize the little buckets for (int i = 0; i < mBigFrequenciesStartIndex; i++) { final int bucketIndex = Math.min(i / mLittleBucketSize, mLittleNumBuckets - 1); bucketed[bucketIndex] += values[i]; } // Initialize the big buckets for (int i = mBigFrequenciesStartIndex; i < values.length; i++) { final int bucketIndex = Math.min( mLittleNumBuckets + (i - mBigFrequenciesStartIndex) / mBigBucketSize, mNumBuckets - 1); bucketed[bucketIndex] += values[i]; } return bucketed; } } /** * CPU usage of a process */ Loading
core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java +130 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.os; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; Loading Loading @@ -139,4 +140,133 @@ public class KernelCpuThreadReaderTest { assertEquals(threadCount, THREAD_IDS.length); } @Test public void testBucketSetup_simple() { long[] frequencies = {1, 2, 3, 4, 1, 2, 3, 4}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 4); assertArrayEquals( new int[]{1, 3, 1, 3}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{2, 2, 2, 2}, frequencyBucketCreator.getBucketedValues(new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_noBig() { long[] frequencies = {1, 2, 3, 4, 5, 6, 7, 8}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 4); assertArrayEquals( new int[]{1, 3, 5, 7}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{2, 2, 2, 2}, frequencyBucketCreator.getBucketedValues(new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_moreLittle() { long[] frequencies = {1, 2, 3, 4, 5, 1, 2, 3}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 4); assertArrayEquals( new int[]{1, 3, 1, 2}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{2, 3, 1, 2}, frequencyBucketCreator.getBucketedValues(new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_moreBig() { long[] frequencies = {1, 2, 3, 1, 2, 3, 4, 5}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 4); assertArrayEquals( new int[]{1, 2, 1, 3}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{1, 2, 2, 3}, frequencyBucketCreator.getBucketedValues(new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_equalBuckets() { long[] frequencies = {1, 2, 3, 4, 1, 2, 3, 4}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 8); assertArrayEquals( new int[]{1, 2, 3, 4, 1, 2, 3, 4}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{1, 1, 1, 1, 1, 1, 1, 1}, frequencyBucketCreator.getBucketedValues(new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_moreBigBucketsThanFrequencies() { long[] frequencies = {1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 8); assertArrayEquals( new int[]{1, 3, 5, 7, 1, 2, 3}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{2, 2, 2, 3, 1, 1, 1}, frequencyBucketCreator.getBucketedValues( new long[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testBucketSetup_oneBucket() { long[] frequencies = {1, 2, 3, 4, 2, 3, 4, 5}; KernelCpuThreadReader.FrequencyBucketCreator frequencyBucketCreator = new KernelCpuThreadReader.FrequencyBucketCreator( frequencies, 1); assertArrayEquals( new int[]{1}, frequencyBucketCreator.getBucketMinFrequencies(frequencies)); assertArrayEquals( new int[]{8}, frequencyBucketCreator.getBucketedValues( new long[]{1, 1, 1, 1, 1, 1, 1, 1})); } @Test public void testGetBigFrequenciesStartIndex_simple() { assertEquals( 3, KernelCpuThreadReader.FrequencyBucketCreator.getBigFrequenciesStartIndex( new long[]{1, 2, 3, 1, 2, 3})); } @Test public void testGetBigFrequenciesStartIndex_moreLittle() { assertEquals( 4, KernelCpuThreadReader.FrequencyBucketCreator.getBigFrequenciesStartIndex( new long[]{1, 2, 3, 4, 1, 2})); } @Test public void testGetBigFrequenciesStartIndex_moreBig() { assertEquals( 2, KernelCpuThreadReader.FrequencyBucketCreator.getBigFrequenciesStartIndex( new long[]{1, 2, 1, 2, 3, 4})); } @Test public void testGetBigFrequenciesStartIndex_noBig() { assertEquals( 4, KernelCpuThreadReader.FrequencyBucketCreator.getBigFrequenciesStartIndex( new long[]{1, 2, 3, 4})); } }