8149662: Refactor hotspot/test/gc/g1/plab/lib/LogParser.java
authormchernov
Wed, 23 Mar 2016 15:48:25 +0300
changeset 37181 0d5e8ae18924
parent 37175 ac6850d71f72
child 37182 18277fd690f4
8149662: Refactor hotspot/test/gc/g1/plab/lib/LogParser.java Reviewed-by: tschatzl, dfazunen
hotspot/test/gc/g1/plab/TestPLABPromotion.java
hotspot/test/gc/g1/plab/TestPLABResize.java
hotspot/test/gc/g1/plab/lib/LogParser.java
hotspot/test/gc/g1/plab/lib/PlabGCStatistics.java
hotspot/test/gc/g1/plab/lib/PlabInfo.java
hotspot/test/gc/g1/plab/lib/PlabReport.java
--- a/hotspot/test/gc/g1/plab/TestPLABPromotion.java	Wed Mar 23 10:31:46 2016 +0100
+++ b/hotspot/test/gc/g1/plab/TestPLABPromotion.java	Wed Mar 23 15:48:25 2016 +0300
@@ -41,17 +41,16 @@
 package gc.g1.plab;
 
 import java.util.List;
-import java.util.Map;
 import java.util.Arrays;
 import java.io.PrintStream;
 
 import gc.g1.plab.lib.AppPLABPromotion;
 import gc.g1.plab.lib.LogParser;
 import gc.g1.plab.lib.PLABUtils;
+import gc.g1.plab.lib.PlabInfo;
 
 import jdk.test.lib.OutputAnalyzer;
 import jdk.test.lib.ProcessTools;
