diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp
index b55f47826f4dd780af74eeb601a39587eb43a0f3..9d045d4d9008014db93ef24196cfedc33566745a 100644
--- a/src/hotspot/share/gc/g1/g1Allocator.cpp
+++ b/src/hotspot/share/gc/g1/g1Allocator.cpp
@@ -295,6 +295,8 @@ G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) :
     for (uint node_index = 0; node_index < length; node_index++) {
       _alloc_buffers[state][node_index] = new PLAB(_g1h->desired_plab_sz(state));
     }
+    _num_plab_fills[state] = 0;
+    _num_direct_allocations[state] = 0;
   }
 }
 
@@ -327,6 +329,8 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest,
     PLAB* alloc_buf = alloc_buffer(dest, node_index);
     alloc_buf->retire();
 
+    _num_plab_fills[dest.type()]++;
+
     size_t actual_plab_size = 0;
     HeapWord* buf = _allocator->par_allocate_during_gc(dest,
                                                        required_in_plab,
@@ -335,7 +339,7 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest,
                                                        node_index);
 
     assert(buf == NULL || ((actual_plab_size >= required_in_plab) && (actual_plab_size <= plab_word_size)),
-           "Requested at minimum " SIZE_FORMAT ", desired " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT,
+           "Requested at minimum %zu, desired %zu words, but got %zu at " PTR_FORMAT,
            required_in_plab, plab_word_size, actual_plab_size, p2i(buf));
 
     if (buf != NULL) {
@@ -343,7 +347,7 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest,
 
       HeapWord* const obj = alloc_buf->allocate(word_sz);
       assert(obj != NULL, "PLAB should have been big enough, tried to allocate "
-                          SIZE_FORMAT " requiring " SIZE_FORMAT " PLAB size " SIZE_FORMAT,
+                          "%zu requiring %zu PLAB size %zu",
                           word_sz, required_in_plab, plab_word_size);
       return obj;
     }
@@ -354,6 +358,7 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest,
   HeapWord* result = _allocator->par_allocate_during_gc(dest, word_sz, node_index);
   if (result != NULL) {
     _direct_allocated[dest.type()] += word_sz;
+    _num_direct_allocations[dest.type()]++;
   }
   return result;
 }
@@ -371,8 +376,9 @@ void G1PLABAllocator::flush_and_retire_stats() {
         buf->flush_and_retire_stats(stats);
       }
     }
+    stats->add_num_plab_filled(_num_plab_fills[state]);
     stats->add_direct_allocated(_direct_allocated[state]);
-    _direct_allocated[state] = 0;
+    stats->add_num_direct_allocated(_num_direct_allocations[state]);
   }
 }
 
diff --git a/src/hotspot/share/gc/g1/g1Allocator.hpp b/src/hotspot/share/gc/g1/g1Allocator.hpp
index c9bf3015dfc446cc28f88445ac39cc7532977b54..16feef2e6b1bef2d3ec30d2aceafd98432a5f3da 100644
--- a/src/hotspot/share/gc/g1/g1Allocator.hpp
+++ b/src/hotspot/share/gc/g1/g1Allocator.hpp
@@ -161,6 +161,10 @@ private:
   // Number of words allocated directly (not counting PLAB allocation).
   size_t _direct_allocated[G1HeapRegionAttr::Num];
 