-import jdk.test.lib.Platform;
 
 /**
  * Test checks PLAB promotion of different size objects.
@@ -63,6 +62,12 @@
     // GC ID with old PLAB statistics
     private final static long GC_ID_OLD_STATS = 2l;
 
+    private final static String PLAB_USED_FIELD_NAME = "used";
+    private final static String PLAB_DIRECT_ALLOCATED_FIELD_NAME = "direct allocated";
+    private final static List<String> FIELDS_TO_EXTRACT = Arrays.asList(PLAB_USED_FIELD_NAME, PLAB_DIRECT_ALLOCATED_FIELD_NAME);
+
+    private static String output;
+
     // Allowable difference for memory consumption (percentage)
     private final static long MEM_DIFFERENCE_PCT = 5;
 
@@ -120,11 +125,12 @@
                 System.out.println(out.getOutput());
                 throw new RuntimeException("Expect exit code 0.");
             }
-            checkResults(out.getOutput(), testCase);
+            output = out.getOutput();
+            checkResults(testCase);
         }
     }
 
-    private static void checkResults(String output, TestCase testCase) {
+    private static void checkResults(TestCase testCase) {
         long plabAllocatedSurvivor;
         long directAllocatedSurvivor;
         long plabAllocatedOld;
@@ -132,65 +138,89 @@
         long memAllocated = testCase.getMemToFill();
         LogParser logParser = new LogParser(output);
 
-        Map<String, Long> survivorStats = getPlabStats(logParser, LogParser.ReportType.SURVIVOR_STATS, GC_ID_SURVIVOR_STATS);
-        Map<String, Long> oldStats = getPlabStats(logParser, LogParser.ReportType.OLD_STATS, GC_ID_OLD_STATS);
+        PlabInfo survivorPlabInfo = logParser.getSpecifiedStats(GC_ID_SURVIVOR_STATS, LogParser.ReportType.SURVIVOR_STATS, FIELDS_TO_EXTRACT);
+        PlabInfo oldPlabInfo = logParser.getSpecifiedStats(GC_ID_OLD_STATS, LogParser.ReportType.OLD_STATS, FIELDS_TO_EXTRACT);
 
-        plabAllocatedSurvivor = survivorStats.get("used");
-        directAllocatedSurvivor = survivorStats.get("direct allocated");
-        plabAllocatedOld = oldStats.get("used");
-        directAllocatedOld = oldStats.get("direct allocated");
+        checkFields(survivorPlabInfo);
+        checkFields(oldPlabInfo);
+
+        plabAllocatedSurvivor = survivorPlabInfo.get(PLAB_USED_FIELD_NAME);
+        directAllocatedSurvivor = survivorPlabInfo.get(PLAB_DIRECT_ALLOCATED_FIELD_NAME);
+        plabAllocatedOld = oldPlabInfo.get(PLAB_USED_FIELD_NAME);
+        directAllocatedOld = oldPlabInfo.get(PLAB_DIRECT_ALLOCATED_FIELD_NAME);
 
         System.out.printf("Survivor PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated);
         System.out.printf("Old      PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedOld, directAllocatedOld, memAllocated);
 
         // Unreachable objects case
         if (testCase.isDeadObjectCase()) {
-            // No dead objects should be promoted
-            if (!(checkRatio(plabAllocatedSurvivor, memAllocated) && checkRatio(directAllocatedSurvivor, memAllocated))) {
-                System.out.println(output);
-                throw new RuntimeException("Unreachable objects should not be allocated using PLAB or direct allocated to Survivor");
-            }
-            if (!(checkRatio(plabAllocatedOld, memAllocated) && checkRatio(directAllocatedOld, memAllocated))) {
-                System.out.println(output);
-                throw new RuntimeException("Unreachable objects should not be allocated using PLAB or direct allocated to Old");
-            }
+            checkDeadObjectsPromotion(plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated);
+            checkDeadObjectsPromotion(plabAllocatedOld, directAllocatedOld, memAllocated);
+
         } else {
             // Live objects case
             if (testCase.isPromotedByPLAB()) {
-                // All live small objects should be promoted using PLAB
-                if (!checkDifferenceRatio(plabAllocatedSurvivor, memAllocated)) {
-                    System.out.println(output);
-                    throw new RuntimeException("Expect that Survivor PLAB allocation are similar to all mem consumed");
-                }
-                if (!checkDifferenceRatio(plabAllocatedOld, memAllocated)) {
-                    System.out.println(output);
-                    throw new RuntimeException("Expect that Old PLAB allocation are similar to all mem consumed");
-                }
+                checkLiveObjectsPromotion(plabAllocatedSurvivor, memAllocated, "Expect that Survivor PLAB allocation are similar to all mem consumed");
+                checkLiveObjectsPromotion(plabAllocatedOld, memAllocated, "Expect that Old PLAB allocation are similar to all mem consumed");
             } else {
                 // All big objects should be directly allocated
-                if (!checkDifferenceRatio(directAllocatedSurvivor, memAllocated)) {
-                    System.out.println(output);
-                    throw new RuntimeException("Test fails. Expect that Survivor direct allocation are similar to all mem consumed");
-                }
-                if (!checkDifferenceRatio(directAllocatedOld, memAllocated)) {
-                    System.out.println(output);
-                    throw new RuntimeException("Test fails. Expect that Old direct allocation are similar to all mem consumed");
-                }
+                checkLiveObjectsPromotion(directAllocatedSurvivor, memAllocated, "Expect that Survivor direct allocation are similar to all mem consumed");
+                checkLiveObjectsPromotion(directAllocatedOld, memAllocated, "Expect that Old direct allocation are similar to all mem consumed");
             }
 
-            // All promoted objects size should be similar to all consumed memory
-            if (!checkDifferenceRatio(plabAllocatedSurvivor + directAllocatedSurvivor, memAllocated)) {
-                System.out.println(output);
-                throw new RuntimeException("Test fails. Expect that Survivor gen total allocation are similar to all mem consumed");
-            }
-            if (!checkDifferenceRatio(plabAllocatedOld + directAllocatedOld, memAllocated)) {
-                System.out.println(output);
-                throw new RuntimeException("Test fails. Expect that Old gen total allocation are similar to all mem consumed");
-            }
+            checkTotalPromotion(plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated, "Expect that Survivor gen total allocation are similar to all mem consumed");
+            checkTotalPromotion(plabAllocatedOld, directAllocatedOld, memAllocated, "Expect that Old gen total allocation are similar to all mem consumed");
         }
         System.out.println("Test passed!");
     }
 
+    private static void checkTotalPromotion(long plabAllocatedSurvivor, long directAllocatedSurvivor, long memAllocated, String exceptionMessage) {
+        // All promoted objects size should be similar to all consumed memory
+        if (!checkDifferenceRatio(plabAllocatedSurvivor + directAllocatedSurvivor, memAllocated)) {
+            System.out.println(output);
+            throw new RuntimeException(exceptionMessage);
+        }
+    }
+
+    /**
+     * Checks that live objects were promoted as expected.
+     * @param plabAllocated
+     * @param totalMemAllocated
+     * @param exceptionMessage
+     */
+    private static void checkLiveObjectsPromotion(long plabAllocated, long totalMemAllocated, String exceptionMessage) {
+        // All live small objects should be promoted using PLAB
+        if (!checkDifferenceRatio(plabAllocated, totalMemAllocated)) {
+            System.out.println(output);
+            throw new RuntimeException(exceptionMessage);
+        }
+    }
+
+    /**
+     * Checks that dead objects are not promoted.
+     * @param plabPromoted promoted by PLAB
+     * @param directlyPromoted
+     * @param memoryAllocated total memory allocated
+     */
+    private static void checkDeadObjectsPromotion(long plabPromoted, long directlyPromoted, long memoryAllocated) {
+        // No dead objects should be promoted
+        if (!(checkRatio(plabPromoted, memoryAllocated) && checkRatio(directlyPromoted, memoryAllocated))) {
+            System.out.println(output);
+            throw new RuntimeException("Unreachable objects should not be allocated using PLAB or directly allocated to Survivor/Old");
+        }
+    }
+
+    /**
+     * Checks that PLAB statistics contains expected fields.
+     * @param info
+     */
+    private static void checkFields(PlabInfo info) {
+        if (!info.checkFields(FIELDS_TO_EXTRACT)) {
+            System.out.println(output);
+            throw new RuntimeException("PLAB log does not contain expected fields");
+        }
+    }
+
     /**
      * Returns true if checkedValue is less than MEM_DIFFERENCE_PCT percent of controlValue.
      *
@@ -215,14 +245,6 @@
         return (Math.abs(checkedValue - controlValue) / controlValue) * 100L < MEM_DIFFERENCE_PCT;
     }
 
-    private static Map<String, Long> getPlabStats(LogParser logParser, LogParser.ReportType type, long gc_id) {
-
-        Map<String, Long> survivorStats = logParser.getEntries()
-                .get(gc_id)
-                .get(type);
-        return survivorStats;
-    }
-
     /**
      * Description of one test case.
      */