+  // Number of PLAB refills experienced so far.
+  size_t _num_plab_fills[G1HeapRegionAttr::Num];
+  size_t _num_direct_allocations[G1HeapRegionAttr::Num];
+
   void flush_and_retire_stats();
   inline PLAB* alloc_buffer(G1HeapRegionAttr dest, uint node_index) const;
   inline PLAB* alloc_buffer(region_type_t dest, uint node_index) const;
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
index eb3586231bda6d10aab6de39b1aa63f0cc13ed91..8acbaae9bb57d7143c6c47666a0e2f6000e285de 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
@@ -2545,7 +2545,8 @@ G1HeapSummary G1CollectedHeap::create_g1_heap_summary() {
 G1EvacSummary G1CollectedHeap::create_g1_evac_summary(G1EvacStats* stats) {
   return G1EvacSummary(stats->allocated(), stats->wasted(), stats->undo_wasted(),
                        stats->unused(), stats->used(), stats->region_end_waste(),
-                       stats->regions_filled(), stats->direct_allocated(),
+                       stats->regions_filled(), stats->num_plab_filled(),
+                       stats->direct_allocated(), stats->num_direct_allocated(),
                        stats->failure_used(), stats->failure_waste());
 }
 
diff --git a/src/hotspot/share/gc/g1/g1EvacStats.cpp b/src/hotspot/share/gc/g1/g1EvacStats.cpp
index f8acabf6be658f217abd04a87d73262ddd4ae5d9..62d5cc3b257f67d2a58d71760cbf447eab4b9489 100644
--- a/src/hotspot/share/gc/g1/g1EvacStats.cpp
+++ b/src/hotspot/share/gc/g1/g1EvacStats.cpp
@@ -33,15 +33,19 @@
 void G1EvacStats::log_plab_allocation() {
   PLABStats::log_plab_allocation();
   log_debug(gc, plab)("%s other allocation: "
-                      "region end waste: " SIZE_FORMAT "B, "
+                      "region end waste: %zuB, "
                       "regions filled: %u, "
-                      "direct allocated: " SIZE_FORMAT "B, "
-                      "failure used: " SIZE_FORMAT "B, "
-                      "failure wasted: " SIZE_FORMAT "B",
+                      "num plab filled: %zu, "
+                      "direct allocated: %zuB, "
+                      "num direct allocated: %zu, "
+                      "failure used: %zuB, "
+                      "failure wasted: %zuB",
                       _description,
                       _region_end_waste * HeapWordSize,
                       _regions_filled,
+                      _num_plab_filled,
                       _direct_allocated * HeapWordSize,
+                      _num_direct_allocated,
                       _failure_used * HeapWordSize,
                       _failure_waste * HeapWordSize);
 }
@@ -94,7 +98,9 @@ G1EvacStats::G1EvacStats(const char* description, size_t default_per_thread_plab
   PLABStats(description, default_per_thread_plab_size, default_per_thread_plab_size * ParallelGCThreads, wt),
   _region_end_waste(0),
   _regions_filled(0),
+  _num_plab_filled(0),
   _direct_allocated(0),
+  _num_direct_allocated(0),
   _failure_used(0),
   _failure_waste(0) {
 }
diff --git a/src/hotspot/share/gc/g1/g1EvacStats.hpp b/src/hotspot/share/gc/g1/g1EvacStats.hpp
index 0bbd1d9661f91af0e3af5b2a74e2994adcc50dbe..c3ecf98efabfacd02921d813d3c159847169b9a3 100644
--- a/src/hotspot/share/gc/g1/g1EvacStats.hpp
+++ b/src/hotspot/share/gc/g1/g1EvacStats.hpp
@@ -32,7 +32,9 @@ class G1EvacStats : public PLABStats {
  private:
   size_t _region_end_waste; // Number of words wasted due to skipping to the next region.
   uint   _regions_filled;   // Number of regions filled completely.
+  size_t _num_plab_filled; // Number of PLABs filled and retired.
   size_t _direct_allocated; // Number of words allocated directly into the regions.
+  size_t _num_direct_allocated; // Number of direct allocation attempts.
 
   // Number of words in live objects remaining in regions that ultimately suffered an
   // evacuation failure. This is used in the regions when the regions are made old regions.
@@ -46,7 +48,9 @@ class G1EvacStats : public PLABStats {
     PLABStats::reset();
     _region_end_waste = 0;
     _regions_filled = 0;
+    _num_plab_filled = 0;
     _direct_allocated = 0;
+    _num_direct_allocated = 0;
     _failure_used = 0;
     _failure_waste = 0;
   }
@@ -61,15 +65,19 @@ class G1EvacStats : public PLABStats {
   ~G1EvacStats();
 
   uint regions_filled() const { return _regions_filled; }
+  size_t num_plab_filled() const { return _num_plab_filled; }
   size_t region_end_waste() const { return _region_end_waste; }
   size_t direct_allocated() const { return _direct_allocated; }
+  size_t num_direct_allocated() const { return _num_direct_allocated; }
 
   // Amount of space in heapwords used in the failing regions when an evacuation failure happens.
   size_t failure_used() const { return _failure_used; }
   // Amount of space in heapwords wasted (unused) in the failing regions when an evacuation failure happens.
   size_t failure_waste() const { return _failure_waste; }
 
+  inline void add_num_plab_filled(size_t value);
   inline void add_direct_allocated(size_t value);
+  inline void add_num_direct_allocated(size_t value);
   inline void add_region_end_waste(size_t value);
   inline void add_failure_used_and_waste(size_t used, size_t waste);
 };
diff --git a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp
index 9ebc1dd57a88556cc7b77104f3290ab4dd3d085d..4b4c6e104b7e31f9bfe4812081e3dbfa7f31619d 100644
--- a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp
@@ -33,6 +33,14 @@ inline void G1EvacStats::add_direct_allocated(size_t value) {
   Atomic::add(&_direct_allocated, value);
 }
 
+inline void G1EvacStats::add_num_plab_filled(size_t value) {
+  Atomic::add(&_num_plab_filled, value);
+}
+
+inline void G1EvacStats::add_num_direct_allocated(size_t value) {
+  Atomic::add(&_num_direct_allocated, value);
+}
+
 inline void G1EvacStats::add_region_end_waste(size_t value) {
   Atomic::add(&_region_end_waste, value);
   Atomic::inc(&_regions_filled);
diff --git a/src/hotspot/share/gc/shared/gcHeapSummary.hpp b/src/hotspot/share/gc/shared/gcHeapSummary.hpp
index c1a10fd2b698b05c8b791997fb740b09f05b27a2..c0ed793fb67b0a78d4e37b459f3064a522536682 100644
--- a/src/hotspot/share/gc/shared/gcHeapSummary.hpp
+++ b/src/hotspot/share/gc/shared/gcHeapSummary.hpp
@@ -177,7 +177,9 @@ private:
 
   size_t _region_end_waste; // Number of words wasted due to skipping to the next region.
   uint   _regions_filled;   // Number of regions filled completely.
+  size_t _num_plab_filled;  // Number of PLABs refilled/retired.
   size_t _direct_allocated; // Number of words allocated directly into the regions.
+  size_t _num_direct_allocated; // Number of direct allocations.
 
   // Number of words in live objects remaining in regions that ultimately suffered an
   // evacuation failure. This is used in the regions when the regions are made old regions.
@@ -187,12 +189,23 @@ private:
   // end of regions.
   size_t _failure_waste;
 public:
-  G1EvacSummary(size_t allocated, size_t wasted, size_t undo_wasted, size_t unused,
-    size_t used, size_t region_end_waste, uint regions_filled, size_t direct_allocated,
-    size_t failure_used, size_t failure_waste) :
+  G1EvacSummary(size_t allocated,
+                size_t wasted,
+                size_t undo_wasted,
+                size_t unused,
+                size_t used,
+                size_t region_end_waste,
+                uint regions_filled,
+                size_t num_plab_filled,
+                size_t direct_allocated,
+                size_t num_direct_allocated,
+                size_t failure_used,
+                size_t failure_waste) :
     _allocated(allocated), _wasted(wasted), _undo_wasted(undo_wasted), _unused(unused),
-    _used(used),  _region_end_waste(region_end_waste), _regions_filled(regions_filled),
-    _direct_allocated(direct_allocated), _failure_used(failure_used), _failure_waste(failure_waste)
+    _used(used),  _region_end_waste(region_end_waste),
+    _regions_filled(regions_filled), _num_plab_filled(num_plab_filled),
+    _direct_allocated(direct_allocated),_num_direct_allocated(num_direct_allocated),
+    _failure_used(failure_used), _failure_waste(failure_waste)
   { }
 
   size_t allocated() const { return _allocated; }
@@ -202,7 +215,9 @@ public:
   size_t used() const { return _used; }
   size_t region_end_waste() const { return _region_end_waste; }
   uint regions_filled() const { return _regions_filled; }
+  size_t num_plab_filled() const { return _num_plab_filled; }
   size_t direct_allocated() const { return _direct_allocated; }
+  size_t num_direct_allocated() const { return _num_direct_allocated; }
   size_t failure_used() const { return _failure_used; }
   size_t failure_waste() const { return _failure_waste; }
 };
diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml
index 26e0e2b36c38ee340d042b15cc3ba199d5658c92..2b3cc8812b56807b8c2ca4efef8a8a5e101353b3 100644
--- a/src/hotspot/share/jfr/metadata/metadata.xml
+++ b/src/hotspot/share/jfr/metadata/metadata.xml
@@ -350,7 +350,9 @@
     <Field type="ulong" contentType="bytes" name="undoWaste" label="Undo Wasted" description="Total memory wasted due to allocation undo within PLABs" />
     <Field type="ulong" contentType="bytes" name="regionEndWaste" label="Region End Wasted" description="Total memory wasted at the end of regions due to refill" />
     <Field type="uint" name="regionsRefilled" label="Region Refills" description="Number of regions refilled" />
+    <Field type="ulong" name="numPlabsFilled" label="PLAB Fills" description="Number of PLABs filled" />
     <Field type="ulong" contentType="bytes" name="directAllocated" label="Allocated (direct)" description="Total memory allocated using direct allocation outside of PLABs" />
+    <Field type="ulong" name="numDirectAllocated" label="Direct allocations" description="Number of direct allocations" />
     <Field type="ulong" contentType="bytes" name="failureUsed" label="Used (failure)" description="Total memory occupied by objects in regions where evacuation failed" />
     <Field type="ulong" contentType="bytes" name="failureWaste" label="Wasted (failure)" description="Total memory left unused in regions where evacuation failed" />
   </Type>
diff --git a/test/hotspot/jtreg/gc/g1/plab/lib/LogParser.java b/test/hotspot/jtreg/gc/g1/plab/lib/LogParser.java
index d8096d1aab8780cca4555d1b43c4872761550373..5a71a60f59dd398d141d6236f4a0098194bf17a2 100644
--- a/test/hotspot/jtreg/gc/g1/plab/lib/LogParser.java
+++ b/test/hotspot/jtreg/gc/g1/plab/lib/LogParser.java
@@ -37,12 +37,12 @@ import java.util.stream.Collectors;
  *
  * Typical GC log with PLAB statistics (options - -Xlog:gc=debug,gc+plab=debug) looks like:
  *
- * [0.330s][debug][gc,plab  ] GC(0) Young PLAB allocation: allocated: 1825632B, wasted: 29424B, unused: 2320B, used: 1793888B, undo waste: 0B,
- * [0.330s][debug][gc,plab  ] GC(0) Young other allocation: region end waste: 0B, regions filled: 2, direct allocated: 271520B, failure used: 0B, failure wasted: 0B
- * [0.330s][debug][gc,plab  ] GC(0) Young sizing: calculated: 358776B, actual: 358776B
- * [0.330s][debug][gc,plab  ] GC(0) Old PLAB allocation: allocated: 427248B, wasted: 592B, unused: 368584B, used: 58072B, undo waste: 0B,
- * [0.330s][debug][gc,plab  ] GC(0) Old other allocation: region end waste: 0B, regions filled: 1, direct allocated: 41704B, failure used: 0B, failure wasted: 0B
- * [0.330s][debug][gc,plab  ] GC(0) Old sizing: calculated: 11608B, actual: 11608B
+ * [0.192s][debug][gc,plab     ] GC(0) Young PLAB allocation: allocated: 2867184B, wasted: 656B, unused: 252896B, used: 2613632B, undo waste: 0B,
+ * [0.192s][debug][gc,plab     ] GC(0) Young other allocation: region end waste: 0B, regions filled: 3, num plab filled: 30, direct allocated: 16400B, num direct allocated: 1, failure used: 0B, failure wasted: 0B
+ * [0.192s][debug][gc,plab     ] GC(0) Young sizing: calculated: 522720B, actual: 522720B
+ * [0.192s][debug][gc,plab     ] GC(0) Old PLAB allocation: allocated: 0B, wasted: 0B, unused: 0B, used: 0B, undo waste: 0B,
+ * [0.192s][debug][gc,plab     ] GC(0) Old other allocation: region end waste: 0B, regions filled: 0, num plab filled: 0, direct allocated: 0B, num direct allocated: 0, failure used: 0B, failure wasted: 0B
+ * [0.192s][debug][gc,plab     ] GC(0) Old sizing: calculated: 0B, actual: 2064B
  */
 final public class LogParser {
 
@@ -62,7 +62,8 @@ final public class LogParser {
     // GC ID
     private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)");
     // Pattern for extraction pair <name>: <numeric value>
-    private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w* \\w+:\\s+\\d+");
+    // This is a non-zero set of words separated by spaces followed by ":" and a value.
+    private static final Pattern PAIRS_PATTERN = Pattern.compile("(?:\\w+ )*\\w+:\\s+\\d+");
 
     /**
      * Construct LogParser object, parse log file with PLAB statistics and store it into report.
@@ -119,7 +120,7 @@ final public class LogParser {
                         do {
                             String pair = matcher.group();
                             String[] nameValue = pair.replaceAll(": ", ":").split(":");
-                            plabInfo.put(nameValue[0].trim(), Long.parseLong(nameValue[1]));
+                            plabInfo.put(nameValue[0], Long.parseLong(nameValue[1]));
                         } while (matcher.find());
                     }
                 }
@@ -194,7 +195,7 @@ final public class LogParser {
                         getEntries().entryStream()
                         .filter(gcLogItem -> extractId == gcIds.contains(gcLogItem.getKey()))
                         .collect(Collectors.toMap(gcLogItem -> gcLogItem.getKey(),
-                                        gcLogItem -> gcLogItem.getValue().get(type).filter(fieldNames)
+                                                  gcLogItem -> gcLogItem.getValue().get(type).filter(fieldNames)
                                 )
                         )
                  );