--- a/hotspot/test/gc/g1/plab/TestPLABResize.java	Wed Mar 23 10:31:46 2016 +0100
+++ b/hotspot/test/gc/g1/plab/TestPLABResize.java	Wed Mar 23 15:48:25 2016 +0300
@@ -41,16 +41,15 @@
  */
 package gc.g1.plab;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
 import java.util.stream.Collectors;
 import java.io.PrintStream;
 
 import gc.g1.plab.lib.LogParser;
 import gc.g1.plab.lib.PLABUtils;
 import gc.g1.plab.lib.AppPLABResize;
+import gc.g1.plab.lib.PlabReport;
 
 import jdk.test.lib.OutputAnalyzer;
 import jdk.test.lib.ProcessTools;
@@ -74,6 +73,8 @@
     private static final int ITERATIONS_MEDIUM = 5;
     private static final int ITERATIONS_HIGH = 8;
 
+    private static final String PLAB_SIZE_FIELD_NAME = "actual";
+
     private final static TestCase[] TEST_CASES = {
         new TestCase(WASTE_PCT_SMALL, OBJECT_SIZE_SMALL, GC_NUM_SMALL, ITERATIONS_MEDIUM),
         new TestCase(WASTE_PCT_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_HIGH, ITERATIONS_SMALL),
@@ -109,16 +110,14 @@
      */
     private static void checkResults(String output, TestCase testCase) {
         final LogParser log = new LogParser(output);
-        final Map<Long, Map<LogParser.ReportType, Map<String, Long>>> entries = log.getEntries();
+        final PlabReport report = log.getEntries();
 
-        final ArrayList<Long> plabSizes = entries.entrySet()
-                .stream()
-                .map(item -> {
-                    return item.getValue()
-                            .get(LogParser.ReportType.SURVIVOR_STATS)
-                            .get("actual");
-                })
-                .collect(Collectors.toCollection(ArrayList::new));
+        final List<Long> plabSizes = report.entryStream()
+                .map(item -> item.getValue()
+                        .get(LogParser.ReportType.SURVIVOR_STATS)
+                        .get(PLAB_SIZE_FIELD_NAME)
+                )
+                .collect(Collectors.toList());
 
         // Check that desired plab size was changed during iterations.
         // The test case does 3 rounds of allocations.  The second round of N allocations and GC's
--- a/hotspot/test/gc/g1/plab/lib/LogParser.java	Wed Mar 23 10:31:46 2016 +0100
+++ b/hotspot/test/gc/g1/plab/lib/LogParser.java	Wed Mar 23 15:48:25 2016 +0300
@@ -22,13 +22,15 @@
  */
 package gc.g1.plab.lib;
 
-import java.util.EnumMap;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Scanner;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 /**
  * LogParser class parses VM output to get PLAB and ConsumptionStats values.
@@ -44,9 +46,6 @@
  */
 final public class LogParser {
 
-    // Name for GC ID field in report.
-    public final static String GC_ID = "gc_id";
-
     /**
      * Type of parsed log element.
      */
@@ -58,7 +57,7 @@
     private final String log;
 
     // Contains Map of PLAB statistics for given log.
-    private final Map<Long, Map<ReportType, Map<String, Long>>> report;
+    private final PlabReport report;
 
     // GC ID
     private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)");
@@ -91,56 +90,107 @@
      *
      * @return The log entries for the Survivor and Old stats.
      */
-    public Map<Long, Map<ReportType, Map<String, Long>>> getEntries() {
+    public PlabReport getEntries() {
         return report;
     }
 
-    private Map<Long, Map<ReportType, Map<String, Long>>> parseLines() throws NumberFormatException {
+    private PlabReport parseLines() throws NumberFormatException {
         Scanner lineScanner = new Scanner(log);
-        Map<Long, Map<ReportType, Map<String, Long>>> allocationStatistics = new HashMap<>();
+        PlabReport plabReport = new PlabReport();
         Optional<Long> gc_id;
         while (lineScanner.hasNextLine()) {
             String line = lineScanner.nextLine();
-            gc_id = getGcId(line);
+            gc_id = getGcId(line, GC_ID_PATTERN);
             if (gc_id.isPresent()) {
                 Matcher matcher = PAIRS_PATTERN.matcher(line);
                 if (matcher.find()) {
-                    Map<ReportType, Map<String, Long>> oneReportItem;
-                    ReportType reportType;
-
-                    if (!allocationStatistics.containsKey(gc_id.get())) {
-                        allocationStatistics.put(gc_id.get(), new EnumMap<>(ReportType.class));
+                    if (!plabReport.containsKey(gc_id.get())) {
+                        plabReport.put(gc_id.get(), new PlabGCStatistics());
                     }
+                    ReportType reportType = line.contains("Young") ? ReportType.SURVIVOR_STATS : ReportType.OLD_STATS;
 
-                    if (line.contains("Young")) {
-                        reportType = ReportType.SURVIVOR_STATS;
-                    } else {
-                        reportType = ReportType.OLD_STATS;
-                    }
-
-                    oneReportItem = allocationStatistics.get(gc_id.get());
-                    if (!oneReportItem.containsKey(reportType)) {
-                        oneReportItem.put(reportType, new HashMap<>());
+                    PlabGCStatistics gcStat = plabReport.get(gc_id.get());
+                    if (!gcStat.containsKey(reportType)) {
+                        gcStat.put(reportType, new PlabInfo());
                     }
 
                     // Extract all pairs from log.
-                    Map<String, Long> plabStats = oneReportItem.get(reportType);
+                    PlabInfo plabInfo = gcStat.get(reportType);
                     do {
                         String pair = matcher.group();
                         String[] nameValue = pair.replaceAll(": ", ":").split(":");
-                        plabStats.put(nameValue[0].trim(), Long.parseLong(nameValue[1]));
+                        plabInfo.put(nameValue[0].trim(), Long.parseLong(nameValue[1]));
                     } while (matcher.find());
                 }
             }
         }
-        return allocationStatistics;
+        return plabReport;
     }
 
-    private Optional<Long> getGcId(String line) {
-        Matcher number = GC_ID_PATTERN.matcher(line);
+    private static Optional<Long> getGcId(String line, Pattern pattern) {
+        Matcher number = pattern.matcher(line);
         if (number.find()) {
             return Optional.of(Long.parseLong(number.group(1)));
         }
         return Optional.empty();
     }
+
+    /**
+     * Extracts GC ID from log.
+     *
+     * @param line - one line of log.
+     * @return GC ID
+     */
+    public static Long getGcIdFromLine(String line, Pattern pattern) {
+        Optional<Long> gcId = getGcId(line, pattern);
+        if (!gcId.isPresent()) {
+            System.out.println(line);
+            throw new RuntimeException("Cannot find GC ID in log.");
+        }
+        return gcId.get();
+    }
+
+    /**
+     * Returns Map<Long,PlabStatistics> which contains specified statistics for specified gc ids.
+     * @param specifiedGcId gc id to get
+     * @param type PLAB type
+     * @param fieldsName name of fields in PlabStatistics
+     * @return
+     **/
+    public Map<Long, PlabInfo> getSpecifiedStats(List<Long> specifiedGcId, LogParser.ReportType type, List<String> fieldsName) {
+        return getSpecifiedStats(specifiedGcId, type, fieldsName, true);
+    }
+
+    /**
+     * Returns PlabStatistics for specified GC ID.
+     * @param specifiedGcId
+     * @param type type of statistics
+     * @param fieldsName name of fields in PlabStatistics
+     * @return
+     **/
+    public PlabInfo getSpecifiedStats(long specifiedGcId, LogParser.ReportType type, List<String> fieldsName) {
+        return getSpecifiedStats(Arrays.asList(specifiedGcId), type, fieldsName, true).get(specifiedGcId);
+    }
+
+    /**
+     * Returns Map<Long,PlabStatistics> which contains specified statistics. Filters out specified gc ids.
+     * @param specifiedGcIdForExclude
+     * @param type
+     * @param fieldsName
+     * @return
+     **/
+    public Map<Long, PlabInfo> getExcludedSpecifiedStats(List<Long> specifiedGcIdForExclude, LogParser.ReportType type, List<String> fieldsName) {
+        return getSpecifiedStats(specifiedGcIdForExclude, type, fieldsName, false);
+    }
+
+    private Map<Long, PlabInfo> getSpecifiedStats(List<Long> gcIds, LogParser.ReportType type, List<String> fieldNames, boolean extractId) {
+        return new HashMap<>(
+                getEntries().entryStream()
+                .filter(gcLogItem -> extractId == gcIds.contains(gcLogItem.getKey()))
+                .collect(Collectors.toMap(gcLogItem -> gcLogItem.getKey(),
+                                gcLogItem -> gcLogItem.getValue().get(type).filter(fieldNames)
+                        )
+                )
+        );
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/PlabGCStatistics.java	Wed Mar 23 15:48:25 2016 +0300
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package gc.g1.plab.lib;
+
+import java.util.EnumMap;
+import java.util.Map;
+
+import gc.g1.plab.lib.LogParser.ReportType;
+
+/**
+ * Class that represents PLAB statistics for a single GC.
+ * It includes both Survivor and Old PLAB statistics.
+ */
+public class PlabGCStatistics {
+
+    private final Map<ReportType, PlabInfo> plabGCStatistics;
+
+    public PlabGCStatistics() {
+        plabGCStatistics = new EnumMap<>(ReportType.class);
+    }
+
+    /**
+     * Checks if the statistics contains the requested type.
+     * @param reportType
+     * @returns true, if contains, false otherwise
+     */
+    public boolean containsKey(ReportType reportType) {
+        return plabGCStatistics.containsKey(reportType);
+    }
+
+    /**
+     * Put pair of ReportType and PlabInfo to statistics.
+     * @param reportType
+     * @param plabInfo
+     */
+    public void put(ReportType reportType, PlabInfo plabInfo) {
+        plabGCStatistics.put(reportType, plabInfo);
+    }
+
+    /**
+     * Returns PlabInfo of specified type
+     * @param reportType
+     * @return
+     */
+    public PlabInfo get(ReportType reportType) {
+        return plabGCStatistics.get(reportType);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/PlabInfo.java	Wed Mar 23 15:48:25 2016 +0300
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package gc.g1.plab.lib;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class PlabInfo {
+
+    private final Map<String, Long> plabInfo;
+
+    public PlabInfo() {
+        plabInfo = new HashMap<>();
+    }
+
+    private PlabInfo(Map<String, Long> map) {
+        plabInfo = new HashMap<>(map);
+    }
+
+    /**
+     * Add key and value to underlying Map.
+     * @param key   PLAB info field name
+     * @param value PLAB info value for field
+     */
+    public void put(String key, long value) {
+        plabInfo.put(key, value);
+    }
+
+    /**
+     * Get stream of Map.Entry representing underlying Map with PLAB information.
+     */
+    public Stream<Map.Entry<String, Long>> entryStream() {
+        return plabInfo.entrySet().stream();
+    }
+
+    /**
+     * Returns the PlabInfo narrowed for the given fields only
+     * @param fields
+     * @return PlabInfo
+     */
+    public PlabInfo filter(List<String> fields) {
+        return new PlabInfo(entryStream()
+                .filter(field -> fields.contains(field.getKey()))
+                .collect(Collectors.toMap(
+                        item -> item.getKey(),
+                        item -> item.getValue())
+                )
+        );
+    }
+
+    /**
+     * Checks if statistic contains expected fields.
+     * @param fields fields which should be in statistic
+     * @return true if all fields are in statistic, false otherwise
+     */
+    public boolean checkFields(List<String> fields) {
+        for (String key : fields) {
+            if (!plabInfo.containsKey(key)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Return a collection of the values.
+     * @return collection of values
+     */
+    public Collection<Long> values() {
+        return plabInfo.values();
+    }
+
+    /**
+     * Get value for specified field.
+     * @param field
+     * @return long value which is contained in specified field
+     */
+    public long get(String field) {
+        return plabInfo.get(field);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/PlabReport.java	Wed Mar 23 15:48:25 2016 +0300
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package gc.g1.plab.lib;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+
+/**
+ * Class contains representation of GC PLAB log.
+ */
+public class PlabReport {
+
+    private final Map<Long, PlabGCStatistics> report = new HashMap<>();
+
+    public PlabReport() {
+    }
+
+    /**
+     * Checks if underlying Map contains requested GC ID.
+     */
+    public boolean containsKey(Long gcId) {
+        return report.containsKey(gcId);
+    }
+
+    /**
+     * Puts GC ID and PlabGCStatistics to underlying Map.
+     */
+    public void put(Long gcId, PlabGCStatistics plabStat) {
+        report.put(gcId, plabStat);
+    }
+
+    /**
+     * Returns PlabGCStatistics for specified GC ID.
+     */
+    public PlabGCStatistics get(Long gcId) {
+        return report.get(gcId);
+    }
+
+    /**
+     * Returns Stream of Map.Entry of underlying Map.
+     */
+    public Stream<Map.Entry<Long, PlabGCStatistics>> entryStream() {
+        return report.entrySet().stream();
+    }
+}